State Changes from User Interactions


<#68435#>;; <#46454#>Data Analysis and Definitions<#46454#>:<#68435#>
<#71776#>;; A <#68436#><#46455#>letter<#46455#><#68436#> is a symbol in: <#68437#><#46456#>'<#46456#><#46457#>a<#46457#> <#46458#>...<#46458#> <#46459#>'<#46459#><#46460#>z<#46460#><#68437#> plus <#68438#><#46461#>'<#46461#><#46462#>_<#46462#><#68438#><#71776#> 
<#71777#>;; A <#68439#><#46463#>word<#46463#><#68439#> is a (listof letter).<#71777#> 
<#71778#>;; A <#68440#><#46464#>body-part<#46464#><#68440#> is one of the following symbols:<#71778#> 
<#46465#>(define<#46465#> <#46466#>PARTS<#46466#> <#46467#>'<#46467#><#46468#>(head<#46468#> <#46469#>body<#46469#> <#46470#>right-arm<#46470#> <#46471#>left-arm<#46471#> <#46472#>right-leg<#46472#> <#46473#>left-leg))<#46473#> 
<#68441#>;; <#46474#>Constants<#46474#>:<#68441#> 
<#46475#>;; some guessing words: <#46475#> 
<#46476#>(d<#46476#><#46477#>efine<#46477#> <#46478#>WORDS<#46478#> 
  <#46479#>'<#46479#><#46480#>(<#46480#><#46481#>(h<#46481#> <#46482#>e<#46482#> <#46483#>l<#46483#> <#46484#>l<#46484#> <#46485#>o)<#46485#> 
    <#46486#>(w<#46486#> <#46487#>o<#46487#> <#46488#>r<#46488#> <#46489#>l<#46489#> <#46490#>d)<#46490#> 
    <#46491#>(i<#46491#> <#46492#>s)<#46492#> 
    <#46493#>(a)<#46493#> 
    <#46494#>(s<#46494#> <#46495#>t<#46495#> <#46496#>u<#46496#> <#46497#>p<#46497#> <#46498#>i<#46498#> <#46499#>d)<#46499#> 
    <#46500#>(p<#46500#> <#46501#>r<#46501#> <#46502#>o<#46502#> <#46503#>g<#46503#> <#46504#>r<#46504#> <#46505#>a<#46505#> <#46506#>m)<#46506#> 
    <#46507#>...<#46507#> 
    <#46508#>))<#46508#> 
<#46509#>;; the number of words we can choose from <#46509#> 
<#46510#>(define<#46510#> <#46511#>WORDS#<#46511#> <#46512#>(length<#46512#> <#46513#>WORDS))<#46513#> 
<#46517#>Figure: Hangman Basics<#46517#>
Recall the hangman game from #sechangman#46519>. The goal of the game is to test a person's active vocabulary. One player thinks of a word and draws the noose of a gallows; the other player tries to guess the word, one letter at a time. For every wrong guess, the first player adds another part to the drawing (see figure~#fighangman#46520>): first the head, then the body, the arms, and the legs. If, however, the player's guess reveals new knowledge about the chosen word, the first player indicates where the the letter occurs in the word. The game is over when the second player guesses the complete word or when the first player has completed the stick figure. Figure~#fighangmanstate#46521> contains the data definitions for letters, words, and body-parts. In particular, <#68442#><#46522#>PARTS<#46522#><#68442#> not only specifies the body parts that are drawn, but also the order in which they are drawn. The figure also defines an incomplete list of words so that the hangman program can randomly pick a word for us to guess. The random picking of words occurs at the beginning of the game, which suggests a random initialization function, similar to that of the color-guessing program in the preceding section. In contrast to the latter, the hangman program must also remember the number of guesses that a player made, because there is only a limited number of them. After <#68443#><#46523#>'<#46523#><#46524#>left-leg<#46524#><#68443#> is drawn, the game is over. Counting down the number of body parts also implies that as the program checks each guess, it must inform the player not only what the guess revealed but also which body part, if any, was lost. Let us capture this thought in a data definition that specifies the legitimate class of responses:
A <#68444#><#46526#>response<#46526#><#68444#> is either
  1. <#68445#><#46528#>``You<#46528#>\ <#46529#>won''<#46529#><#68445#>
  2. <#68446#><#46530#>(list<#46530#>\ <#46531#>``The<#46531#>\ <#46532#>End''<#46532#>\ <#46533#>word)<#46533#><#68446#>
  3. <#68447#><#46534#>(list<#46534#>\ <#46535#>``Good<#46535#>\ <#46536#>guess!''<#46536#>\ <#46537#>word)<#46537#><#68447#>
  4. <#68448#><#46538#>(list<#46538#>\ <#46539#>``Sorry''<#46539#>\ <#46540#>body-part<#46540#>\ <#46541#>word)<#46541#><#68448#>
