MIPS汇编开发井字棋:动态数据存储与数组实现技术问询
刚好我之前做过类似的MIPS汇编项目,给你分享两个适配井字棋需求的实用方案,帮你搞定落子记录的存储问题:
方案一:静态预分配数组(最适合井字棋场景)
井字棋最多只有9次落子,完全可以提前在.data段预留足够的固定空间,用一个计数器跟踪当前已记录的落子数,实现简单又高效。
实现思路
- 定义一个固定大小的数组,每个落子用2字节存储:1字节存玩家标识(比如
X的ASCII码88、O的79),1字节存落子位置(0-8,对应9个格子) - 用一个变量记录已落子的数量,每次追加时直接计算写入位置,更新计数器即可
代码示例
.data move_history: .space 18 # 9步×2字节=18字节,完全够用 move_count: .word 0 # 记录已保存的落子数量 .text # 追加落子的函数:a0=玩家标识(X/O的ASCII),a1=落子位置(0-8) append_move: # 计算当前要写入的数组偏移地址 lw $t0, move_count sll $t0, $t0, 1 # 每个落子占2字节,所以计数器×2得到字节偏移 la $t1, move_history add $t1, $t1, $t0 # 最终写入地址 # 写入玩家标识和位置 sb $a0, 0($t1) # 第一个字节存玩家 sb $a1, 1($t1) # 第二个字节存位置 # 更新落子计数器 lw $t0, move_count addi $t0, $t0, 1 sw $t0, move_count jr $ra
方案二:动态堆分配(适合扩展需求)
如果后续要支持多局游戏、保存更多历史记录,可以用MIPS的sbrk系统调用(调用号9)动态分配堆内存,实现可扩容的数组。
实现思路
- 初始化时分配一块初始大小的堆内存
- 每次追加落子前检查剩余空间,不足则扩容(通常是翻倍当前大小)
- 将旧数据复制到新的内存块,再写入新的落子记录
代码示例
.data move_history: .word 0 # 存储堆数组的起始地址 current_size: .word 8 # 初始分配8字节(4个落子的空间) move_count: .word 0 # 已保存的落子数量 .text # 初始化动态数组 init_history: li $v0, 9 lw $a0, current_size syscall # 分配内存,返回地址存在$v0 sw $v0, move_history jr $ra # 动态追加落子的函数:a0=玩家标识,a1=落子位置 append_move_dynamic: # 检查是否需要扩容 lw $t0, move_count sll $t1, $t0, 1 # 已使用的字节数=落子数×2 lw $t2, current_size bge $t1, $t2, resize_history # 已用空间≥当前大小,触发扩容 # 无需扩容,直接写入数据 lw $t3, move_history add $t3, $t3, $t1 sb $a0, 0($t3) sb $a1, 1($t3) j update_counter # 扩容逻辑 resize_history: # 把当前内存大小翻倍 lw $t2, current_size sll $t2, $t2, 1 sw $t2, current_size # 分配新的内存块 li $v0, 9 move $a0, $t2 syscall move $t4, $v0 # 新内存地址存在$t4 # 复制旧数据到新内存 lw $t3, move_history move $a1, $t3 # 源地址 move $a0, $t4 # 目标地址 move $a2, $t1 # 要复制的字节数 jal memcpy # 更新历史数组的地址 sw $t4, move_history # 写入新的落子记录 add $t4, $t4, $t1 sb $a0, 0($t4) sb $a1, 1($t4) # 更新落子计数器 update_counter: lw $t0, move_count addi $t0, $t0, 1 sw $t0, move_count jr $ra # 内存复制辅助函数:a0=目标地址,a1=源地址,a2=复制字节数 memcpy: beq $a2, $zero, memcpy_done lb $t5, 0($a1) sb $t5, 0($a0) addi $a0, $a0, 1 addi $a1, $a1, 1 addi $a2, $a2, -1 j memcpy memcpy_done: jr $ra
额外小贴士
- 如果你非要用字符串存储,也可以把每个落子格式化为类似
"X0"的字符串片段,然后维护一个带终止符的字符串数组,但这种方式在MIPS里处理起来比直接存二进制数据麻烦很多,不推荐。 - 静态数组方案完全满足井字棋的单局需求,代码更简洁,运行效率也更高,优先选这个就好。
内容的提问来源于stack exchange,提问作者Felcannon




