Assembly 8086井字棋获胜检测子程序仅检测第一行问题求助
终极井字棋3×3棋盘获胜检测问题排查
我正在开发终极井字棋(ultimate tic tac toe)游戏,已完成大部分功能:实现数组映射、单棋盘获胜检测并将结果映射至3×3数组等。但3×3棋盘的获胜检测子程序CHECK_WINNER仅能检测第一行。我在单井字棋测试文件中该功能运行正常,怀疑问题可能隐藏在其他子程序中。
相关汇编代码如下:
CHECK_WINNER PROC XOR BX, BX XOR CX, CX XOR DX, DX XOR DI, DI LEA DI, BIG_BOARD VERIFICA_VENCEDOR_LINHA1: CMP CX, 3 JE VERIFICA_VENCEDOR_COLUNA1 MOV AL, [DI] CMP AL, JOGADOR_CURR JNE PROXIMA_LINHA1 INC DI MOV AL, [DI] CMP AL, JOGADOR_CURR JNE PROXIMA_LINHA1 INC DI MOV AL, [DI] CMP AL, JOGADOR_CURR JNE PROXIMA_LINHA1 INC DI JMP GANHOU_BOARD1 PROXIMA_LINHA1: MOV DI, DX ADD BX, 3 ADD DI, BX INC CX JMP VERIFICA_VENCEDOR_LINHA1 VERIFICA_VENCEDOR_COLUNA1: XOR BX, BX XOR CX, CX MOV DI, DX COLUNA_LOOP1: CMP CX, 3 JE VERIFICA_VENCEDOR_DIAGONAL1 MOV AL, [DI] CMP AL, JOGADOR_CURR JNE PROXIMA_COLUNA1 ADD DI, 3 MOV AL, [DI] CMP AL, JOGADOR_CURR JNE PROXIMA_COLUNA1 ADD DI, 3 MOV AL, [DI] CMP AL, JOGADOR_CURR JNE PROXIMA_COLUNA1 ADD DI, 3 JMP GANHOU_BOARD1 PROXIMA_COLUNA1: MOV DI, DX INC BX ADD DI, BX INC CX JMP COLUNA_LOOP1 VERIFICA_VENCEDOR_DIAGONAL1: XOR BX, BX XOR CX, CX MOV CX, 3 MOV DI, DX MOV AL, [DI] CMP AL, JOGADOR_CURR JNE DIAG21 ADD DI, 4 MOV AL, [DI] CMP AL, JOGADOR_CURR JNE NAO_GANHOU1 ADD DI, 4 MOV AL, [DI] CMP AL, JOGADOR_CURR JNE DIAG21 JMP GANHOU_BOARD1 DIAG21: MOV DI, DX ADD DI, 2 MOV AL, [DI] CMP AL, JOGADOR_CURR JNE NAO_GANHOU1 ADD DI, 2 MOV AL, [DI] CMP AL, JOGADOR_CURR JNE NAO_GANHOU1 ADD DI, 2 MOV AL, [DI] CMP AL, JOGADOR_CURR JNE NAO_GANHOU1 JMP GANHOU_BOARD1 NAO_GANHOU1: RET GANHOU_BOARD1: CALL EXIT CHECK_WINNER ENDP
问题根源
代码初始化阶段的DX寄存器被清零,却在后续切换行/列时用来重置DI的地址:
- 初始化时
LEA DI, BIG_BOARD正确指向了棋盘数组的起始地址,但XOR DX, DX将DX设为0,没有把棋盘起始地址存入DX。 - 当第一行检测失败进入
PROXIMA_LINHA1时,MOV DI, DX会把DI重置为0(而不是棋盘的起始地址),后续ADD DI, BX计算出的偏移完全错误,导致无法正确检测第二、第三行。
修复方案
- 修正寄存器初始化:在
LEA DI, BIG_BOARD后,将DI的值存入DX,让DX保存棋盘的起始地址:
CHECK_WINNER PROC XOR BX, BX XOR CX, CX XOR DX, DX XOR DI, DI LEA DI, BIG_BOARD MOV DX, DI ; 保存棋盘起始地址到DX,后续用来重置DI VERIFICA_VENCEDOR_LINHA1: ; 后续代码保持不变
- 调整获胜后的处理逻辑:
GANHOU_BOARD1中的CALL EXIT会直接终止程序,不符合终极井字棋的流程(应该返回获胜状态给调用者,继续游戏逻辑),建议改为设置获胜标志后RET,例如:
GANHOU_BOARD1: MOV AX, 1 ; 用AX返回获胜标志(1表示当前玩家获胜) RET
- 验证对角线步长:右上到左下的对角线步长
ADD DI,2是正确的(对应索引2→4→6),但如果棋盘数组的内存布局不是连续的0-8索引,需要重新确认步长是否匹配。
内容的提问来源于stack exchange,提问作者Tomás Ramos
相关产品推荐
相关产品推荐