Three of the responses are lists so that the program can provide several pieces of information at once. Specifically, the first response says that filling in the guess turns the status word into the chosen word and that the player survived the game. The second response indicates the opposite; the list of available body parts is exhausted and the game is over because the player did not guess all the letters in the word. In the third case, the player's guess was successful and the second item in the list shows how much the player knows about the word. Finally, the fourth response represents a bad guess, in which case the response is a list of three items: a greeting, the lost body part, and a reminder of what the player has found about the word. We can now imagine the role of the two services in the <#46544#>hangman<#46544#> program. The first, called <#68449#><#46545#>hangman<#46545#><#68449#>, picks a new word; the second, called <#68450#><#46546#>hangman-guess<#46546#><#68450#>, consumes a letter and produces one of the four possible responses. Here is a feasible dialog:
<#46551#>;SPMgt;<#46551#> <#46552#>(hangman)<#46552#>
<#46553#>;SPMgt;<#46553#> <#46554#>(hangman-guess<#46554#> <#46555#>'<#46555#><#46556#>a)<#46556#> 
<#46557#>(list<#46557#> <#46558#>``Sorry''<#46558#> <#46559#>'<#46559#><#46560#>head<#46560#> <#46561#>(list<#46561#> <#46562#>'<#46562#><#46563#>_<#46563#> <#46564#>'<#46564#><#46565#>_<#46565#> <#46566#>'<#46566#><#46567#>_<#46567#> <#46568#>'<#46568#><#46569#>_<#46569#> <#46570#>'<#46570#><#46571#>_<#46571#> <#46572#>'<#46572#><#46573#>_<#46573#><#46574#>))<#46574#> 
<#46575#>;SPMgt;<#46575#> <#46576#>(hangman-guess<#46576#> <#46577#>'<#46577#><#46578#>i)<#46578#> 
<#46579#>(list<#46579#> <#46580#>``Good<#46580#> <#46581#>guess!''<#46581#> <#46582#>(list<#46582#> <#46583#>'<#46583#><#46584#>_<#46584#> <#46585#>'<#46585#><#46586#>_<#46586#> <#46587#>'<#46587#><#46588#>_<#46588#> <#46589#>'<#46589#><#46590#>_<#46590#> <#46591#>'<#46591#><#46592#>i<#46592#> <#46593#>'<#46593#><#46594#>_<#46594#><#46595#>))<#46595#> 
<#46596#>;SPMgt;<#46596#> <#46597#>(hangman-guess<#46597#> <#46598#>'<#46598#><#46599#>s)<#46599#> 
<#46600#>(list<#46600#> <#46601#>``Good<#46601#> <#46602#>guess!''<#46602#> <#46603#>(list<#46603#> <#46604#>'<#46604#><#46605#>s<#46605#> <#46606#>'<#46606#><#46607#>_<#46607#> <#46608#>'<#46608#><#46609#>_<#46609#> <#46610#>'<#46610#><#46611#>_<#46611#> <#46612#>'<#46612#><#46613#>i<#46613#> <#46614#>'<#46614#><#46615#>_<#46615#><#46616#>))<#46616#> 
<#46617#>;SPMgt;<#46617#> <#46618#>(hangman-guess<#46618#> <#46619#>'<#46619#><#46620#>i)<#46620#> 
<#46621#>(list<#46621#> <#46622#>``Sorry''<#46622#> <#46623#>'<#46623#><#46624#>body<#46624#> <#46625#>(list<#46625#> <#46626#>'<#46626#><#46627#>s<#46627#> <#46628#>'<#46628#><#46629#>_<#46629#> <#46630#>'<#46630#><#46631#>_<#46631#> <#46632#>'<#46632#><#46633#>_<#46633#> <#46634#>'<#46634#><#46635#>i<#46635#> <#46636#>'<#46636#><#46637#>_<#46637#><#46638#>))<#46638#> 
<#46639#>...<#46639#> 
<#46640#>;SPMgt;<#46640#> <#46641#>(hangman)<#46641#> 
<#46642#>;SPMgt;<#46642#> <#46643#>(hangman-guess<#46643#> <#46644#>'<#46644#><#46645#>a)<#46645#> 
<#46646#>``You<#46646#> <#46647#>won''<#46647#> 
The dialog consists of two rounds of hangman. They show that the results of <#68451#><#46651#>hangman-guess<#46651#><#68451#> depend on the prior use of <#68452#><#46652#>hangman<#46652#><#68452#>. Furthermore, the first round illustrates how <#68453#><#46653#>hangman-guess<#46653#><#68453#> applied to the same guess twice produces two different answers. This again means that <#68454#><#46654#>hangman-guess<#46654#><#68454#> modifies and uses memory, specifically, it counts down the body parts as the player makes useless guesses. In addition, the dialog shows that the player loses a body part whenever a guess doesn't contribute any new knowledge. Consider the second guess: <#68455#><#46655#>'<#46655#><#46656#>i<#46656#><#68455#>. It occurs in the penultimate position of the word and the response of <#68456#><#46657#>hangman-guess<#46657#><#68456#> says so. When the player enters <#68457#><#46658#>'<#46658#><#46659#>i<#46659#><#68457#> again as the fourth guess, <#68458#><#46660#>hangman-guess<#46660#><#68458#> detects no progress because the positions of <#68459#><#46661#>'<#46661#><#46662#>i<#46662#><#68459#> have already been revealed. In the informal description of the game, this aspect had been left open. By putting together an example, we become aware of this ambiguity and can make a decision.
<#71779#>;; <#68460#><#46667#>chosen-word<#46667#> <#46668#>:<#46668#> <#46669#>word<#46669#><#68460#><#71779#>
<#46670#>;; the word that the player is to guess<#46670#> 
<#46671#>(define<#46671#> <#46672#>chosen-word<#46672#> <#46673#>(first<#46673#> <#46674#>WORDS))<#46674#> 
<#71780#>;; <#68461#><#46675#>status-word<#46675#> <#46676#>:<#46676#> <#46677#>word<#46677#><#68461#><#71780#> 
<#46678#>;; represents which letters the player has and hasn't guessed<#46678#> 
<#46679#>(define<#46679#> <#46680#>status-word<#46680#> <#46681#>(first<#46681#> <#46682#>WORDS))<#46682#> 
<#71781#>;; <#68462#><#46683#>body-parts-left<#46683#> <#46684#>:<#46684#> <#46685#>(listof<#46685#> <#46686#>body-part)<#46686#><#68462#><#71781#> 
<#46687#>;; represents the list of body parts that are still ;SPMquot;available;SPMquot;<#46687#> 
<#46688#>(define<#46688#> <#46689#>body-parts-left<#46689#> <#46690#>PARTS)<#46690#> 
<#71782#>;; <#68463#><#46691#>hangman<#46691#> <#46692#>:<#46692#> <#46693#><#46693#><#46694#>-;SPMgt;<#46694#><#46695#><#46695#> <#46696#>void<#46696#><#68463#><#71782#> 
<#71783#>;; effect: initialize <#68464#><#46697#>chosen-word<#46697#><#68464#>, <#68465#><#46698#>status-word<#46698#><#68465#>, and <#68466#><#46699#>body-parts-left<#46699#><#68466#><#71783#> 
<#46700#>(d<#46700#><#46701#>efine<#46701#> <#46702#>(hangman)<#46702#> 
  <#46703#>(b<#46703#><#46704#>egin<#46704#> 
    <#46705#>(set!<#46705#> <#46706#>chosen-word<#46706#> <#46707#>(list-ref<#46707#> <#46708#>WORDS<#46708#> <#46709#>(random<#46709#> <#46710#>(length<#46710#> <#46711#>WORDS))))<#46711#> 
    <#46712#>(set!<#46712#> <#46713#>status-word<#46713#> <#46714#>...)<#46714#> 
    <#46715#>(set!<#46715#> <#46716#>body-parts-left<#46716#> <#46717#>PARTS)))<#46717#> 
