C语言开发黑白棋(Reversi)游戏——撤销功能实现困境
黑白棋落子撤销功能修复方案
核心思路:基于链表的棋盘状态快照管理
撤销功能的核心是每次落子(玩家/AI)后保存完整的棋盘状态快照,通过链表串联所有快照,撤销时回溯到上一个快照即可。以下是具体实现步骤:
1. 定义链表节点结构
每个节点存储当前棋盘状态、落子方、落子位置等关键信息,使用动态内存分配:
#define BOARD_SIZE 8 // 棋盘状态节点 typedef struct BoardState { char board[BOARD_SIZE][BOARD_SIZE]; // 完整棋盘 int player; // 0表示玩家,1表示AI int x, y; // 落子坐标 struct BoardState* prev; // 指向前一个状态的指针 } BoardState; BoardState* currentState = NULL; // 当前状态指针
2. 落子后保存状态快照
每次玩家或AI落子并完成翻转操作后,创建新的节点保存当前棋盘状态:
// 保存当前棋盘状态到链表 void saveBoardState(char board[BOARD_SIZE][BOARD_SIZE], int player, int x, int y) { BoardState* newState = (BoardState*)malloc(sizeof(BoardState)); if (!newState) { printf("内存分配失败!\n"); return; } // 复制棋盘数据 for (int i = 0; i < BOARD_SIZE; i++) { for (int j = 0; j < BOARD_SIZE; j++) { newState->board[i][j] = board[i][j]; } } newState->player = player; newState->x = x; newState->y = y; newState->prev = currentState; // 指向当前状态(上一个节点) currentState = newState; // 更新当前状态为新节点 }
3. 实现撤销操作
撤销时,检查当前状态是否有前序节点,若有则恢复前序节点的棋盘状态,并释放当前节点的内存:
// 撤销落子操作 void undoMove(char board[BOARD_SIZE][BOARD_SIZE]) { if (!currentState || !currentState->prev) { printf("没有可撤销的操作!\n"); return; } BoardState* temp = currentState; // 恢复前序状态的棋盘 currentState = currentState->prev; for (int i = 0; i < BOARD_SIZE; i++) { for (int j = 0; j < BOARD_SIZE; j++) { board[i][j] = currentState->board[i][j]; } } free(temp); // 释放当前节点的动态内存 printf("已撤销上一步操作!\n"); }
4. 关键注意事项
- 完整复制棋盘:必须复制整个棋盘的二维数组,不能只保存落子位置和翻转的棋子(因为AI落子可能涉及多个翻转,回溯时难以逐一还原)。
- 内存管理:每次撤销后必须释放当前节点的内存,避免内存泄漏;程序退出时要遍历链表释放所有节点。
- 初始状态保存:游戏初始化后,需要保存初始棋盘状态作为链表的头节点,确保第一次撤销有可回溯的状态。
5. 调试建议
- 在
saveBoardState函数中添加打印逻辑,输出保存的棋盘状态和节点地址,验证每个落子后是否正确创建了节点。 - 在
undoMove函数中打印恢复后的棋盘,确认是否与上一步状态一致。 - 检查链表指针是否正确赋值,避免出现空指针或野指针导致的崩溃。
内容的提问来源于stack exchange,提问作者please help
相关产品推荐
相关产品推荐

