玩家企鹅移动逻辑Bug修复与游戏结束判定方案咨询
企鹅移动逻辑修复及游戏结束判定方案
问题背景
移动判定规则:目标位置需满足无企鹅、非0号水域tile、未超出棋盘范围,违反则需重新输入方向。当前实现的移动逻辑存在无规律错误移动、误判无法移动的问题,同时缺少所有玩家无企鹅可移动时的游戏结束判定。
现存代码问题分析
1. 企鹅定位函数逻辑错误
getPengPos仅返回玩家的第一只企鹅位置,但循环中按企鹅编号遍历,导致所有编号对应的操作都修改同一只企鹅,这是错误移动的核心原因。
2. 边界判定完全混乱
- 行边界与
board_width对比、列边界与board_height对比,维度完全搞反; - 边界条件错误(如向上移动判断
playerRow-1 > 0,遗漏了第0行的合法位置)。
3. 缺少核心判定条件
未检查目标位置是否有企鹅、是否为0号水域tile,仅判断边界,不符合规则要求。
4. 移动循环逻辑不合理
当前循环强制所有玩家的第N只企鹅必须移动,未考虑企鹅是否可移动,也没有全局检查所有企鹅的可移动状态。
修复方案及代码实现
1. 修复企鹅定位函数
新增penguinIndex参数,按顺序查找玩家的第N只企鹅:
void getPengPos(struct board *gameBoard, int playerIndex, int penguinIndex, int *row, int *column) { int count = 0; for (int i = 0; i < gameBoard->rows; i++) { for (int j = 0; j < gameBoard->columns; j++) { if (gameBoard->penguins[i * gameBoard->columns + j] == 'A' + playerIndex) { if (count == penguinIndex) { *row = i; *column = j; return; } count++; } } } *row = -1; *column = -1; // 未找到对应编号的企鹅 }
2. 新增辅助函数
单只企鹅可移动检查
bool canPenguinMove(struct board *gameBoard, int row, int col) { // 检查四个方向是否符合移动条件 // 向上 if (row - 1 >= 0) { int idx = (row-1)*gameBoard->columns + col; if (gameBoard->penguins[idx] == ' ' && gameBoard->tiles[idx] != 0) { return true; } } // 向下 if (row + 1 < gameBoard->rows) { int idx = (row+1)*gameBoard->columns + col; if (gameBoard->penguins[idx] == ' ' && gameBoard->tiles[idx] != 0) { return true; } } // 向左 if (col - 1 >= 0) { int idx = row*gameBoard->columns + (col-1); if (gameBoard->penguins[idx] == ' ' && gameBoard->tiles[idx] != 0) { return true; } } // 向右 if (col + 1 < gameBoard->columns) { int idx = row*gameBoard->columns + (col+1); if (gameBoard->penguins[idx] == ' ' && gameBoard->tiles[idx] != 0) { return true; } } return false; }
全局可移动状态检查
bool allPenguinsTrapped(struct board *gameBoard, int num_players, int num_pengwings) { for (int i = 0; i < num_players; i++) { for (int x = 0; x < num_pengwings; x++) { int row, col; getPengPos(gameBoard, i, x, &row, &col); if (row != -1 && canPenguinMove(gameBoard, row, col)) { return false; // 存在可移动企鹅,游戏继续 } } } return true; // 所有企鹅无法移动,游戏结束 }
3. 重写移动阶段函数
修正循环逻辑、边界判断,补充核心规则检查,添加游戏结束判定:
void movementPhase(struct board *gameBoard, Player players[], int num_players, int num_pengwings, int board_height, int board_width) { char direction; bool validInput; // 先检查全局状态,若所有企鹅无法移动直接结束 if (allPenguinsTrapped(gameBoard, num_players, num_pengwings)) { printf("所有企鹅都无法移动,游戏结束!\n"); return; } // 玩家轮流操作自己的所有企鹅 for (int i = 0; i < num_players; i++) { for (int x = 0; x < num_pengwings; x++) { int playerRow, playerCol; getPengPos(gameBoard, i, x, &playerRow, &playerCol); // 企鹅不存在或无法移动则跳过 if (playerRow == -1 || !canPenguinMove(gameBoard, playerRow, playerCol)) { printf("玩家%d的第%d只企鹅无法移动,跳过操作。\n", i+1, x+1); continue; } validInput = false; while (!validInput) { printf("玩家%d,输入第%d只企鹅的移动方向(u, d, r, l): ", i+1, x+1); scanf(" %c", &direction); int targetRow = playerRow; int targetCol = playerCol; bool boundaryValid = true; // 计算目标坐标并校验边界 switch(direction) { case 'u': targetRow = playerRow - 1; boundaryValid = (targetRow >= 0); break; case 'd': targetRow = playerRow + 1; boundaryValid = (targetRow < gameBoard->rows); break; case 'r': targetCol = playerCol + 1; boundaryValid = (targetCol < gameBoard->columns); break; case 'l': targetCol = playerCol - 1; boundaryValid = (targetCol >= 0); break; default: printf("无效输入,请输入u、d、r或l。\n"); boundaryValid = false; break; } if (!boundaryValid) { printf("移动方向超出棋盘范围,请重新输入。\n"); continue; } // 校验目标位置的核心规则 int targetIdx = targetRow * gameBoard->columns + targetCol; if (gameBoard->penguins[targetIdx] != ' ') { printf("目标位置已有企鹅,无法移动,请重新输入。\n"); continue; } if (gameBoard->tiles[targetIdx] == 0) { printf("目标位置是水域tile,无法移动,请重新输入。\n"); continue; } // 执行移动 validInput = true; gameBoard->penguins[playerRow * gameBoard->columns + playerCol] = ' '; gameBoard->penguins[targetIdx] = 'A' + i; printBoard(gameBoard); // 移动后再次检查全局状态,若所有企鹅无法移动则提前结束 if (allPenguinsTrapped(gameBoard, num_players, num_pengwings)) { printf("所有企鹅都无法移动,游戏结束!\n"); return; } } } } }
内容的提问来源于stack exchange,提问作者Merrichu
相关产品推荐
相关产品推荐