<#46721#>Figure: Hangman Basics (Part 2)<#46721#>
Thus far, our reasoning has revealed the need for two services and three state variables:
<#68467#><#46724#>chosen-word<#46724#><#68467#>, which is the word to be guessed;
<#68468#><#46725#>status-word<#46725#><#68468#>, which records how much of the word has been guessed;
and <#68469#><#46726#>body-parts-left<#46726#><#68469#>, which remembers how many, and which, imaginary body parts the player can still lose.
The first two variables always stand for <#68470#><#46728#>word<#46728#><#68470#>s, as their name says. A natural value for the last one is a list of body parts; indeed, the list should always be a suffix of <#68471#><#46729#>PARTS<#46729#><#68471#>. Figure~#fighangmanstate2#46730> contains the definitions of the state variables and their purpose statements. The first two, <#68472#><#46731#>chosen-word<#46731#><#68472#> and <#68473#><#46732#>status-word<#46732#><#68473#>, are set to the first items if WORDS, so that they represent some word. The third one is set to <#68474#><#46733#>PARTS<#46733#><#68474#> because this list represents the entire collection of available body parts. Next we must develop an initializer for the state variables. As in the preceding section, a single initializer suffices. It is the <#68475#><#46734#>hangman<#46734#><#68475#> function, and its purpose is to set up the program's memory. Specifically, it picks a word for <#68476#><#46735#>chosen-word<#46735#><#68476#>, and it sets <#68477#><#46736#>status-word<#46736#><#68477#> and <#68478#><#46737#>body-parts-left<#46737#><#68478#> to values that reflect that the game has just begun. For the last one, this is easy because <#68479#><#46738#>PARTS<#46738#><#68479#> is the appropriate list. The initial value for <#68480#><#46739#>status-word<#46739#><#68480#> requires a short analysis. First, the value must be a word. Second, it must consist of as many letters as <#68481#><#46740#>chosen-word<#46740#><#68481#>. Finally, each of the letters is unknown, because the player hasn't made any guesses yet. Thus, the matching action is a build a word as long as <#68482#><#46741#>chosen-word<#46741#><#68482#> but to use <#68483#><#46742#>'<#46742#><#46743#>_<#46743#><#68483#> as the letters.
<#46746#>Exercise 37.2.1<#46746#> Develop the function <#68484#><#46748#>make-status-word<#46748#><#68484#>, which consumes a word and produces an equally long word consisting of just <#68485#><#46749#>'<#46749#><#46750#>_<#46750#><#68485#>. Use the function to complete the definition of <#68486#><#46751#>hangman<#46751#><#68486#> in figure~#fighangmanstate2#46752>.~ external Solution<#68487#><#68487#> <#46758#>Exercise 37.2.2<#46758#> Use <#68488#><#46760#>build-list<#46760#><#68488#> to create the status word in a single expression. Complete the definition of <#68489#><#46761#>hangman<#46761#><#68489#> in figure~#fighangmanstate2#46762>.~ external Solution<#68490#><#68490#>
Now we are ready to deal with the most difficult part: the design of <#68491#><#46770#>hangman-guess<#46770#><#68491#>, a function that uses and modifies the memory. It consumes a letter and produces an answer, specifically a <#68492#><#46771#>response<#46771#><#68492#>, which depends on how the current value of <#68493#><#46772#>status-word<#46772#><#68493#>, <#68494#><#46773#>chosen-word<#46773#><#68494#>, and <#68495#><#46774#>guess<#46774#><#68495#> compare. At the same time, the function must affect the state variable <#68496#><#46775#>status-word<#46775#><#68496#> if the player's guess added new knowledge. If not, the function must shorten <#68497#><#46776#>body-parts-left<#46776#><#68497#>, the list of available body parts. The matching contract, purpose and effect statements are as follows:
<#71784#>;; <#68498#><#46781#>hangman-guess<#46781#> <#46782#>:<#46782#> <#46783#>letter<#46783#> <#46784#><#46784#><#46785#>-;SPMgt;<#46785#><#46786#><#46786#> <#46787#>response<#46787#><#68498#><#71784#>
<#46788#>;; to determine whether the player has won, lost, or may continue to<#46788#> 
<#46789#>;; play and, if no progress was made, which body part was lost<#46789#> 
<#46790#>;; effect:<#46790#> 
<#71785#>;; (1) if the guess represents progress, update <#68499#><#46791#>status-word<#46791#><#68499#><#71785#> 
<#71786#>;; (2) if not, shorten the <#68500#><#46792#>body-parts-left<#46792#><#68500#> by one <#71786#> 
We have already considered a sample dialog that illustrates the working of <#68501#><#46796#>hangman-guess<#46796#><#68501#>. By dissecting this dialog, we can develop specific examples for <#68502#><#46797#>hangman-guess<#46797#><#68502#>. The sample dialog and the purpose/effect statements imply that the result of <#68503#><#46798#>hangman-guess<#46798#><#68503#> depends on whether or not the guess constitutes progress and, if not, whether or not the guess was the last one. Let's use these distinctions for the development of examples:
  1. If <#68504#><#46800#>status-word<#46800#><#68504#> is <#68505#><#46801#>(list<#46801#>\ <#46802#>'<#46802#><#46803#>b<#46803#>\ <#46804#>'<#46804#><#46805#>_<#46805#>\ <#46806#>'<#46806#><#46807#>_<#46807#>\ <#46808#>'<#46808#><#46809#>_<#46809#><#46810#>)<#46810#><#68505#> and <#68506#><#46811#>chosen-word<#46811#><#68506#> is <#68507#><#46812#>(list<#46812#>\ <#46813#>'<#46813#><#46814#>b<#46814#>\ <#46815#>'<#46815#><#46816#>a<#46816#>\ <#46817#>'<#46817#><#46818#>l<#46818#>\ <#46819#>'<#46819#><#46820#>l)<#46820#><#68507#>, then evaluating
     <#46825#>(hangman-guess<#46825#> <#46826#>'<#46826#><#46827#>l)<#46827#>
    
    produces <#68508#><#46831#>(list<#46831#>\ <#46832#>``Good<#46832#>\ <#46833#>guess!''<#46833#>\ <#46834#>(list<#46834#>\ <#46835#>'<#46835#><#46836#>b<#46836#>\ <#46837#>'<#46837#><#46838#>_<#46838#>\ <#46839#>'<#46839#><#46840#>l<#46840#>\ <#46841#>'<#46841#><#46842#>l))<#46842#><#68508#> and <#68509#><#46843#>status-word<#46843#><#68509#> becomes <#68510#><#46844#>(list<#46844#>\ <#46845#>'<#46845#><#46846#>b<#46846#>\ <#46847#>'<#46847#><#46848#>_<#46848#>\ <#46849#>'<#46849#><#46850#>l<#46850#>\ <#46851#>'<#46851#><#46852#>l)<#46852#><#68510#>.
  2. If <#68511#><#46853#>status-word<#46853#><#68511#> is <#68512#><#46854#>(list<#46854#>\ <#46855#>'<#46855#><#46856#>b<#46856#>\ <#46857#>'<#46857#><#46858#>_<#46858#>\ <#46859#>'<#46859#><#46860#>l<#46860#>\ <#46861#>'<#46861#><#46862#>l)<#46862#><#68512#> and <#68513#><#46863#>chosen-word<#46863#><#68513#> is <#68514#><#46864#>(list<#46864#>\ <#46865#>'<#46865#><#46866#>b<#46866#>\ <#46867#>'<#46867#><#46868#>a<#46868#>\ <#46869#>'<#46869#><#46870#>l<#46870#>\ <#46871#>'<#46871#><#46872#>l)<#46872#><#68514#>, then evaluating
     <#46877#>(hangman-guess<#46877#> <#46878#>'<#46878#><#46879#>a)<#46879#>
    
    produces <#68515#><#46883#>``You<#46883#>\ <#46884#>won''<#46884#><#68515#>. The evaluation has no effect in this case.
  3. If <#68516#><#46885#>status-word<#46885#><#68516#> is <#68517#><#46886#>(list<#46886#>\ <#46887#>'<#46887#><#46888#>b<#46888#>\ <#46889#>'<#46889#><#46890#>_<#46890#>\ <#46891#>'<#46891#><#46892#>l<#46892#>\ <#46893#>'<#46893#><#46894#>l)<#46894#><#68517#>, <#68518#><#46895#>chosen-word<#46895#><#68518#> is <#68519#><#46896#>(list<#46896#>\ <#46897#>'<#46897#><#46898#>b<#46898#>\ <#46899#>'<#46899#><#46900#>a<#46900#>\ <#46901#>'<#46901#><#46902#>l<#46902#>\ <#46903#>'<#46903#><#46904#>l)<#46904#><#68519#>, and <#68520#><#46905#>body-parts-left<#46905#><#68520#> is <#68521#><#46906#>(list<#46906#>\ <#46907#>'<#46907#><#46908#>right-leg<#46908#>\ <#46909#>'<#46909#><#46910#>left-leg)<#46910#><#68521#>, then evaluating
     <#46915#>(hangman-guess<#46915#> <#46916#>'<#46916#><#46917#>l)<#46917#>
    
    produces <#68522#><#46921#>(list<#46921#>\ <#46922#>``Sorry''<#46922#>\ <#46923#>'<#46923#><#46924#>right-leg<#46924#>\ <#46925#>(list<#46925#>\ <#46926#>'<#46926#><#46927#>b<#46927#>\ <#46928#>'<#46928#><#46929#>_<#46929#>\ <#46930#>'<#46930#><#46931#>l<#46931#>\ <#46932#>'<#46932#><#46933#>l))<#46933#><#68522#> and <#68523#><#46934#>body-parts-left<#46934#><#68523#> becomes <#68524#><#46935#>(list<#46935#>\ <#46936#>'<#46936#><#46937#>left-leg)<#46937#><#68524#>.
  4. Finally, if <#68525#><#46938#>status-word<#46938#><#68525#> is <#68526#><#46939#>(list<#46939#>\ <#46940#>'<#46940#><#46941#>b<#46941#>\ <#46942#>'<#46942#><#46943#>_<#46943#>\ <#46944#>'<#46944#><#46945#>l<#46945#>\ <#46946#>'<#46946#><#46947#>l)<#46947#><#68526#>, <#68527#><#46948#>chosen-word<#46948#><#68527#> is <#68528#><#46949#>(list<#46949#>\ <#46950#>'<#46950#><#46951#>b<#46951#>\ <#46952#>'<#46952#><#46953#>a<#46953#>\ <#46954#>'<#46954#><#46955#>l<#46955#>\ <#46956#>'<#46956#><#46957#>l)<#46957#><#68528#>, and <#68529#><#46958#>body-parts-left<#46958#><#68529#> is <#68530#><#46959#>(list<#46959#>\ <#46960#>'<#46960#><#46961#>left-leg)<#46961#><#68530#>, then evaluating
     <#46966#>(hangman-guess<#46966#> <#46967#>'<#46967#><#46968#>l)<#46968#>
    
    produces <#68531#><#46972#>(list<#46972#>\ <#46973#>``The<#46973#>\ <#46974#>End''<#46974#>\ <#46975#>(list<#46975#>\ <#46976#>'<#46976#><#46977#>b<#46977#>\ <#46978#>'<#46978#><#46979#>a<#46979#>\ <#46980#>'<#46980#><#46981#>l<#46981#>\ <#46982#>'<#46982#><#46983#>l))<#46983#><#68531#> and <#68532#><#46984#>body-parts-left<#46984#><#68532#> becomes <#68533#><#46985#>empty<#46985#><#68533#>.
