Hangman Game Simulation
Solution
;-------------------------------------------------------------
; Program that simulates a game of Hangman
;-------------------------------------------------------------
TITLE Hangman. asm
INCLUDE irvine32.inc
.DATA
help0 BYTE " Hangman", 0dh, 0ah, 0
help1 BYTE "The game consists in completing a word of a given length by", 0dh, 0ah, 0
help2 BYTE "guessing correctly its letters or guessing the complete word.", 0dh, 0ah, 0
help3 BYTE "You have 5 chances to guess a letter and only 3 to guess a word.", 0dh, 0ah, 0
menu0 BYTE "Game Menu", 0dh, 0ah, 0
menu1 BYTE " 1. Play", 0dh, 0ah, 0
menu2 BYTE " 2. Statistics", 0dh, 0ah, 0
menu3 BYTE " 3. Quit", 0dh, 0ah, 0
menu4 BYTE "Selection? ", 0
stats0 BYTE 0dh,0ah,"Games statistics",0dh,0ah,0
stats1 BYTE "Games played: ",0
stats2 BYTE "Games won: ",0
stats3 BYTE "Games lost: ",0
wordMsg BYTE "Word = ", 0
guessTypeMsg BYTE "Do you wish to guess a letter or the whole word: ( 1 for letter 2 for word) ",0
guessLetterMsg BYTE "Guess a letter: ",0
guessWordMsg BYTE "Guess the word: ",0
invOptionMsg BYTE "Invalid option. Please try again", 0dh, 0ah, 0
noLetterMsg BYTE "You ran out of letter guesses.", 0dh, 0ah, 0
loseMsg BYTE "That is incorrect. You lose",0dh, 0ah,0dh, 0ah, 0
winMsg BYTE "That is correct. You win",0dh, 0ah,0dh, 0ah, 0
leftLetterMsg1 BYTE "( ",0
leftLetterMsg2 BYTE " letter guesses left)",0
badWordMsg1 BYTE "That is incorrect - ",0
badWordMsg2 BYTE " word guesses remaining",0dh,0ah,0
String0 BYTE "fruit", 0h
String1 BYTE "kayak", 0h
String2 BYTE "beauceron", 0h
String3 BYTE "puppy", 0h
String4 BYTE "phoenix", 0h
String5 BYTE "pizza", 0h
String6 BYTE "frigate", 0h
String7 BYTE "ketchup", 0h
String8 BYTE "chai", 0h
String9 BYTE "basket", 0h
String10 BYTE "cabinet", 0h
String11 BYTE "rescue", 0h
String12 BYTE "machine", 0h
String13 BYTE "mississippian", 0h
String14 BYTE "destroyer", 0h
String15 BYTE "zoomies", 0h
String16 BYTE "hangman", 0h
String17 BYTE "preface", 0h
String18 BYTE "annoying", 0h
String19 BYTE "candle", 0h
StringTable DWORD String0, String1, String2, String3, String4
DWORD String5, String6, String7, String8, String9
DWORD String10, String11, String12, String13, String14
DWORD String15, String16, String17, String18, String19
random word DWORD 0
current word BYTE 50 DUP(?)
guessWord BYTE 20 DUP(?)
letters BYTE 5
words BYTE 3
lguess BYTE 0
gamesPlayed DWORD 0
gamesWon DWORD 0
gamesLost DWORD 0
quitflg DB 0
.CODE
main PROC
call Randomize ; initialize random generator
; Print initial help
mov edx, OFFSET help0 ; load address of string to print in edx
call WriteString ; use Irvine library to print string
mov edx, OFFSET help1 ; load address of string to print in edx
call WriteString ; use Irvine library to print string
mov edx, OFFSET help2 ; load address of string to print in edx
call WriteString ; use Irvine library to print string
mov edx, OFFSET help3 ; load address of string to print in edx
call WriteString ; use Irvine library to print string
call CrLf ; leave an empty line
call WaitMsg ; wait for user to press a key
call ClrScr ; clear the screen using irvine library
gameStart:
; Print option menu
mov edx, OFFSET menu0 ; load address of string to print in edx
call WriteString ; use Irvine library to print string
mov edx, OFFSET menu1 ; load address of string to print in edx
call WriteString ; use Irvine library to print string
mov edx, OFFSET menu2 ; load address of string to print in edx
call WriteString ; use Irvine library to print string
mov edx, OFFSET menu3 ; load address of string to print in edx
call WriteString ; use Irvine library to print string
readOption:
mov edx, OFFSET menu4 ; load address of string to print in edx
call WriteString ; use Irvine library to print string
call ReadDec ; read a number from the user
cmp al, 1 ; if the user selected option 1
je play ; play the game
cmp al, 2 ; if the user selected option 2
je stats ; show statistics
cmp al, 3 ; else, if 3 was selected
je quit ; quit the game
; print invalid option message
mov edx, OFFSET invOptionMsg ; load address of string to print in edx
call WriteString ; use Irvine library to print string
jmp readOption ; try again
play:
inc DWORD PTR [gamesPlayed] ; increment played games
mov esi, OFFSET StringTable ; point to start of string table
mov eax, 20 ; pass number of words in table
call genRandomWord ; generate a random guess word
mov [randomWord], eax ; get pointer to random word in variable
mov esi, [randomWord] ; pass the string address to strlen
call Strlen ; calculate the string length
mov esi, OFFSET currentWord ; pass guess word to initialize it
call initializeString ; initialize guess word filling underscores
mov BYTE PTR [letters], 5 ; letter guesses
mov BYTE PTR [words], 3 ; word guesses
mov BYTE PTR [lguess], 0 ; clear letter guess flag
playLoop:
; print word message
mov edx, OFFSET wordMsg ; load address of string to print in edx
call WriteString ; use Irvine library to print string
mov edx, OFFSET currentWord ; load address of guess word
call WriteString ; print current guess word
cmp BYTE PTR [lguess], 0 ; see if last guess was a letter
je typeStart ; if not, ask for input
; print first part of left letters message
mov edx, OFFSET leftLetterMsg1 ; load address of string to print in edx
call WriteString ; use Irvine library to print string
movzx eax, BYTE PTR [letters] ; load number of left letters
call WriteDec ; print number
; print second part of left letters message
mov edx, OFFSET leftLetterMsg2 ; load address of string to print in edx
call WriteString ; use Irvine library to print string
typeStart:
call CrLf ; jump to next line
typeLoop:
; print prompt for type of guess
mov edx, OFFSET guessTypeMsg ; load address of string to print in edx
call WriteString ; use Irvine library to print string
call ReadDec ; read number from user
cmp eax, 1 ; if selected 1
je playLetter ; plays with a letter
cmp eax, 2 ; if selected 2
je playWord ; plays with a word
; print invalid option message
mov edx, OFFSET invOptionMsg ; load address of string to print in edx
call WriteString ; use Irvine library to print string
jmp typeLoop ; try again
playLetter:
cmp BYTE PTR [letters], 0 ; see if we are out of guesses
jg getLetter ; if there are some left, get the letter
; if out of guesses, print message
mov edx, OFFSET noLetterMsg ; load address of string to print in edx
call WriteString ; use Irvine library to print string
jmp typeLoop ; get another option
getLetter:
; print prompt for letter
mov edx, OFFSET guessLetterMsg ; load address of string to print in edx
call WriteString ; use Irvine library to print string
call ReadChar ; read a character
call WriteChar ; echo char on screen
call CrLf ; jump to next line
call tolower ; convert char to lowercase
mov esi, OFFSET currentWord ; load pointer to current word
mov edi, [randomWord] ; load pointer to random word
call updateGuess ; update the guessed chars
cmp eax, 0 ; see if there was a match
je updLetters ; if there was no match, update letter matches
mov esi, OFFSET currentWord ; load pointer to current word
call checkWin ; see if the user completed the word
cmp eax, 1 ; if there is a win
jne updLetters ; if not, update guesses
; print last word message
mov edx, OFFSET wordMsg ; load address of string to print in edx
call WriteString ; use Irvine library to print string
mov edx, OFFSET currentWord ; load address of guess word
call WriteString ; print current guess word
call CrLf ; jump to next line
jmp win ; go to win
updLetters:
mov BYTE PTR [lguess],1 ; set flag to indicate letter guess
dec BYTE PTR [letters] ; decrement number of guesses
jmp playLoop ; play again
playWord:
; print prompt for word
mov edx, OFFSET guessWordMsg ; load address of string to print in edx
call WriteString ; use Irvine library to print string
mov edx, OFFSET guessWord ; place to save string read
mov ecx, 20 ; maximum length to read
call ReadString ; read string from user
mov esi, OFFSET guessWord ; pass read string address
call strtolower ; convert string to lowercase
mov esi, OFFSET guessWord ; load address of guessed word
mov edi, [randomWord] ; load random word being played
call strcmp ; compare strings
cmp eax, 1 ; see if the strings are equal
je win ; if equal, user wins
mov BYTE PTR [lguess],0 ; clear flag to indicate no letter guess
dec BYTE PTR [words] ; else, decrement number of word guesses
cmp BYTE PTR [words], 0 ; see if we are out of word guesses
jg badWord ; if there are stil some left, play again
; else, print lose message
mov edx, OFFSET loseMsg ; load address of string to print in edx
call WriteString ; use Irvine library to print string
inc DWORD PTR [gamesLost] ; increment lost games
jmp stats ; jump to stats
badWord:
; bad word entered, print bad message
mov edx, OFFSET badWordMsg1 ; load address of string to print in edx
call WriteString ; use Irvine library to print string
movzx eax, BYTE PTR [words] ; load number of left words
call WriteDec ; print number
; print second part of bad message
mov edx, OFFSET badWordMsg2 ; load address of string to print in edx
call WriteString ; use Irvine library to print string
jmp playLoop ; play again
win:
; print win message
mov edx, OFFSET winMsg ; load address of string to print in edx
call WriteString ; use Irvine library to print string
inc DWORD PTR [gamesWon] ; increment won games
jmp stats
quit:
mov BYTE PTR [quitflg], 1 ; set quit flag to 1
stats:
; print stats title
mov edx, OFFSET stats0 ; load address of string to print in edx
call WriteString ; use Irvine library to print string
; print number of games played
mov edx, OFFSET stats1 ; load address of string to print in edx
call WriteString ; use Irvine library to print string
mov eax, [gamesPlayed] ; load number of played games
call WriteDec ; print on screen using irvine library
call CrLf
; print number of games won
mov edx, OFFSET stats2 ; load address of string to print in edx
call WriteString ; use Irvine library to print string
mov eax, [gamesWon] ; load number of won games
call WriteDec ; print on screen using irvine library
call CrLf
; print number of games lost
mov edx, OFFSET stats3 ; load address of string to print in edx
call WriteString ; use Irvine library to print string
mov eax, [gamesLost] ; load number of lost games
call WriteDec ; print on screen using irvine library
call CrLf
call CrLf
cmp BYTE PTR [quitflg], 0 ; if not quit
je gameStart ; jump to start of game menu
exit ; exit the program
ret
main ENDP
;-------------------------------------------------------------
strlen PROC
;
; Calculates the length of a zero-terminated string
; On entry: esi = pointer to string
; On return: eax = string length
;-------------------------------------------------------------
mov eax, 0 ; initialize length to zero
sloop:
cmp BYTE PTR [esi], 0 ; see if char is zero
je endsloop ; if zero, end loop
inc esi ; else, advance to next char
inc eax ; increment length
jmp sloop ; repeat loop
endsloop:
ret
strlen ENDP
;-------------------------------------------------------------
strcmp PROC
;
; Compares two strings
; On entry: esi = pointer to first string
; esi = pointer to second string
; On return: eax = 1 if both strings are equal, 0 otherwise
;-------------------------------------------------------------
cmploop:
mov al, [esi] ; load char from first string
cmp al, [edi] ; compare with same char in second string
jne notEqual ; if not equal, return
inc esi ; else, advance to next char in first string
inc edi ; advance to next char in second string
cmp al, 0 ; see if we compared the last char
jne cmploop ; if not, repeat loop
mov eax, 1 ; else, return 1 to indicate the stirngs are equal
ret
notEqual:
mov eax,0 ; return zero to indicate not equal
ret
strcmp ENDP
;-------------------------------------------------------------
genRandomWord PROC
;
; Generate a random word from a table of words
; On entry: esi = pointer to table
; eax = number of words in table
; On return: eax = pointer to randomly selected word
;-------------------------------------------------------------
push ebx ; save ebx value on stack
mov ebx, eax ; save number in ebx
call Random32 ; get a random number
mov edx, 0 ; clear edx or making division
div ebx ; divide random number by number of words
shl edx, 2 ; multiply remainder by 4 to get offset in string table
add esi, edx ; move address of selected string in esi
mov eax, [esi] ; load pointer to address from table and return it
pop ebx ; restore ebx
ret
genRandomWord ENDP
;-------------------------------------------------------------
initialize string PROC
;
; Initializes the string to be guessed by inserting underscore
; characters
; On entry: esi = address of space to save string
; eax = length of word to guess
;-------------------------------------------------------------
mov ecx, eax ; use length to make a loop
initLoop:
mov BYTE PTR [esi], '_' ; save an underscore
inc esi ; advance position in string
mov BYTE PTR [esi], ' ' ; save a space
inc esi ; advance position in string
loop initLoop
mov BYTE PTR [esi], 0 ; save an end of string
ret
initialize string ENDP
;-------------------------------------------------------------
updateGuess PROC
;
; Updates the guessed char in the current word
; On entry: esi = pointer to current word
; edi = pointer to selected random word
; al = guessed character to test
; On return: eax = number of times the char was found in the string
;-------------------------------------------------------------
push ebx ; save ebx on stack
mov cl, al ; mov character to search to cl
mov ebx, 0 ; initialize correct character count to zero
updLoop:
mov dl, [esi] ; load character from current word
cmp dl, 0 ; see if we reached the end of the word
je updDone
cmp dl, '_' ; see if char is available
jne skip ; if not, skip
cmp cl, [edi] ; compare char input with char in random word
jne skip ; if not equal, skip to next one
inc ebx ; else, increment number of found chars
mov [esi], cl ; reveal char in current guess word
skip:
add esi, 2 ; skip space and go to next char in current guess
inc edi ; advance to next char in random word
jmp updLoop
updDone:
mov eax, ebx ; return number of correct guesses
pop ebx ; restore ebx
ret
updateGuess ENDP
;-------------------------------------------------------------
checkWin PROC
;
; Check if the user has won the game
; On entry: esi = pointer to current guess word
; On return: eax = 1 if the user won, 0 otherwise
;-------------------------------------------------------------
chkLoop:
mov cl, [esi] ; load character from current word
cmp cl, 0 ; see if we reached the end of the word
je isWin ; if we reached the end, the user won
cmp cl, '_' ; see if char is available
je noWin ; if available, it's still not a win
add esi, 2 ; skip space and go to next char in current guess
jmp chkLoop
noWin:
mov eax, 0 ; return 0 to indicate no win
ret
isWin:
mov eax, 1 ; return 1 to indicate win
ret
checkWin ENDP
;-------------------------------------------------------------
to lower PROC
;
; Convert char to lowercase
; On entry: al = char to convert
; On return: al = char converted to lowercase
;-------------------------------------------------------------
cmp al, 'A' ; see if it's uppercase
jl tlReturn ; if not, return same char
cmp al, 'Z' ; see if it's uppercase
jg tlReturn ; if not, return same char
xor al, 32 ; change case
tlReturn:
ret
tolower ENDP
;-------------------------------------------------------------
strtolower PROC
;
; Convert string to lowercase
; On entry: esi = pointer to string
;-------------------------------------------------------------
stlloop:
mov al, [esi] ; load char from string
cmp al, 0 ; see if char is zero
je endstloop ; if zero, end loop
call tolower ; convert to lowercase
mov [esi], al ; save converted char
inc esi ; advance to next char
jmp stlloop ; repeat loop
endstloop:
ret
strtolower ENDP
END main