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

Yahtzee游戏代码异常:未选骰子提示无效,首轮重复执行

Yahtzee游戏C代码问题修复

核心问题分析

1. 输入缓冲区残留换行符

用scanf("%s")读取玩家姓名时,仅会读取空格/换行前的内容,输入结束时的换行符会留在标准输入缓冲区中。玩家1第一次调用selectDice里的fgets时,会直接读取这个空换行符,导致输入为空,触发无效判定。

代码中使用的fflush(stdin)是C标准未定义行为,并非所有编译器都能正确清空输入缓冲区,因此这个操作不可靠。

2. isValid函数逻辑缺陷

  • 仅检查第一个分割后的token就直接break,忽略后续输入的有效性
  • 输入为空时,strtok返回NULL,函数直接返回初始值FALSE,判定为空输入无效
  • 若第一个token有效但后续存在无效token,函数仍会返回TRUE,存在逻辑漏洞

3. 首轮重复执行的假象

玩家1第一次selectDice拿到空输入后返回0,rollDice里的roll变量不会递增,导致重复执行Roll 1逻辑,看起来像首轮执行了两次。

修复方案

1. 正确清空输入缓冲区

替换不可靠的fflush(stdin),用循环读取缓冲区残留内容:

// 读取玩家1姓名后清空缓冲区
scanf("%s", playerOne);
while(getchar() != '\n'); 

// 读取玩家2姓名后同理
scanf("%s", playerTwo);
while(getchar() != '\n');

2. 修复isValid函数逻辑

遍历所有输入token,只要有一个无效就返回FALSE,同时处理空输入:

int isValid(char data[NAME]){
  char * value;
  int valid = TRUE;

  // 处理空输入
  if(data[0] == '\0'){
    return FALSE;
  }

  value = strtok(data, " ");
  
  while (value != NULL){
    int number = atoi(value);
    if (!(number >= 1 && number <= 5)){
      valid = FALSE;
      break;
    }
    value = strtok(NULL, " ");
  }
  return valid;
}

3. 允许空输入(全不保留骰子)

玩家直接按回车时,视为不保留任何骰子的有效操作:

int selectDice(int dice[DICE], int keep[DICE]){
  char input[NAME];
  char data[NAME];
  char * value;
  int valid = 0;

  printf("Enter the dice you would like to keep, enter values 1 through 5 with spaces between numbers: \n");
  
  fgets(input, NAME, stdin);
  trimTrailing(input);
  strcpy(data, input);

  // 空输入视为全不保留
  if(data[0] == '\0'){
    initDice(keep);
    printf("\n");
    return TRUE;
  }

  valid = isValid(data);
  
  printf("\n");
  
  if (valid == 0){
    return 0;
  }

  initDice(keep);
  value = strtok(input, " ");
  
  while (value != NULL){
    int number = atoi(value);
    if (number >= 1 && number <= 5){
      keep[number - 1] = 1;
      valid = TRUE;
    }
    value = strtok(NULL, " ");
  }
  return valid;
}

4. 修正函数声明

匹配函数声明与定义的参数列表:

// Function Prototypes
void welcomeScreen();
void playGame();
void displayEmptyCard();
void displayRoll(int dice[DICE]);
int rollDie();
void initDice(int dice[DICE]);
void rollDice(int dice[DICE], int keep[DICE]);
int selectDice(int dice[DICE], int keep[DICE]);
int isValid(char data[NAME]);
void trimTrailing(char * str);

测试验证

修复后:

  • 玩家1输入姓名后,输入缓冲区换行符被正确清空,fgets会等待玩家输入
  • 直接回车的空输入会被视为有效操作,进入下一次掷骰
  • 所有输入数字都会被校验,存在无效值时提示重新输入
  • 玩家1与玩家2的流程一致,不会出现首轮重复执行的问题

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.21 12:54:56