The first two examples illustrate what happens when the player enters a guess that reveals new information; the last two focus on those cases where the guess contributes nothing. The case split naturally suggests a basic template based on a distinction among the possible situations:
<#46991#>(d<#46991#><#46992#>efine<#46992#> <#46993#>(hangman-guess<#46993#> <#46994#>guess)<#46994#>
  <#46995#>(c<#46995#><#46996#>ond<#46996#> 
    <#46997#>[<#46997#><#46998#>.<#46998#><#46999#>..<#46999#> <#71787#>;; <#68534#><#47000#>guess<#47000#><#68534#> did reveal new information: <#71787#> 
      <#47001#>(c<#47001#><#47002#>ond<#47002#> 
        <#47003#>[<#47003#><#47004#>...<#47004#> <#47005#>;; guess completed the search for the word<#47005#> 
         <#47006#>...]<#47006#> 
        <#47007#>[<#47007#><#47008#>.<#47008#><#47009#>..<#47009#> <#68535#>;; guess did <#47010#>not<#47010#> complete the search for the word<#68535#> 
          <#47011#>(b<#47011#><#47012#>egin<#47012#> 
            <#47013#>(set!<#47013#> <#47014#>status-word<#47014#> <#47015#>...)<#47015#> 
            <#47016#>...)]<#47016#><#47017#>)]<#47017#> 
    <#47018#>[<#47018#><#47019#>...<#47019#> <#71788#>;; <#68536#><#47020#>guess<#47020#><#68536#> did <#47021#>not<#47021#> reveal any new information: <#71788#> 
     <#47022#>(b<#47022#><#47023#>egin<#47023#> 
       <#47024#>(set!<#47024#> <#47025#>body-parts-left<#47025#> <#47026#>...)<#47026#> 
       <#47027#>...<#47027#> <#47028#>)]<#47028#><#47029#>))<#47029#> 
