Chomp游戏C语言实现求助:棋盘更新异常与坐标反转困惑
Chomp游戏实现问题排查与改进建议
问题背景与需求
这是一项学校作业,要求实现Chomp游戏,需满足以下要求:
- 程序必须包含指定函数,禁止使用指针和结构体,可使用已声明全局变量(
m和n除外,可新增全局变量与函数):initialize():将矩阵所有位置初始化为'O',无参数与返回值。print_board():打印矩阵,无参数与返回值。get_move():获取玩家输入的行和列,通过数组返回,参数为玩家编号(Player 1或Player 2)和存储坐标的数组,无返回值。check_move():验证移动是否合法(未超出矩阵范围且未被吃掉),参数为待验证的移动坐标(行和列),返回验证结果。update_board():更新矩阵,参数为新的移动坐标,无返回值。
当前遇到的问题:
- 输入坐标后棋盘更新结果不符合预期。
- 需要实现输入坐标的垂直反转(终端输入的行号与显示的棋盘行号对应)。
- 欢迎提供代码改进建议。
预期输出示例
Welcome to Chomp! +----------+ |OOOOOOOOOO| |OOOOOOOOOO| |OOOOOOOOOO| |XOOOOOOOOO| +----------+ Player 1: Your move, please! (row,col): 3,7 +----------+ |OOOOOO | |OOOOOO | |OOOOOO | |XOOOOOOOOO| +----------+ Player 2: Your move, please! (row,col): 3,1 <= Bad move! +----------+ | | | | | | |XOOOOOOOOO| +----------+ Player 1: Your move, please! (row,col): 4,2 <= Good move! +----------+ | | | | | | |X | +----------+ Player 2: Your move, please! (row,col): 4,2 Already taken! Player 2: Your move, please! (row,col): 4,11 Illegal position! Player 2: Your move, please! (row,col): 4,1 Game over, player 2 has been poisoned!
现有代码
#include <stdio.h> #include <string.h> // Global variables int height = 4; int width = 10; int player = 2; int move[2] = {0}; char board[4][10]; int m; int n; void Initialize(); void PrintBoard(); void GetMove(int player, int move[2]); int CheckMove(int move[2]); void UpdateBoard(int move[2]); int main(void) { Initialize(); while(1) { PrintBoard(); player = (player == 2)? 1 : 2; while(1) { GetMove(player, move); int c = CheckMove(move); if (c == 0) { UpdateBoard(move); break; } else if (c == 1) { printf("\nAlready taken. Please try again! (row col): "); continue; } else if (c == 2) { printf("\nYou lost!\n"); return 0; } else if (c == 3) { printf("\nIllegal move. Try again! (row col): "); continue; } } } } void Initialize() { memset(board, 'O' , sizeof(char) * height * width); board[3][0] = 'X'; } void PrintBoard() { printf("\n+----------+\n"); for (int i = 0; i < 4; i++) { for(int j = 0; j <= 11; j++) { if (j == 0 || j == 11) { printf("|"); } else { printf("%c", board[i][j-1]); } } printf("\n"); } printf("+----------+\n"); } void GetMove(int player, int move[2]) { printf("\nPlayer %d: your move! (row col): ", player); for (int i = 0; i < 2; i++) scanf(" %d", &move[i]); } int CheckMove(int move[2]) { int check = 99; if ((move[0] >= 1 && move[0] < 5) && (move[1] >= 1 && move[1] <= 10)) { printf("move = %d %d\n", move[0], move[1]); int m = move[0] - 1; int n = move[1] - 1; printf("move = %d %d\n", m, n); // move[0] -= 1; // move[1] -= 1; // more checks if (board[m][n] == 'Z') { check = 1; } else if(board[m][n] == 'X') { check = 2; } else { check = 0; } } else { check = 3; } return check; } void UpdateBoard(int move[2]) { // int y = move[0]; // int x = move[1]; for (int i = m; i >= 0; i--) { for (int j = n; j < width; j++) { board[i][j] = 'Z'; } } }
问题分析与修复
1. 棋盘更新异常的核心原因
UpdateBoard函数依赖全局变量m和n,但这两个变量仅在CheckMove中被声明为局部变量,未赋值给全局变量,导致更新逻辑使用未初始化的垃圾值,完全错误。
修复方案:
- 在
CheckMove中,将转换后的索引赋值给全局m和n,替换局部变量声明:
int CheckMove(int move[2]) { int check = 99; if ((move[0] >= 1 && move[0] <= height) && (move[1] >= 1 && move[1] <= width)) { m = move[0] - 1; n = move[1] - 1; if (board[m][n] == 'Z') { check = 1; } else if(board[m][n] == 'X') { check = 2; } else { check = 0; } } else { check = 3; } return check; }
- 调整
UpdateBoard循环逻辑:Chomp规则是吃掉选中位置右下方所有格子(含自身),循环应从选中行到最后一行,列从选中列到最后一列:
void UpdateBoard(int move[2]) { for (int i = m; i < height; i++) { for (int j = n; j < width; j++) { board[i][j] = 'Z'; } } }
2. 输入坐标垂直反转实现
当前输入行号1对应数组索引0(最上方),但初始X在数组索引3(最下方),对应输入行4。要让输入行号与显示行号一致,需反转行号转换逻辑:
修改CheckMove中的行转换:
// 输入行号转数组索引:height - 输入行号 m = height - move[0]; n = move[1] - 1;
调整PrintBoard遍历顺序,从数组最后一行开始打印(对应显示的第一行):
void PrintBoard() { printf("\n+----------+\n"); for (int i = height - 1; i >= 0; i--) { printf("|"); for(int j = 0; j < width; j++) { printf("%c", board[i][j] == 'Z'? ' ' : board[i][j]); } printf("|\n"); } printf("+----------+\n"); }
3. 其他逻辑修复
- 移除
CheckMove中的调试打印语句,保持输出整洁。 - 边界判断使用全局变量
height和width,避免硬编码数字。 PrintBoard简化打印逻辑,直接输出边框+棋盘内容,去除冗余判断。
额外代码改进建议
- 减少全局变量依赖:将
move数组改为main中的局部变量,传递给相关函数。 - 添加初始化提示:在
main开头打印"Welcome to Chomp!",匹配示例输出。 - 优化输入兼容性:支持逗号分隔的坐标输入,修改
scanf为scanf("%d,%d", &move[0], &move[1]),同时兼容空格分隔。 - 统一函数命名:作业要求函数名为小写(如
initialize()),将当前大驼峰命名改为小写,符合要求。 - 完善输出提示:将"Illegal move"改为"Illegal position!","You lost!"改为"Game over, player X has been poisoned!",匹配示例输出。
内容的提问来源于stack exchange,提问作者Dimitri Mikhalev
相关产品推荐
相关产品推荐

