You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Chomp游戏C语言实现求助:棋盘更新异常与坐标反转困惑

Chomp游戏实现问题排查与改进建议

问题背景与需求

这是一项学校作业,要求实现Chomp游戏,需满足以下要求:

  • 程序必须包含指定函数,禁止使用指针和结构体,可使用已声明全局变量(m和n除外,可新增全局变量与函数):
    • initialize():将矩阵所有位置初始化为'O',无参数与返回值。
    • print_board():打印矩阵,无参数与返回值。
    • get_move():获取玩家输入的行和列,通过数组返回,参数为玩家编号(Player 1或Player 2)和存储坐标的数组,无返回值。
    • check_move():验证移动是否合法(未超出矩阵范围且未被吃掉),参数为待验证的移动坐标(行和列),返回验证结果。
    • update_board():更新矩阵,参数为新的移动坐标,无返回值。

当前遇到的问题:

  1. 输入坐标后棋盘更新结果不符合预期。
  2. 需要实现输入坐标的垂直反转(终端输入的行号与显示的棋盘行号对应)。
  3. 欢迎提供代码改进建议。

预期输出示例

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简化打印逻辑,直接输出边框+棋盘内容,去除冗余判断。

额外代码改进建议

  1. 减少全局变量依赖:将move数组改为main中的局部变量,传递给相关函数。
  2. 添加初始化提示:在main开头打印"Welcome to Chomp!",匹配示例输出。
  3. 优化输入兼容性:支持逗号分隔的坐标输入,修改scanf为scanf("%d,%d", &move[0], &move[1]),同时兼容空格分隔。
  4. 统一函数命名:作业要求函数名为小写(如initialize()),将当前大驼峰命名改为小写,符合要求。
  5. 完善输出提示:将"Illegal move"改为"Illegal position!","You lost!"改为"Game over, player X has been poisoned!",匹配示例输出。

内容的提问来源于stack exchange,提问作者Dimitri Mikhalev

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.16 23:50:20