The location of the <#68537#><#47033#>set!<#47033#>-expression<#68537#>s in the template's nested <#68538#><#47034#>cond<#47034#><#68538#>s specify exactly under which conditions effects happen. First, the outermost conditional distinguishes whether or not <#68539#><#47035#>guess<#47035#><#68539#> produces new knowledge about the hidden word; if it doesn't, the function must modify <#68540#><#47036#>body-parts-left<#47036#><#68540#>. Second, if <#68541#><#47037#>guess<#47037#><#68541#> reveals new knowledge, the function updates the <#68542#><#47038#>status-word<#47038#><#68542#> variable unless the player has just finished the entire word. Because we haven't considered yet how to express these tests, we use comments to indicate what the conditions are. Let us turn to this problem first, so that we can start the function-definition step with a full-fledged template. The first missing condition concerns the question whether <#68543#><#47039#>guess<#47039#><#68543#> reveals new information. To this end, we must compare <#68544#><#47040#>guess<#47040#><#68544#> with the letters in <#68545#><#47041#>chosen-word<#47041#><#68545#>. This comparison should produce the new status word. Here is the specification for the auxiliary function that conducts this computation:
<#71789#>;; <#68546#><#47046#>reveal-list<#47046#> <#47047#>:<#47047#> <#47048#>word<#47048#> <#47049#>word<#47049#> <#47050#>letter<#47050#> <#47051#><#47051#><#47052#>-;SPMgt;<#47052#><#47053#><#47053#> <#47054#>word<#47054#><#68546#><#71789#>
<#71790#>;; to compute the new status word from <#68547#><#47055#>chosen-word<#47055#><#68547#>,<#71790#> 
<#71791#>;; <#68548#><#47056#>status-word<#47056#><#68548#>, and <#68549#><#47057#>guess<#47057#><#68549#><#71791#> 
<#47058#>(define<#47058#> <#47059#>(reveal-list<#47059#> <#47060#>chosen-word<#47060#> <#47061#>status-word<#47061#> <#47062#>guess)<#47062#> <#47063#>...)<#47063#> 
Fortunately, we have discussed this auxiliary function twice before (see sections~#sechangman#47067> and exercise~#exhangmanlist#47068>) and know how to define it; figure~#fighangmanstate3#47069> contains a suitable definition. Using <#68550#><#47070#>reveal-list<#47070#><#68550#>, we can now formulate a condition that determines whether <#68551#><#47071#>guess<#47071#><#68551#> reveals new knowledge:
<#47076#>(equal?<#47076#> <#47077#>status-word<#47077#> <#47078#>(reveal-list<#47078#> <#47079#>status-word<#47079#> <#47080#>chosen-word<#47080#> <#47081#>guess))<#47081#>
The condition uses <#68552#><#47085#>equal?<#47085#><#68552#> to compare the current value of <#68553#><#47086#>status-word<#47086#><#68553#> with its new value, as computed by <#68554#><#47087#>reveal-list<#47087#><#68554#>. If the two lists are equal, <#68555#><#47088#>guess<#47088#><#68555#> doesn't produce new knowledge; otherwise it does. The second missing condition concerns the question whether the given <#68556#><#47089#>guess<#47089#><#68556#> completes the search for the word. If <#68557#><#47090#>guess<#47090#><#68557#> is equal to all missing letters in <#68558#><#47091#>status-word<#47091#><#68558#>, then the player has found the complete word. Here is the corresponding condition:
<#47096#>(equal?<#47096#> <#47097#>chosen-word<#47097#> <#47098#>(reveal-list<#47098#> <#47099#>status-word<#47099#> <#47100#>chosen-word<#47100#> <#47101#>guess))<#47101#>
That is, the game is over if <#68559#><#47105#>chosen-word<#47105#><#68559#> is equal to the result of <#68560#><#47106#>reveal-list<#47106#><#68560#>. Let's put everything together in a single template:
<#47111#>(d<#47111#><#47112#>efine<#47112#> <#47113#>(hangman-guess<#47113#> <#47114#>guess)<#47114#>
  <#47115#>(l<#47115#><#47116#>ocal<#47116#> <#47117#>((define<#47117#> <#47118#>new-status<#47118#> <#47119#>(reveal-list<#47119#> <#47120#>status-word<#47120#> <#47121#>chosen-word<#47121#> <#47122#>guess)))<#47122#> 
    <#47123#>(c<#47123#><#47124#>ond<#47124#> 
      <#47125#>[<#47125#><#47126#>(equal?<#47126#> <#47127#>new-status<#47127#> <#47128#>status-word)<#47128#> 
       <#47129#>(b<#47129#><#47130#>egin<#47130#> 
         <#47131#>(set!<#47131#> <#47132#>body-parts-left<#47132#> <#47133#>...)<#47133#> 
         <#47134#>...<#47134#> <#47135#>)]<#47135#> 
      <#47136#>[<#47136#><#47137#>else<#47137#> 
       <#47138#>(c<#47138#><#47139#>ond<#47139#> 
         <#47140#>[<#47140#><#47141#>(equal?<#47141#> <#47142#>new-status<#47142#> <#47143#>chosen-word)<#47143#> 
          <#47144#>...]<#47144#> 
         <#47145#>[<#47145#><#47146#>else<#47146#> 
          <#47147#>(b<#47147#><#47148#>egin<#47148#> 
            <#47149#>(set!<#47149#> <#47150#>status-word<#47150#> <#47151#>...)<#47151#> 
            <#47152#>...)]<#47152#><#47153#>)]<#47153#><#47154#>)))<#47154#> 
The template uses a <#68561#><#47158#>local<#47158#>-expression<#68561#> because the result of <#68562#><#47159#>reveal-list<#47159#><#68562#> is used in two conditions. Also, in this template the two outer <#68563#><#47160#>cond<#47160#><#68563#>-clauses are swapped, because it is more natural to write
<#47165#>(equal?<#47165#> <#47166#>new-status<#47166#> <#47167#>status-word)<#47167#>
than its negation. We can now turn to the function-design step. The template is conditional. So we develop the effect and the answer for each clause separately:
  1. Assume that <#68564#><#47172#>(equal?<#47172#>\ <#47173#>new-status<#47173#>\ <#47174#>status-word)<#47174#><#68564#> evaluates to <#68565#><#47175#>true<#47175#><#68565#>, that is, the player made no progress. This implies that the player loses an imaginary body part. To capture this effect, the <#47176#>set!<#47176#>-expression\ must change the value of <#68566#><#47177#>body-parts-left<#47177#><#68566#>. Specifically, it must set the state variable to the rest of its current value:
    <#47182#>(set!<#47182#> <#47183#>body-parts-left<#47183#> <#47184#>(rest<#47184#> <#47185#>body-parts-left))<#47185#>
    
    The answer depends on the new value of <#68567#><#47189#>body-parts-left<#47189#><#68567#>. If it is <#68568#><#47190#>empty<#47190#><#68568#>, the game is over; the appropriate response is <#68569#><#47191#>(list<#47191#>\ <#47192#>``The<#47192#>\ <#47193#>End''<#47193#>\ <#47194#>chosen-word)<#47194#><#68569#> so that the player finds out what the chosen word was. If <#68570#><#47195#>body-parts-left<#47195#><#68570#> is not empty, the response is <#68571#><#47196#>(list<#47196#>\ <#47197#>``Sorry''<#47197#>\ <#47198#>?<#47198#><#47199#>?<#47199#><#47200#>?<#47200#>\ <#47201#>status-word)<#47201#><#68571#>. The response says that <#68572#><#47202#>guess<#47202#><#68572#> is useless. Its last part is the current value of <#68573#><#47203#>status-word<#47203#><#68573#> so that the player sees what he has discovered. The <#68574#><#47204#>?<#47204#><#47205#>?<#47205#><#47206#>?<#47206#><#68574#> indicates a problem. To understand the problem, take a look at what we have:
    <#47211#>(b<#47211#><#47212#>egin<#47212#> 
      <#47213#>(set!<#47213#> <#47214#>body-parts-left<#47214#> <#47215#>(rest<#47215#> <#47216#>body-parts-left))<#47216#> 
      <#47217#>(c<#47217#><#47218#>ond<#47218#> 
        <#47219#>[<#47219#><#47220#>(empty?<#47220#> <#47221#>body-parts-left)<#47221#> <#47222#>(list<#47222#> <#47223#>``The<#47223#> <#47224#>End''<#47224#> <#47225#>chosen-word)]<#47225#> 
        <#47226#>[<#47226#><#47227#>else<#47227#> <#47228#>(list<#47228#> <#47229#>``Sorry''<#47229#> <#47230#>?<#47230#><#47231#>?<#47231#><#47232#>?<#47232#> <#47233#>status-word)]<#47233#><#47234#>))<#47234#> 
    
    In principle, the question marks should be the body part that the player just lost to the gallows. But, because <#68575#><#47238#>set!<#47238#><#68575#> modifies <#68576#><#47239#>body-parts-left<#47239#><#68576#>, we can no longer just say <#68577#><#47240#>(first<#47240#><#47241#> <#47241#>\ <#47242#>body-parts-left)<#47242#><#68577#>. As mentioned in section~#secseqtime#47243>, when programming with <#68578#><#47244#>set!<#47244#><#68578#> timing matters. We can solve the problem with a <#68579#><#47245#>local<#47245#>-expression<#68579#>s that names the first item on <#68580#><#47246#>body-parts-left<#47246#><#68580#> before the state variable is modified.
  2. The second case is much simpler than the first. We distinguish two subcases:
    1. If <#68581#><#47248#>new-status<#47248#><#68581#> is equal to <#68582#><#47249#>chosen-word<#47249#><#68582#>, the player has won. The response is <#68583#><#47250#>``You<#47250#>\ <#47251#>won''<#47251#><#68583#>; there is no effect.
    2. If the two are not equal, the player made some progress and must be told. Furthermore, the function must keep track of the progress; a <#68584#><#47252#>(set!<#47252#>\ <#47253#>status-word<#47253#>\ <#47254#>new-status)<#47254#><#68584#> accomplishes this effect. The response consists of an encouragement and the new status.
Figure~#fighangmanstate3#47257> contains the complete definition of <#68585#><#47258#>hangman-guess<#47258#><#68585#>.
<#71792#>;; <#68586#><#47263#>hangman-guess<#47263#> <#47264#>:<#47264#> <#47265#>letter<#47265#> <#47266#><#47266#><#47267#>-;SPMgt;<#47267#><#47268#><#47268#> <#47269#>response<#47269#><#68586#><#71792#>
<#47270#>;; to determine whether the player has won, lost, or may continue to play<#47270#> 
<#47271#>;; and, if so, which body part was lost, if no progress was made<#47271#> 
<#71793#>;; effects: (1) if the guess represents progress, update <#68587#><#47272#>status-word<#47272#><#68587#><#71793#> 
<#71794#>;; (2) if not, shorten the <#68588#><#47273#>body-parts-left<#47273#><#68588#> by one <#71794#> 
<#47274#>(d<#47274#><#47275#>efine<#47275#> <#47276#>(hangman-guess<#47276#> <#47277#>guess)<#47277#> 
  <#47278#>(l<#47278#><#47279#>ocal<#47279#> <#47280#>((define<#47280#> <#47281#>new-status<#47281#> <#47282#>(reveal-list<#47282#> <#47283#>chosen-word<#47283#> <#47284#>status-word<#47284#> <#47285#>guess)))<#47285#> 
    <#47286#>(c<#47286#><#47287#>ond<#47287#> 
      <#47288#>[<#47288#><#47289#>(equal?<#47289#> <#47290#>new-status<#47290#> <#47291#>status-word)<#47291#> 
       <#47292#>(l<#47292#><#47293#>ocal<#47293#> <#47294#>((define<#47294#> <#47295#>next-part<#47295#> <#47296#>(first<#47296#> <#47297#>body-parts-left)))<#47297#> 
         <#47298#>(b<#47298#><#47299#>egin<#47299#> 
           <#47300#>(set!<#47300#> <#47301#>body-parts-left<#47301#> <#47302#>(rest<#47302#> <#47303#>body-parts-left))<#47303#> 
           <#47304#>(c<#47304#><#47305#>ond<#47305#> 
             <#47306#>[<#47306#><#47307#>(empty?<#47307#> <#47308#>body-parts-left)<#47308#> <#47309#>(list<#47309#> <#47310#>``The<#47310#> <#47311#>End''<#47311#> <#47312#>chosen-word)]<#47312#> 
             <#47313#>[<#47313#><#47314#>else<#47314#> <#47315#>(list<#47315#> <#47316#>``Sorry''<#47316#> <#47317#>next-part<#47317#> <#47318#>status-word)]<#47318#><#47319#>)))]<#47319#> 
      <#47320#>[<#47320#><#47321#>else<#47321#> 
       <#47322#>(c<#47322#><#47323#>ond<#47323#> 
         <#47324#>[<#47324#><#47325#>(equal?<#47325#> <#47326#>new-status<#47326#> <#47327#>chosen-word)<#47327#> <#47328#>``You<#47328#> <#47329#>won'']<#47329#> 
         <#47330#>[<#47330#><#47331#>else<#47331#> 
          <#47332#>(b<#47332#><#47333#>egin<#47333#> 
            <#47334#>(set!<#47334#> <#47335#>status-word<#47335#> <#47336#>new-status)<#47336#> 
            <#47337#>(list<#47337#> <#47338#>``Good<#47338#> <#47339#>guess!''<#47339#> <#47340#>status-word))]<#47340#><#47341#>)]<#47341#><#47342#>)))<#47342#> 
<#71795#>;; <#68589#><#47343#>reveal-list<#47343#> <#47344#>:<#47344#> <#47345#>word<#47345#> <#47346#>word<#47346#> <#47347#>letter<#47347#> <#47348#><#47348#><#47349#>-;SPMgt;<#47349#><#47350#><#47350#> <#47351#>word<#47351#><#68589#><#71795#> 
<#47352#>;; to compute the new status word<#47352#> 
<#47353#>(d<#47353#><#47354#>efine<#47354#> <#47355#>(reveal-list<#47355#> <#47356#>chosen-word<#47356#> <#47357#>status-word<#47357#> <#47358#>guess)<#47358#> 
  <#47359#>(l<#47359#><#47360#>ocal<#47360#> <#47361#>((d<#47361#><#47362#>efine<#47362#> <#47363#>(reveal-one<#47363#> <#47364#>chosen-letter<#47364#> <#47365#>status-letter)<#47365#> 
            <#47366#>(c<#47366#><#47367#>ond<#47367#> 
              <#47368#>[<#47368#><#47369#>(symbol=?<#47369#> <#47370#>chosen-letter<#47370#> <#47371#>guess)<#47371#> <#47372#>guess]<#47372#> 
              <#47373#>[<#47373#><#47374#>else<#47374#> <#47375#>status-letter]<#47375#><#47376#>)))<#47376#> 
    <#47377#>(map<#47377#> <#47378#>reveal-one<#47378#> <#47379#>chosen-word<#47379#> <#47380#>status-word)))<#47380#> 
<#47384#>Figure: Hangman Basics (Part 3)<#47384#>

<#47388#>Exercise 37.2.3<#47388#> Draw a diagram that shows how <#68590#><#47390#>hangman<#47390#><#68590#> and <#68591#><#47391#>hangman-guess<#47391#><#68591#> interact with the state variables.~ external Solution<#68592#><#68592#> <#47397#>Exercise 37.2.4<#47397#> Formulate the four examples for <#68593#><#47399#>hangman-guess<#47399#><#68593#> as boolean-valued expressions that produce <#68594#><#47400#>true<#47400#><#68594#> if <#68595#><#47401#>hangman-guess<#47401#><#68595#> is correct. Develop an additional example for each case; turn these new examples into additional tests.~ external Solution<#68596#><#68596#> <#47407#>Exercise 37.2.5<#47407#> Develop a graphical user interface, similar to that of the teachpack <#47409#>hangman.ss<#47409#>. Connect the functions in this section as call-backs.~ external Solution<#68597#><#68597#> <#47415#>Exercise 37.2.6<#47415#> Modify the program so that it keeps track of all the guesses. Then, if a player enters the same guess twice for the same round of a hangman game, the response of <#68598#><#47417#>hangman-guess<#47417#><#68598#> is <#68599#><#47418#>``You<#47418#>\ <#47419#>have<#47419#>\ <#47420#>used<#47420#>\ <#47421#>this<#47421#>\ <#47422#>guess<#47422#><#47423#> <#47423#><#47424#>before.``<#47424#><#68599#>~ external Solution<#68600#><#68600#> <#47430#>Exercise 37.2.7<#47430#> Consider the following variant of <#68601#><#47432#>reveal-list!<#47432#><#68601#>:
<#71796#>;; <#68602#><#47437#>reveal-list!<#47437#> <#47438#>:<#47438#> <#47439#>letter<#47439#> <#47440#><#47440#><#47441#>-;SPMgt;<#47441#><#47442#><#47442#> <#47443#>void<#47443#><#68602#><#71796#>
<#71797#>;; effect: to modify <#68603#><#47444#>status-word<#47444#><#68603#> based on a comparison of <#68604#><#47445#>chosen-word<#47445#><#68604#>,<#71797#> 
<#71798#>;; the <#68605#><#47446#>status-word<#47446#><#68605#>, and the player's <#68606#><#47447#>guess<#47447#><#68606#><#71798#> 
<#47448#>(d<#47448#><#47449#>efine<#47449#> <#47450#>(reveal-list!<#47450#> <#47451#>chosen-word<#47451#> <#47452#>status-word<#47452#> <#47453#>guess)<#47453#> 
  <#47454#>(l<#47454#><#47455#>ocal<#47455#> <#47456#>((d<#47456#><#47457#>efine<#47457#> <#47458#>(reveal-one<#47458#> <#47459#>chosen-letter<#47459#> <#47460#>status-letter)<#47460#> 
            <#47461#>(c<#47461#><#47462#>ond<#47462#> 
              <#47463#>[<#47463#><#47464#>(symbol=?<#47464#> <#47465#>chosen-letter<#47465#> <#47466#>guess)<#47466#> <#47467#>guess]<#47467#> 
              <#47468#>[<#47468#><#47469#>else<#47469#> <#47470#>status-letter]<#47470#><#47471#>)))<#47471#> 
    <#47472#>(set!<#47472#> <#47473#>status-word<#47473#> <#47474#>(map<#47474#> <#47475#>reveal-one<#47475#> <#47476#>chosen-word<#47476#> <#47477#>status-word))))<#47477#> 
It changes the state variable <#68607#><#47481#>status-word<#47481#><#68607#> to a value that is computed from the old value of <#68608#><#47482#>status-word<#47482#><#68608#>, <#68609#><#47483#>chosen-word<#47483#><#68609#>, and the guess. Modify <#68610#><#47484#>hangman-guess<#47484#><#68610#> so that it works properly with the <#68611#><#47485#>reveal-list!<#47485#><#68611#> function.~ external Solution<#68612#><#68612#>