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
相关产品推荐
相关产品推荐

