Hangman

Class demo for Intro Programming class
September 2004
Jim Mahoney

Define the program

How do we break this problem into smaller pieces?

Well, here's how I did it.  
Below are a number of short discrete function definitions,
each followed by a short test to see if it worked.

This wasn't my first attempt; I had to play around a bit to find what I wanted.
I started by looking at the Mathematica help stuff under ?*String* .
Originally I used the InputString[] function to talk to the user,
but all those pop up dialogs got tacky after a while.

The basic idea is that I store the hidden word in one variable,
and what the player currently knows in another, 
with "*" characters for the letters that haven't been guessed yet.
After each guess, the program loops over the letters in the word
to see if each matches the guess, and if so, copies those correct
letters over the "*" characters.

As I played with this, I kept adding features - like the ability to guess the entire word.
Just having too much fun...

(* 
      Return a random word from a list. *) 
getRandomWord[wordList_] := 
        Module[{i}, 
i  =  
            Random[Integer, {1, Length[wordList]}]; 
Return[
            wordList[[i]]];
];

\(getRandomWord[\ {"impossible", \ "turkey", \ "hilarious"}]\)

\(getRandomWord[\ {"impossible", \ "turkey", \ "hilarious"}]\)

\(\(\( (*\ Given\ a\ word, \ 
      return\ a\ string\ of\ periods\ the\ same\ \(\(length\)\(.\)\)\ *) \)\(
\)\(\(convertToBlanks[word_] := 
        Module[{blanks}, 
blanks\  = \ ""; 
Do[\ 
	
            blanks = 
              blanks\  <> "*"\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \  (*\ \ \ a\  <> \ b\ \ \  ⇔ \ \ \ StringJoin[a, 
                  b]\ \ *) 
, {StringLength[
                word]}
]; 
Return[
            blanks];
];\)
 (*\ 
      Here' s\ another\ way, \ terser, \ 
      more\ "mathematica-ish"\ way\ to\ do\ the\ same\ \(\(thing\)\(.\)\)\ *) 

    \(convertToBlanks2[word_] := 
        StringInsert["", "*", 
          Table[1, {StringLength[word]}]];\)\)\)\)

convertToBlanks["12345"]

convertToBlanks2["12345"]

\(\(\( (*\ 
      Search\ each\ spot\ in\ an\ "answer"\ string\ for\ a\ given\ letter . \ \ In\ each\ position\ that\ it' s\ found, \ 
      copy\ it\ into\ a\ second\ "known"\ string\ in\ that\ spot . \ \ Return\ the\ modified\ "known"\ \(\(string\)\(.\)\)\ *) \)\(
\)\(lookForLetter[answer_, known_, letter_] := 
        Module[{ithLetter, copyOfKnown}, 
copyOfKnown\  = \ 
            known; 
Do[
	
            ithLetter\  = \ 
              StringTake[
                answer, {i, 
                  i}]; \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 
	
            If[ithLetter\  == \ letter, \ 
              copyOfKnown\  = \ 
                StringReplacePart[copyOfKnown, 
                  letter, {i, i}]];
, {i, 1, 
              StringLength[
                answer]}
]; 
Return[
            copyOfKnown];
];\)\)\)

lookForLetter["hello", ".....", "l"]

lookForLetter["hello", "..ll.", "o"]

lookForLetter["hello", "..llo", "x"]

\(\(\( (*\ 
      Tell\ the\ player\ some\ \(\(stuff\)\(.\)\)\ *) \)\(
\)\(tellStuff[number_, \ word_] := 
        Module[{}, 
\(Print[\ " After guess "\  <> \ 
                ToString[number]\  <> \ ", you have '"\  <> \ 
                word\  <> \ "'.  Guess again."];\)
];\)\)\)

tellStuff[2, "...a..."];

lookForWholeAnswer[answer_, known_, 
          wordGuessed_] := 
        Module[{}, 
If[
              answer == wordGuessed, 
   
              Return[answer], 
   
              Return[known]
];
];

lookForWholeAnswer["original", "........", "badguess"]

lookForWholeAnswer["original", "........", "original"]

