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

C语言交通游戏:通用链表与结构体实现撤销功能的问题

游戏撤销功能异常的问题分析与修复

核心问题点

  1. 状态记录逻辑混乱

    • moveCar和movePlayer函数一开始就插入状态,无论操作是否有效(比如玩家输入无效方向、车辆无法移动时),都会向链表中添加无效状态,导致撤销时回退到错误的节点。
    • 游戏循环中每次先执行moveCar再处理输入,导致车辆移动和玩家操作的状态被分开记录,撤销时无法同步回退一组完整的操作。
  2. 撤销时未同步更新地图
    undoMove仅修改了全局变量(playerRow、carRow等),但没有更新map数组中对应的玩家和车辆位置,导致地图显示与实际状态不符,出现车辆重复、玩家位置未变化的视觉错误。

  3. moveCar中的地图数据污染
    在车辆转向失败的分支中,直接将map[carRow][carCol]赋值为方向字符(如CAR_NORTH),但map数组应存储枚举值(CAR=2)而非字符,这会破坏地图数据结构,导致显示异常。

修复方案

1. 调整状态记录时机与逻辑

  • 仅在有效操作发生前记录当前状态,避免无效操作占用链表节点。
  • 调整游戏循环顺序:先处理玩家输入,再执行车辆移动,将玩家操作+对应车辆移动作为一个完整步骤,只记录一次状态。

修改main函数的循环逻辑:

while (1)
{
    printMap();

    char input = getchar();
    if (input == 'q')
    {
        break;
    }
    else if (input == 'u')
    {
        undoMove();
    }
    else
    {
        // 记录当前状态,再执行玩家移动和车辆移动
        insertStart(playerRow, playerCol, carRow, carCol, carDirection);
        movePlayer(input);
        moveCar();
    }

    if (checkWinCondition())
    {
        printf("You Win!\n");
        break;
    }

    if (checkLoseCondition())
    {
        printf("You Lose!\n");
        break;
    }
}

同时删除movePlayer和moveCar函数开头的insertStart调用。

2. 修复undoMove函数,同步更新地图

在恢复全局变量后,需要更新map数组,确保显示与实际状态一致:

void undoMove()
{
    if (head == NULL)
    {
        return; // Nothing to undo
    }

    // 先清除当前状态在地图中的标记
    map[playerRow][playerCol] = SPACE;
    map[carRow][carCol] = ROAD;

    // 恢复之前的状态
    playerRow = head->playerRow;
    playerCol = head->playerCol;
    carRow = head->carRow;
    carCol = head->carCol;
    carDirection = head->carDirection;

    // 在地图中标记恢复后的状态
    map[playerRow][playerCol] = PLAYER;
    map[carRow][carCol] = CAR;

    // 移除已恢复的状态节点
    removeStart();
}

3. 修复moveCar中的地图赋值错误

删除转向失败分支中直接修改map的代码,仅更新carDirection即可:

else
{
    carDirection = (carDirection + 2) % 4; /* Turn around (180 degrees) if no path is found */
    // 移除原有的switch赋值代码,map中保持CAR枚举值,方向由carDirection控制
}

4. 优化movePlayer的无效输入处理

避免无效输入时干扰流程,仅在输入有效时执行移动:

void movePlayer(char direction)
{
    int newPlayerRow = playerRow;
    int newPlayerCol = playerCol;

    switch (direction)
    {
    case 'w':
        newPlayerRow--;
        break;
    case 's':
        newPlayerRow++;
        break;
    case 'a':
        newPlayerCol--;
        break;
    case 'd':
        newPlayerCol++;
        break;
    case 'q':
        return;
    default:
        printf("Invalid input. Use 'w' to move up, 's' to move down, 'a' to move left, 'd' to move right and 'q' to quit the game.\n");
        sleep(1);
        return;
    }

    if (newPlayerRow >= 0 && newPlayerRow < rows &&
        newPlayerCol >= 0 && newPlayerCol < cols &&
        map[newPlayerRow][newPlayerCol] != CAR &&
        map[newPlayerRow][newPlayerCol] != '*')
    {
        map[playerRow][playerCol] = SPACE;
        playerRow = newPlayerRow;
        playerCol = newPlayerCol;
        map[playerRow][playerCol] = PLAYER;
    }
}

修复后的效果

  • 撤销操作会同步回退玩家和车辆的状态,地图显示与实际状态一致。
  • 仅记录有效操作步骤,避免无效状态占用链表空间。
  • 地图数据结构不再被污染,车辆显示正常。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.08 04:02:02