我的C语言纸牌游戏程序获胜计数错误,是什么原因导致的?
纸牌游戏compareCards判定逻辑异常问题修复
问题描述
我开发了一款对比两名玩家手牌、按指定规则判定每轮胜负的纸牌游戏,胜负判定逻辑封装在compareCards函数中,函数返回true代表玩家1本轮获胜,返回false代表玩家2本轮获胜。我在游戏运行函数的循环内调用该函数,循环次数与每名玩家的发牌数量一致。但目前compareCards函数存在异常,部分轮次无法匹配判定条件,最终游戏结束时两名玩家的获胜计数结果错误,我尝试调整多处条件判断逻辑均未定位到问题。
compareCards函数说明:看似随机的轮次会触发函数末尾的打印语句,说明判定逻辑漏过了所有预设条件分支,对应代码如下:
bool compareCards(char *card1, char *card2) { char card1Face = card1[0]; char card2Face = card2[0]; //if card1 is A/K/Q/J and card2 is num if ((card1Face >= 'A' && card1Face <= 'Z') && !(card2Face >= 'A' && card2Face <= 'Z')) { return true; } //if card1 is num and card2 is A/K/Q/J else if (!(card1Face >= 'A' && card1Face <= 'Z') && (card2Face >= 'A' && card2Face <= 'Z')) { return false; } //if card1 and card2 both A/K/Q/J else if ((card1Face >= 'A' && card1Face <= 'Z') && (card2Face >= 'A' && card2Face <= 'Z')) { //test for A if (card1Face == 'A' && card2Face != 'A') { return true; } else if (card1Face != 'A' && card2Face == 'A') { return false; } //test for K if (card1Face == 'K' && card2Face != 'K') { return true; } else if (card1Face != 'K' && card2Face == 'K') { return false; } //test for Q if (card1Face == 'Q' && card2Face != 'Q') { return true; } else if (card1Face != 'Q' && card2Face == 'Q') { return false; } //test for J if (card1Face == 'J' && card2Face != 'J') { return true; } else if (card1Face != 'J' && card2Face == 'J') { return false; } } //end cards are face cards //If card1 and card2 are nums else if ((card1Face >= '1' && card1Face <= '9') && (card2Face >= '1' && card2Face <= '9')) { //if card1 is 10 and card2 is not if (card1Face == '1' && card2Face != '1') { return true; } //if card2 is 10 and card1 is not else if (card1Face != '1' && card2Face == '1') { return false; } //if card1 higher than card2 else if (card1Face > card2Face) { return true; } //if card1 lower than card2 else if (card1Face < card2Face) { return false; } } //end cards are nums //if card1 and card2 same face value else if (card1Face == card2Face) { char card1Suit = card1[strlen(card1) - 1]; char card2Suit = card2[strlen(card2) - 1]; //test for spade if (card1Suit == 'S') { return true; } else if (card2Suit == 'S') { return false; } //test for Hearts if (card1Suit == 'H') { return true; } else if (card2Suit == 'H') { return false; } //test for Diamonds if (card1Suit == 'D') { return true; } else if (card2Suit == 'D') { return false; } //test for Clubs if (card1Suit == 'C') { return true; } else if (card2Suit == 'C') { return false; } } printf("IF THIS PRINTS UH OH"); return EXIT_SUCCESS; }
游戏主逻辑playGame函数代码如下:
void playGame(void) { srand(time(NULL)); //initialize deck char *(*deck)[13] = initializeDeck(); deck = shuffleDeck(deck); bool quit = false; while (1) { printHeaderDeal(); //user input loop while (1) { fflush(stdin); char choice = getchar(); //if enter to deal if (choice == '\n') { break; } //if q to quit else if (choice == 'q' || choice == 'Q') { printf("You chose to quit\n"); quit = true; break; } //handling wrong input else { printf("Incorrect choice! Please choose ENTER to deal or q to quit. \n"); scanf("%*[^\n]%*c"); } } //end user input //if quit selected break from loop if (quit == true) { break; } int numCardsToDeal; //user selects number of cards to deal while (1) { printf("How many cards would you like to deal? 2-20\n"); scanf(" %d", &numCardsToDeal); scanf("%*[^\n]"); //set range = even number between 2-20 if (numCardsToDeal >= 2 && numCardsToDeal <= 20) { if (numCardsToDeal % 2 == 1) { printf("Players must have same amount of cards in hand. Pick an even amount to deal.\n"); } else { break; } } else { printf("Incorrect selection.\n"); } }//end num to deal selection and validation //call deal cards and subtract the return value from the remaining card total cardsRemaining -= dealCards(deck, numCardsToDeal); bool result;
打印玩家手牌、调用比较函数、按轮次统计获胜次数的逻辑代码:
int length1 = sizeof(player1Hand)/sizeof(player1Hand[0]); printf("\n\n"); printf("Player 1 hand: "); for(int i = 0; i < length1; i++) { printf("[%s]", player1Hand[i]); } printf("\n\n"); int length2 = sizeof(player2Hand)/sizeof(player2Hand[0]); printf("Player 2 hand: "); for(int i = 0; i < length2; i++) { printf("[%s]", player2Hand[i]); } printf("\n\n"); //loop through player hands based on num of dealt cards, call compareCards on each iteration and store results of each comparison for (int i = 0; i < (numCardsToDeal / 2); i++) { result = compareCards(player1Hand[i], player2Hand[i]); if (result == true) { player1Wins++; } else if (result == false) { player2Wins++; } } //if run out of cards end game if (cardsRemaining == 0) { printf("No more cards remaining in deck. Game over.\n\n"); break; } } //end game printf("Total wins for player 1: %d\n", player1Wins); printf("Total wins for player 2: %d\n", player2Wins); free(deck);
问题根因
1. 判定分支覆盖不全
- 当两张字母牌为A/K/Q/J以外的大写字母且面值不等时,字母判断块内无匹配分支,也不会进入后续同面值判断分支,直接漏到函数末尾
- 当牌面值字符不在
A-Z或1-9范围内时,也会触发漏判 - 若花色为小写字母(如
s/h等),同面值的花色判断分支也会全部漏过
2. 异常分支返回值错误
触发漏判时函数返回EXIT_SUCCESS,该宏定义值为0等价于false,会被主逻辑判定为玩家2获胜,直接导致胜场计数错误
3. 主逻辑潜在问题
fflush(stdin)属于C标准未定义行为,不同编译器实现效果不稳定,可能导致输入逻辑异常- 若
player1Hand/player2Hand为动态分配的指针数组,sizeof计算的长度是指针本身大小而非数组元素个数,会导致打印手牌时出现乱码
修复方案
1. 完善compareCards函数逻辑
- 字母牌判断块兜底:两张都是合法字母牌(A/K/Q/J)且不等时,按A>K>Q>J规则直接比较返回
- 花色判断统一转为大写,兼容小写输入
- 函数末尾添加兜底返回逻辑,覆盖所有边缘场景
- 替换异常分支的
EXIT_SUCCESS为符合规则的bool返回值
2. 修复主逻辑问题
- 替换
fflush(stdin)为scanf("%*[^\n]%*c")清空输入缓冲区 - 打印手牌时用
numCardsToDeal/2作为循环长度,替代sizeof计算的结果
内容的提问来源于stack exchange,提问作者chessfordays
相关产品推荐
相关产品推荐