\(\(\( (*\ 
      Initialize\ \(game\  : 
1. \ set\ globals\ nGuesses\), \ hiddenWord, \ 
      whatPlayerSees, \ 
\ \ 2. \ talk\ to\ the\ player
\ 
        3. \ prompt\ player\ for\ first\ \(\(guess\)\(.\)\)\ *) \)\(
\)\(hangman[] := 
        Module[{}, 
nGuesses\  = \ 
            0; \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \  (*\ 
            number\ of\ player\ guesses\ so\ far\ *) 
wordList\  = \ {"impossible", \ "turkey", \ "hilarious", "stupendous", "amazing", "fantastic"}; 
hiddenWord\  = \ 
            getRandomWord[wordList]; 
whatPlayerSees\  = \ 
            convertToBlanks[
              hiddenWord]; 
Print[\ " *** Hangman *** "]; 
Print[\ " Picking a random word... OK, the word is is ""\  <> \ 
              whatPlayerSees\  <> ""."\ ]; 
Print[\ " Start guessing a single letter or the whole answer by typing things like 'guess[e]' or 'guess[answer]'."];
];\)\)\)

hangman[]

\(\(\( (*\ 
      When\ the\ player\ makes\ a\ guess, 
0. \ convert\ input\ symbol\ to\ a\ string\ character\ or\ word, \ 
1. \ increment\ the\ counter, \ 
2. \ update\ what' 
        s\ known, \ 
3. \ give\ hints\ about\ what\ happened, 
4. \ prompt\ for\ the\ next\ \(\(guess\)\(.\)\)\ *) \)\(
\)\(guess[input_] := 
        Module[{whatWasKnown, letter}, 
 (*\ 
            0. \ convert\ input\ symbol\ to\ a\ string\ character\ or\ word\ *) 
letterOrWord\  = \ 
            ToString[input]; 
 (*\ 
            1. \ increment\ the\ counter\ *) 
nGuesses\  = \ nGuesses\  + \ 1; 
 (*\ 
            2. \ update\ what' 
              s\ known\ *) 
whatWasKnown\  = \ 
            whatPlayerSees; \ \ \ \ \ \ \  (*\ 
            Remember\ what\ was\ known\ before\ so\ we\ can\ compare\ further\ \(\(down\)\(.\)\)\ *) 
If[
            StringLength[letterOrWord] > 1, 
 (*then*) \ 
            whatPlayerSees\  = \ 
              lookForWholeAnswer[hiddenWord, whatPlayerSees, 
                letterOrWord], 
 (*else*) \ 
            whatPlayerSees\  = \ 
              lookForLetter[hiddenWord, whatPlayerSees, 
                letterOrWord]
]; 
 (*\ 
            3. \ give\ hints\ *) 
If[
            whatPlayerSees\  == \ whatWasKnown\  && \ 
              StringLength[letterOrWord] > 1, \ 
            Print["Nope, the word isn't ""\  <> \ 
                letterOrWord\  <> ""."]]; 
If[
            whatPlayerSees\  == \ whatWasKnown\  && \ 
              StringLength[letterOrWord] == 1, \ 
            Print["Nope, there isn't a ""\  <> \ 
                letterOrWord\  <> "" in the word."]]; 
If[whatPlayerSees == hiddenWord, 
            Print[" Yup, the word is ""\  <> \ 
                hiddenWord\  <> "". You won in "\  <> \ 
                ToString[
                  nGuesses]\  <> \ " guesses."]; 
Return[]; \ \  (*\ We' re\ finished, \ 
              so\ don' t\ need\ to\ prompt\ for\ next\ guess; \ 
              leave\ \(\(now\)\(.\)\)\ *) 
]; 
 (*\ 
            prompt\ for\ the\ next\ guess\ *) 
tellStuff[
            nGuesses, whatPlayerSees];
];\)\)\)

hiddenWord

guess[a]

Play the game

To start the game, evaluate hangman[].

hangman[]

guess[e]

guess[a]

guess[futureistic]

guess[s]

guess[z]

guess[t]

guess[n]

guess[stupendous]

Watching it run

TracePrint[hangman[], TraceDepth -> 3]