在平局的情况下,抖音游戏不会终止



我正在用汇编语言制作一个井字游戏。在平局的情况下,它不会终止。我该如何纠正
下面是代码:

data segment       
new_line db 13, 10, "$"

game_draw db "_|_|_", 13, 10
db "_|_|_", 13, 10
db "_|_|_", 13, 10, "$"    

game_pointer db 9 DUP(?)  

win_flag db 0 
player db "0$" 

game_over_message db "Game ended", 13, 10, "$"    
game_start_message db "Welcome", 13, 10, "$"
player_message db "PLAYER $"   
win_message db " WIN!$"   
type_message db "TYPE A POSITION: $"  
tra db 'want to play again? (y/n):$'
drw db "the game is draw! $"



ends
stack segment
dw   128  dup(?)
ends         
extra segment

ends

code segment

start:
; set segment registers
mov     ax, data
mov     ds, ax
mov     ax, extra
mov     es, ax
; game start   
call    set_game_pointer    

main_loop:  
call    clear_screen   

lea     dx, game_start_message 
call    print

lea     dx, new_line
call    print                      

lea     dx, player_message
call    print
lea     dx, player
call    print  

lea     dx, new_line
call    print    

lea     dx, game_draw
call    print    

lea     dx, new_line
call    print    

lea     dx, type_message    
call    print            

; read draw position                   
call    read_keyboard

; calculate draw position                   
sub     al, 49               
mov     bh, 0
mov     bl, al 
call update_draw





call    check  

; check if game ends                   
cmp     win_flag, 1 
je     game_over ;STEPH CHANGES  

call    change_player 

jmp      main_loop 

change_player:   
lea     si, player    
xor     ds:[si], 1 

ret
update_draw:
mov     bl, game_pointer[bx]
mov     bh, 0

lea     si, player

cmp     ds:[si], "0"
je      draw_x 


cmp     ds:[si], "1"
je      draw_o              

draw_x:
mov     cl, "x"
jmp     update 

draw_o:          
mov     cl, "o"  
jmp     update    



update:         
mov     ds:[bx], cl 







ret     



check:
call    check_line
ret     


check_line:
mov     cx, 0

check_line_loop:     
cmp     cx, 0
je      first_line

cmp     cx, 1
je      second_line

cmp     cx, 2
je      third_line  

call    check_column
ret    

first_line:    
mov     si, 0   
jmp     do_check_line   
second_line:    
mov     si, 3
jmp     do_check_line

third_line:    
mov     si, 6
jmp     do_check_line        
do_check_line:
inc     cx

mov     bh, 0
mov     bl, game_pointer[si]
mov     al, ds:[bx]
cmp     al, "_"
je      check_line_loop

inc     si
mov     bl, game_pointer[si]    
cmp     al, ds:[bx]
jne     check_line_loop 

inc     si
mov     bl, game_pointer[si]  
cmp     al, ds:[bx]
jne     check_line_loop


mov     win_flag, 1
ret         



check_column:
mov     cx, 0

check_column_loop:     
cmp     cx, 0
je      first_column

cmp     cx, 1
je      second_column

cmp     cx, 2
je      third_column  

call    check_diagonal
ret    

first_column:    
mov     si, 0   
jmp     do_check_column   
second_column:    
mov     si, 1
jmp     do_check_column

third_column:    
mov     si, 2
jmp     do_check_column        
do_check_column:
inc     cx

mov     bh, 0
mov     bl, game_pointer[si]
mov     al, ds:[bx]
cmp     al, "_"
je      check_column_loop

add     si, 3
mov     bl, game_pointer[si]    
cmp     al, ds:[bx]
jne     check_column_loop 

add     si, 3
mov     bl, game_pointer[si]  
cmp     al, ds:[bx]
jne     check_column_loop


mov     win_flag, 1
ret        

check_diagonal:
mov     cx, 0

check_diagonal_loop:     
cmp     cx, 0
je      first_diagonal

cmp     cx, 1
je      second_diagonal                         

ret    

first_diagonal:    
mov     si, 0                
mov     dx, 4 ;jump size
jmp     do_check_diagonal   
second_diagonal:    
mov     si, 2
mov     dx, 2
jmp     do_check_diagonal       
do_check_diagonal:
inc     cx

mov     bh, 0
mov     bl, game_pointer[si]
mov     al, ds:[bx]
cmp     al, "_"
je      check_diagonal_loop

add     si, dx
mov     bl, game_pointer[si]    
cmp     al, ds:[bx]
jne     check_diagonal_loop 

add     si, dx
mov     bl, game_pointer[si]  
cmp     al, ds:[bx]
jne     check_diagonal_loop


mov     win_flag, 1
ret  

game_over:        
call    clear_screen   

lea     dx, game_start_message 
call    print

lea     dx, new_line
call    print                          

lea     dx, game_draw
call    print    

lea     dx, new_line
call    print
lea     dx, game_over_message
call    print  

lea     dx, player_message
call    print

lea     dx, player
call    print

lea     dx, win_message
call    print 
jmp     fim


set_game_pointer:
lea     si, game_draw
lea     bx, game_pointer          

