-
Notifications
You must be signed in to change notification settings - Fork 0
/
hangman.asm
executable file
·557 lines (499 loc) · 10.9 KB
/
hangman.asm
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
; Matthew Moltzau
; Assembly - Test2
Include Irvine32.inc
.code
main PROC
.data
welcome BYTE "----------------------------------------------------------", 0ah, 0dh,
" Welcome to Hangman!", 0ah, 0dh,
" Once we start the game, you have 10 letter guesses total", 0ah, 0dh,
" and 3 word guesses. Each guess, regardless of whether it", 0ah, 0dh,
" is correct or not will decrement from your count.", 0ah, 0dh,
"----------------------------------------------------------", 0ah, 0dh, 0
menu BYTE "[0]: Start Game", 0ah, 0dh,
"[1]: Quit", 0ah, 0dh,
">> ", 0
error BYTE "Only 0 and 1 are valid options.", 0ah, 0dh, 0
letter_guesses BYTE 10
word_guesses BYTE 3
; Did not get to these:
lguess_total DWORD 0
wguess_total DWORD 0
games_won WORD 0
games_lost WORD 0
.code
call Randomize ; seed the random number generator
; Clear Registers
mov eax, 0
mov ebx, 0
mov ecx, 0
mov edx, 0
mov esi, 0
; WELCOME MESSAGE
mov edx, OFFSET welcome
call WriteString
call WaitMsg
call Crlf
MenuLoop:
; DISPLAY MENU
; [0]: Play (this also gets triggered if the user enters nothing)
; [1]: Quit
mov edx, OFFSET menu
call WriteString
call ReadDec ; reads into eax
call Crlf
; CMP MENU OPTIONS
cmp eax, 1
je menu_exit
cmp eax, 0
je cont_menu
mov edx, OFFSET error
call WriteString
jmp MenuLoop
cont_menu:
; SETUP GAME
call GetRndWord ; OFFSET into EDX, length into al
movzx ecx, al ; word length
mov ah, letter_guesses ; letter guesses into ah
mov al, word_guesses ; word guesses into al
call PlayGame
jmp MenuLoop ; loopnz loopz
menu_exit:
exit
main ENDP
;---------------------------------------------
; GetRndWord
; Precondition: Random seed must be set
; Returns: word OFFSET into EDX, LENGTH into al
;---------------------------------------------
GetRndWord PROC
.data
word0 BYTE "kiwi", 0h
word1 BYTE "canoe", 0h
word2 BYTE "doberman", 0h
word3 BYTE "frame", 0h
word4 BYTE "bannana", 0h
word5 BYTE "orange", 0h
word6 BYTE "frigate", 0h
word7 BYTE "ketchup", 0h
word8 BYTE "postal", 0h
word9 BYTE "basket", 0h
word10 BYTE "cabinent", 0h
word11 BYTE "birch", 0h
word12 BYTE "machine", 0h
word13 BYTE "mississipian", 0h
word14 BYTE "destroyer", 0h
word15 BYTE "tank", 0h
word16 BYTE "fruit", 0h
word17 BYTE "nibble", 0h
word18 BYTE "assembly", 0h
word19 BYTE "offensive", 0h
.code
call Random32 ; random large num into EAX
mov ah, 0 ; prevent overflow error
mov bl, 20 ; divisor
div bl ; AX % BL --> AH = Remainder
cmp ah, 0
jne check1
mov edx, OFFSET word0
mov ax, LENGTHOF word0
jmp end_case
check1:
cmp ah, 1
jne check2
mov edx, OFFSET word1
mov ax, LENGTHOF word1
jmp end_case
check2:
cmp ah, 2
jne check3
mov edx, OFFSET word2
mov ax, LENGTHOF word2
jmp end_case
check3:
cmp ah, 3
jne check4
mov edx, OFFSET word3
mov ax, LENGTHOF word3
jmp end_case
check4:
cmp ah, 4
jne check5
mov edx, OFFSET word4
mov ax, LENGTHOF word4
jmp end_case
check5:
cmp ah, 5
jne check6
mov edx, OFFSET word5
mov ax, LENGTHOF word5
jmp end_case
check6:
cmp ah, 6
jne check7
mov edx, OFFSET word6
mov ax, LENGTHOF word6
jmp end_case
check7:
cmp ah, 7
jne check8
mov edx, OFFSET word7
mov ax, LENGTHOF word7
jmp end_case
check8:
cmp ah, 8
jne check9
mov edx, OFFSET word8
mov ax, LENGTHOF word8
jmp end_case
check9:
cmp ah, 9
jne check10
mov edx, OFFSET word9
mov ax, LENGTHOF word9
jmp end_case
check10:
cmp ah, 10
jne check11
mov edx, OFFSET word10
mov ax, LENGTHOF word10
jmp end_case
check11:
cmp ah, 11
jne check12
mov edx, OFFSET word11
mov ax, LENGTHOF word11
jmp end_case
check12:
cmp ah, 12
jne check13
mov edx, OFFSET word12
mov ax, LENGTHOF word12
jmp end_case
check13:
cmp ah, 13
jne check14
mov edx, OFFSET word13
mov ax, LENGTHOF word13
jmp end_case
check14:
cmp ah, 14
jne check15
mov edx, OFFSET word14
mov ax, LENGTHOF word14
jmp end_case
check15:
cmp ah, 15
jne check16
mov edx, OFFSET word15
mov ax, LENGTHOF word15
jmp end_case
check16:
cmp ah, 16
jne check17
mov edx, OFFSET word16
mov ax, LENGTHOF word16
jmp end_case
check17:
cmp ah, 17
jne check18
mov edx, OFFSET word17
mov ax, LENGTHOF word17
jmp end_case
check18:
cmp ah, 18
jne check19
mov edx, OFFSET word18
mov ax, LENGTHOF word18
jmp end_case
check19:
cmp ah, 19
mov edx, OFFSET word19
mov ax, LENGTHOF word19
end_case:
RET
GetRndWord ENDP
;------------------------------------------------------
; Display Word
; Recieves:
; ebx as a mask to show certain characters
; edx word OFFSET
; ecx word length
; Displays:
; Word = _ _ _ _ _
; OR
; Word = _ e _ _ o
;------------------------------------------------------
DisplayWord PROC
.data
disp BYTE "Word =", 0
.code
push ecx
push ebx
push eax
push edx
push edx ; Word =
mov edx, OFFSET disp
call WriteString
pop edx
ror ebx, cl ; rotate all bits off right
dec ecx
PrintLoop:
mov eax, ' '
call WriteChar
rol ebx, 1 ; get next bit
TEST ebx, 1 ; non-destructive AND: is the bit set?
jnz print_char
mov al, '_'
call WriteChar
jmp print_end
print_char:
mov al, BYTE PTR [edx]
call WriteChar
print_end:
inc edx
loop PrintLoop
call Crlf
pop edx
pop eax
pop ebx
pop ecx
RET
DisplayWord ENDP
;------------------------------------------------------------
; Compare Strings
; Recieves:
; ESI as word OFFSET
; EDX as guess OFFSET
; Returns:
; Sets the zero flag if the strings don't match
; Clears the zero flag if the string do match
; So: if 0, match is FALSE; if 1, match is TRUE
;------------------------------------------------------------
CmpStrings PROC
push esi
push edx
push eax
cmp_loop:
movzx eax, BYTE PTR [esi]
cmp al, [edx]
jne word_false ; [esi] != [edx], word mismatch
cmp al, 0 ; null terminator where [esi] == [edx]
je word_true
inc esi
inc edx
jmp cmp_loop
word_false:
AND dl, 0 ; sets the zero flag
jmp cmp_end
word_true:
OR dl, 1 ; clear the zero flag
cmp_end:
pop eax
pop edx
pop esi
RET
CmpStrings ENDP
;----------------------------------------------
; Letter Guess
; Recieves:
; ESI as word OFFSET
; dl as char to scan for
; Returns:
; EBX as mask for dl
; Example:
; edx -> bannana
; dl = a
; ebx is now 0100101
;----------------------------------------------
LetterGuess PROC
push esi
push edx
mov ebx, 0
lguess_loop:
mov dh, BYTE PTR [esi]
cmp dl, dh
jne check_termination
OR ebx, 1 ; just add a bit
check_termination:
cmp dh, 0 ; null termination
je lguess_end
inc esi
shl ebx, 1 ; bannana:a -> 0100101
jmp lguess_loop
lguess_end:
pop edx
pop esi
RET
LetterGuess ENDP
;------------------------------------------
; To Lowercase
; Recieves:
; EDX as string OFFSET
; Returns:
; unchanged offset with a changed string
; that is now lowercase
;------------------------------------------
ToLower PROC
push edx
push eax
lower_loop:
cmp BYTE PTR [edx], 0 ; null termation
je exit_lwr
mov al, BYTE PTR [edx] ; get char
cmp al, 'A' ; if al < 'A'
jb NotUpperCase ; continue to bottom
cmp al, 'Z' ; if al > 'Z'
ja NotUpperCase ; continue to bottom
add al, 20h ; 'A' 41, 'a' 61
mov BYTE PTR [edx], al ; set char
NotUpperCase:
inc edx ; continue to next char
jmp lower_loop
exit_lwr:
pop eax
pop edx
RET
ToLower ENDP
;----------------------------------------
; Play Game
; Recieves:
; EDX as word OFFSET
; ECX as word LENGTH
; AH as letter guesses
; AL as word guesses
; Returns:
; AH remaining letter guesses
; AL remaining word guesses
; TODO set zero flag if game was lostcu
;----------------------------------------
PlayGame PROC
.data
prompt BYTE "Guess either a letter or a word.", 0ah, 0dh, ">> ", 0
lguesses BYTE " letter guesses remaining", 0ah, 0dh, 0
wguesses BYTE " word guesses remaining", 0ah, 0dh, 0
wrongw BYTE "The word you guessed was incorrect.", 0ah, 0dh, 0
win BYTE "You've won the game. Congratulations!", 0ah, 0dh, 0
loss BYTE "You didn't win the game. Better luck next time.", 0ah, 0dh, 0
err1 BYTE "You cannot enter any more letters.", 0ah, 0dh, 0
err2 BYTE "You cannot enter any more words.", 0ah, 0dh, 0
err3 BYTE "You must enter something!", 0ah, 0dh, 0
guess BYTE 32 DUP(0)
b_letters DWORD 0
letter_guesses2 BYTE 0
word_guesses2 BYTE 0
.code
push edx
push ecx
push esi
; DISPLAY THE STRING (for debug)
; call WriteString
; call Crlf
mov letter_guesses2, ah
mov word_guesses2, al
; Setup Letter Flags (ebx and b_letters)
mov ebx, 0
NOT ebx ; FFFFFFFFh
mov b_letters, 0 ; reset var
shld b_letters, ebx, cl ; if cl = 6 then 0000003Fh
sub b_letters, 1
NOT ebx ; want at 0
mov esi, edx ; will need edx for other stuff
PlayLoop:
; WRITE REMAINING GUESSES
movzx eax, letter_guesses2
call WriteDec
mov edx, OFFSET lguesses
call WriteString
movzx eax, word_guesses2
call WriteDec
mov edx, OFFSET wguesses
call WriteString
mov edx, esi
call DisplayWord
; GET USER INPUT
mov edx, OFFSET prompt
call WriteString
mov edx, OFFSET guess
push ecx
mov ecx, LENGTHOF guess
call ReadString ; OFFSET into EDX, len into EAX
call ToLower ; converts string to lowercase
pop ecx
cmp al, 0 ; Did the user actually input anything?
jne test_if_1
mov edx, OFFSET err3
call WriteString
jmp PlayLoop
test_if_1:
cmp al, 1 ; is input a letter or a word?
jne word_input
; WE HAVE A LETTER INPUT
cmp letter_guesses2, 0 ; Do we have any more letter guesses left?
jne remaining_letters
; cannot enter any more letters
mov edx, OFFSET err1
call WriteString
jmp PlayLoop ; continue
remaining_letters:
mov dl, BYTE PTR [edx] ; overwrite self with the input
push ebx ; save ebx
call LetterGuess ; returns EBX
pop edx ; restore into edx
OR ebx, edx ; combine
cmp ebx, b_letters
jne not_win
jmp VICTORY
not_win:
cmp letter_guesses2, 0
je keepzero1
dec letter_guesses2 ; decrement letter guesses
keepzero1:
jmp cont_game
word_input:
; WE HAVE A WORD INPUT
cmp word_guesses2, 0 ; Do we have any more word guesses left?
jne remaining_words
; cannot enter any more words
mov edx, OFFSET err2
call WriteString
jmp PlayLoop ; continue
remaining_words:
call CmpStrings ; compares edx and esi
jz mismatch
jmp VICTORY
mismatch:
cmp word_guesses2, 0
je keepzero2
dec word_guesses2 ; decrement word guesses
keepzero2:
mov edx, OFFSET wrongw
call WriteString
jmp cont_game
victory:
mov ebx, b_letters ; set flags to display word
mov edx, esi
call DisplayWord
mov edx, OFFSET win
call WriteString
jmp exit_game
cont_game:
cmp word_guesses2, 0 ; Do I have 0 word guesses and 0 letter guesses?
jne can_guess
cmp letter_guesses2, 0
je lost_game
can_guess:
jmp PlayLoop
lost_game:
mov edx, OFFSET loss
call WriteString
exit_game:
; prepare output
mov ah, letter_guesses2
mov al, word_guesses2
pop esi
pop ecx
pop edx
RET
PlayGame ENDP
end main