C语言模式游戏开发:用数组校验玩家输入字符重复实现问题
C语言模式类游戏输入重复校验方案
需求
开发模式类游戏时需要实现输入字符去重逻辑:玩家1(uno)、玩家2(dos)的所有历史输入字符不允许重复,若输入已使用过的字符,要提示用户重新输入未使用的字符,预期运行效果如下:
Round 1: Player 1 Inputs : -> A Player 2 Inputs : -> B Valid Round 2: Player 1 Inputs : -> L Player 2 Inputs : -> V Valid Round 3: Player 1 Inputs : -> A (Invalid Already been used) enter char again
现有基础代码
#include <stdio.h> #include <string.h> #define SWITCH(_g0,_g1) \ (_g0 << 8) | (_g1 << 0) #define CASE(_g0,_g1) \ case SWITCH(_g0,_g1) int getval(const char *prompt) { char *cp; char buf[100]; int val; while (1) { printf("%s: ",prompt); fflush(stdout); cp = fgets(buf,sizeof(buf),stdin); // handle end of file if (cp == NULL) { val = -1; break; } // get the first char on the line val = buf[0]; if (val != '\n') break; } return val; } int main () { int i = 0; int roundCount = 1; int pos = 0; int over = 0; int f = 1; char G[9]; char uno,dos; printf("Game Start!\n"); do { printf("Round %d!\n", roundCount++); printf("Input selection upon prompt.\n"); printf("Player 1: "); scanf(" %c", &uno ); printf("Player 2: "); scanf(" %c", &dos); //printf("DEBUG: %2.2X %2.2X\n",G[0],G[1]); switch (SWITCH(uno,dos)) { CASE('L','V'): CASE('V','S'): CASE('S','P'): CASE('P','R'): CASE('R','L'): CASE('R','S'): CASE('P','V'): CASE('S','L'): CASE('V','R'): CASE('L','P'): f++; pos--; printf("Uno Wins! Pos[%d]\n\n", pos); break; CASE('R','P'): CASE('L','R'): CASE('R','V'): CASE('P','S'): CASE('P','L'): CASE('S','R'): CASE('S','V'): CASE('L','S'): CASE('V','P'): CASE('V','L'): f++; pos++; printf("Dos Wins Pos[%d]!\n\n", pos); break; CASE('R','R'): CASE('P','P'): CASE('S','S'): CASE('L','L'): CASE('V','V'): f++; pos = pos; break; } if (pos == -3 || pos == 3) { printf("Game over\n"); break; } if (f == 5 && pos != -3 && pos != 3) { switch (SWITCH(uno,dos)) { CASE('L','V'): CASE('V','S'): CASE('S','P'): CASE('P','R'): CASE('R','L'): CASE('R','S'): CASE('P','V'): CASE('S','L'): CASE('V','R'): CASE('L','P'): printf("Uno:Wins!\n"); break; CASE('R','P'): CASE('L','R'): CASE('R','V'): CASE('P','S'): CASE('P','L'): CASE('S','R'): CASE('S','V'): CASE('L','S'): CASE('V','P'): CASE('V','L'): printf("Dos Win!\n"); break; } } } while (f < 5); return 0; }
(注:已修复原有代码中函数名定义错误、括号不匹配的基础语法问题)
原有尝试的问题
你之前写的单次for循环校验逻辑存在两个核心问题:
- 仅遍历校验一次,如果用户第二次输入的字符仍然重复,不会触发二次校验,会直接放行
- 未绑定已使用字符的实际数量,遍历整个数组长度会读到未初始化的无效元素,导致逻辑错误
修改后完整实现代码
#include <stdio.h> #include <string.h> #define SWITCH(_g0,_g1) \ (_g0 << 8) | (_g1 << 0) #define CASE(_g0,_g1) \ case SWITCH(_g0,_g1) // 校验字符是否已被使用 int is_used(char c, char *used_arr, int used_len) { for(int i=0; i<used_len; i++) { if(used_arr[i] == c) return 1; } return 0; } int getval(const char *prompt) { char *cp; char buf[100]; int val; while (1) { printf("%s: ",prompt); fflush(stdout); cp = fgets(buf,sizeof(buf),stdin); // handle end of file if (cp == NULL) { val = -1; break; } // get the first char on the line val = buf[0]; if (val != '\n') break; } return val; } int main () { int i = 0; int roundCount = 1; int pos = 0; int over = 0; int f = 1; char G[9]; char uno,dos; // 新增:存储已使用的字符,最多5轮共10个字符,预留足够空间 char used_chars[20]; int used_cnt = 0; printf("Game Start!\n"); do { printf("Round %d!\n", roundCount++); printf("Input selection upon prompt.\n"); // 玩家1输入加重复校验 while(1) { printf("Player 1: "); scanf(" %c", &uno); if(is_used(uno, used_chars, used_cnt)) { printf("(Invalid Already been used)\nenter char again\n"); } else { break; } } used_chars[used_cnt++] = uno; // 玩家2输入加重复校验 while(1) { printf("Player 2: "); scanf(" %c", &dos); if(is_used(dos, used_chars, used_cnt)) { printf("(Invalid Already been used)\nenter char again\n"); } else { break; } } used_chars[used_cnt++] = dos; printf("Valid\n\n"); //printf("DEBUG: %2.2X %2.2X\n",G[0],G[1]); switch (SWITCH(uno,dos)) { CASE('L','V'): CASE('V','S'): CASE('S','P'): CASE('P','R'): CASE('R','L'): CASE('R','S'): CASE('P','V'): CASE('S','L'): CASE('V','R'): CASE('L','P'): f++; pos--; printf("Uno Wins! Pos[%d]\n\n", pos); break; CASE('R','P'): CASE('L','R'): CASE('R','V'): CASE('P','S'): CASE('P','L'): CASE('S','R'): CASE('S','V'): CASE('L','S'): CASE('V','P'): CASE('V','L'): f++; pos++; printf("Dos Wins Pos[%d]!\n\n", pos); break; CASE('R','R'): CASE('P','P'): CASE('S','S'): CASE('L','L'): CASE('V','V'): f++; pos = pos; break; } if (pos == -3 || pos == 3) { printf("Game over\n"); break; } if (f == 5 && pos != -3 && pos != 3) { switch (SWITCH(uno,dos)) { CASE('L','V'): CASE('V','S'): CASE('S','P'): CASE('P','R'): CASE('R','L'): CASE('R','S'): CASE('P','V'): CASE('S','L'): CASE('V','R'): CASE('L','P'): printf("Uno:Wins!\n"); break; CASE('R','P'): CASE('L','R'): CASE('R','V'): CASE('P','S'): CASE('P','L'): CASE('S','R'): CASE('S','V'): CASE('L','S'): CASE('V','P'): CASE('V','L'): printf("Dos Win!\n"); break; } } } while (f < 5); return 0; }
逻辑说明
- 新增
used_chars数组存储两个玩家所有历史输入的字符,used_cnt记录已存储的字符数量 - 输入阶段用死循环做校验,只有输入未使用的字符才会跳出循环,存入数组后进入后续逻辑
- 单独封装
is_used校验函数,代码可复用性更高
内容的提问来源于stack exchange,提问作者Johnny Abella
相关产品推荐
相关产品推荐