mov     cx, 9   

loop_1:
cmp     cx, 6
je      add_1                

cmp     cx, 3
je      add_1

jmp     add_2 

add_1:
add     si, 1
jmp     add_2     

add_2:                                
mov     ds:[bx], si 
add     si, 2

inc     bx               
loop    loop_1 

ret  


print:      ; print dx content  
mov     ah, 9
int     21h   

ret 

clear_screen:       ; get and set video mode
mov     ah, 0fh
int     10h   

mov     ah, 0
int     10h

ret


read_keyboard:  ; read keybord and return content in ah
mov     ah, 1       
int     21h 
ret 




ret 


fim:
jmp     fim         

code ends
end start

更正初始化

game_pointer数组由字节组成,但set_game_pointer。此错误不会损害程序,因为对game_draw字符串的所有引用的高字节恰好为零,并且内存中指针列表后面的win_flag无论如何都从零开始
首选的解决方案是将指针列表定义为单词,并在汇编时填充该列表,因为它的初始化不需要运行时代码。

game_pointer    dw game_draw,      game_draw + 2,  game_draw + 4
dw game_draw + 7,  game_draw + 9,  game_draw + 11
dw game_draw + 14, game_draw + 16, game_draw + 18
win_flag        db 0
OccupiedSquares db 0
player          db "0$" 

改进用户输入

您忽略了验证用户输入!您假设它将始终是"0"中的一个数字;1〃;至";9〃;。更糟糕的是,你甚至没有检查游戏场上指示的方块是否仍然是空的,因此可以进行修改
在下一个代码中,我建议了一个解决方案:

; Read, calculate, and update draw position                   
update_draw:
ReDo:
call    read_keyboard      ; -> AL
sub     al, '1'
cmp     al, 8
ja      ReDo               ; Invalid key
mov     bh, 0
mov     bl, al
shl     bx, 1              ; Double because the pointer list contains WORDS
mov     bx, game_pointer[bx]
cmp     byte ptr [bx], '_'
jne     ReDo               ; Square is not empty
mov     al, 'x'
cmp     player, '0'
je      update 
mov     al, 'o'            ; If it's not player 0, then it's surely player 1
update:         
mov     [bx], al 
inc     OccupiedSquares    ; See next paragraph
ret     

结束游戏

你说";它在"平局"的情况下不终止;。好吧,比这更糟糕!只有当检测到"获胜"时,程序才会结束。当游戏场地没有空位时,你希望玩家做什么?这是需要检查的条件
您可以通过查看组成网格的9个字节来找到,但更容易的是保持程序接收到的有效密钥的计数,如果该计数等于9,您就知道所有的正方形都被占用了。

call    update_draw
call    check  
cmp     win_flag, 1 
je      game_over  
cmp     OccupiedSquares, 9
je      game_over
xor     player, 1        ; change_player 
jmp     main_loop

game_over代码最终将开始执行一个无休止的循环。为什么会这样?终止程序的正常方法是调用专用于此目的的DOS函数:

fim:
mov     ax, 4C00h    ; DOS.Terminate
int     21h

减少程序占用空间

checkcheck_linecheck_column代码过于复杂。你重复了太多相同的代码
您在check_diagonal例程中编写的算法也非常适合验证其他算法
当检测到"获胜"时,此处的困难部分将是pop ax指令。此pop将当前call的返回地址删除到do_check子例程。这反过来意味着接下来的ret将返回到整个检查例程的父级,这正是您检查win_flag以决定"游戏结束"的地方。

check:
; 3 rows
mov     dx, 2      ; jump size
mov     si, 0   
call    do_check
mov     si, 6
call    do_check
mov     si, 12
call    do_check
; 3 columns
mov     dx, 6
mov     si, 0   
call    do_check
mov     si, 2
call    do_check
mov     si, 4
call    do_check
; 2 diagonals
mov     dx, 8
mov     si, 0   
call    do_check
mov     dx, 4
mov     si, 4
call    do_check                ; Must remain a tail-call!
ret
do_check:
mov     bx, game_pointer[si]
mov     al, [bx]
cmp     al, "_"
je      cont                    ; Empty square
add     si, dx
mov     bx, game_pointer[si]    
cmp     al, [bx]
jne     cont                    ; Not identical letter
add     si, dx
mov     bx, game_pointer[si]  
cmp     al, [bx]
jne     cont                    ; Not identical letter
mov     win_flag, 1
pop     ax                      ; Forget `call do_check`
cont:
ret

我在下面添加了一行;设置段寄存器

mov     bp,9

之后;检查游戏是否结束我添加了下面的代码来计算平局位置

;Calculate draw position
sub bp,1 
cmp bp,0
je game_drawn

下面的game_over:我添加了game_drawn来打印游戏抽奖消息

game_drawn:        
call    clear_screen   
lea     dx, game_start_message 
call    print
lea     dx, new_line
call    print                          
lea     dx, game_draw
call    print    
lea     dx, new_line
call    print
lea     dx, game_draw_message
call    print  
lea     dx, player_message
call    print
jmp     fim

最新更新