C语言实现MasterMind游戏:白棋计数函数BUG修复求助
MasterMind游戏白棋计算函数问题修复
问题描述
正在用C语言开发MasterMind游戏,大部分功能已完成,但计算白棋(颜色正确但位置错误)的calculaBrancas函数存在问题:当随机生成的棋盘包含重复颜色,且玩家猜中其中一个错误位置时,函数无法正确计数。
现有完整代码
#include <stdio.h> #include <string.h> #include <stdlib.h> #include <time.h> #include <math.h> #define STRING_MAXIMO 10 void gerarTabuleiro(int nivel, char (*tabuleiro)[STRING_MAXIMO]) { char coresNivel1[6][STRING_MAXIMO] = {"vermelho", "verde", "azul", "amarelo", "rosa", "ciano"}; char coresNivel2[7][STRING_MAXIMO] = {"vermelho", "verde", "azul", "amarelo", "rosa", "ciano", "castanho"}; char coresNivel3[8][STRING_MAXIMO] = {"vermelho", "verde", "azul", "amarelo", "rosa", "ciano", "castanho", "roxo"}; int index; srand(time(NULL)); if(nivel == 1){ for(index = 0; index != nivel + 3; index++) strcpy(tabuleiro[index], coresNivel1[rand() % 6]); } else if(nivel == 2){ for(index = 0; index != nivel + 3; index++) strcpy(tabuleiro[index], coresNivel2[rand() % 7]); } else if(nivel == 3){ for(index = 0; index != nivel + 3; index++) strcpy(tabuleiro[index], coresNivel3[rand() % 8]); } } int calculaPretas(int nivel, char (*tabuleiro)[STRING_MAXIMO], char (*palpite)[STRING_MAXIMO]) { int index; int nDp = 0; for(index = 0; index != nivel + 3; index++){ if(strcmp(palpite[index], tabuleiro[index]) == 0) nDp++; } return nDp; } int calculaBrancas(int nivel, char (*tabuleiro)[STRING_MAXIMO], char (*palpite)[STRING_MAXIMO]) { int indexT, indexP; int nDp = 0; int contabilizado[nivel+3]; for(int index = 0; index != nivel + 3; index++) contabilizado[index] = 0; for(indexP = 0; indexP != nivel + 3; indexP++){ for(indexT = 0; indexT != nivel + 3; indexT++){ if((strcmp(palpite[indexP], tabuleiro[indexT]) == 0) && indexP != indexT && !contabilizado[indexP]){ nDp++; contabilizado[indexP] = 1; } } } return nDp; } int main(int argc, char *argv) { int nivel; int index; printf("#############################################################################################################\n"); printf("# O objectivo do Mastermind é descobrir uma combinação de cores determinada aleatoriamente pelo computador. #\n"); printf("# Para tal e necessario que escolha o nivel de jogo adequado #\n"); printf("# Nivel 1 -> 4 casas e 6 cores possiveis #\n"); printf("# Nivel 2 -> 5 casas e 7 cores possiveis #\n"); printf("# Nivel 3 -> 6 casas e 8 cores possiveis #\n"); printf("# Escolha o nivel pretendido #\n"); scanf("%i", &nivel); printf("# Nivel %i selecionado #\n", nivel); printf("#############################################################################################################\n\n\n"); char tabuleiro[nivel + 3][STRING_MAXIMO]; char palpite[nivel + 3][STRING_MAXIMO]; gerarTabuleiro(nivel, tabuleiro); /*Teste*/ printf("| "); for(index = 0; index != nivel + 3; index++){ printf("%s | ", tabuleiro[index]); } printf("\n\n"); /*Fim de teste*/ int novoPalpite; int tentativas = 0; int numeroDeBrancas = 0, numeroDePretas = 0; do{ printf("# Insira o seu palpite #\n"); for(index = 0; index != nivel + 3; index++){ printf("# Casa %i\t", index + 1); scanf("%s", palpite[index]); } tentativas++; numeroDePretas = calculaPretas(nivel, tabuleiro, palpite); numeroDeBrancas = calculaBrancas(nivel, tabuleiro, palpite); printf("###########################################\n"); printf("# Numero de peças pretas: %i #\n", numeroDePretas); printf("#Numero de peças brancas: %i #\n", numeroDeBrancas); printf("###########################################\n"); if(numeroDePretas == nivel + 3){ printf("###########################################\n"); printf("# Necessitou de %i tentativas para ganhar #\n", tentativas); printf("# TABULEIRO #\n# "); for(index = 0; index != nivel + 3; index++) printf("%s # ", tabuleiro[index]); printf("\n###########################################\n"); break; } printf("# Deseja introduzir um novo palpite #\n"); printf("# 1. Novo palpite #\n"); printf("# 2. Desistir #\n"); scanf("%i", &novoPalpite); if(novoPalpite == 2){ printf("# Desistiu do jogo #\n"); printf("# Tabuleiro #\n "); printf("| "); for(index = 0; index != nivel + 3; index++) printf("%s | ", tabuleiro[index]); printf("\n\n"); } }while(novoPalpite == 1); return 0; }
问题分析
原calculaBrancas函数存在两个核心问题:
- 未排除黑棋位置:已经被判定为黑棋(颜色和位置均正确)的棋子,不应该参与白棋的计数逻辑,但原函数没有处理这一点,会导致重复计数。
- 仅标记猜测项:只标记了猜测的棋子是否已被计数,但没有标记棋盘上的棋子,当棋盘存在重复颜色时,同一个棋盘棋子可能被多个猜测棋子匹配,导致白棋数量虚高。
修复方案
修改calculaBrancas函数,新增棋盘标记数组,先排除黑棋位置,再双向标记已匹配的猜测和棋盘棋子:
int calculaBrancas(int nivel, char (*tabuleiro)[STRING_MAXIMO], char (*palpite)[STRING_MAXIMO]) { int indexT, indexP; int nDp = 0; int tamanho = nivel + 3; // 标记棋盘位置是否已被匹配(用于白棋计算) int tabuleiroUsado[tamanho]; // 标记猜测位置是否已被匹配(用于白棋计算) int palpiteUsado[tamanho]; // 初始化标记数组 for(int index = 0; index < tamanho; index++){ tabuleiroUsado[index] = 0; palpiteUsado[index] = 0; } // 第一步:标记所有黑棋的位置,这些位置不参与白棋计算 for(int index = 0; index < tamanho; index++){ if(strcmp(palpite[index], tabuleiro[index]) == 0){ tabuleiroUsado[index] = 1; palpiteUsado[index] = 1; } } // 第二步:匹配颜色正确但位置错误的棋子,双向标记避免重复计数 for(indexP = 0; indexP < tamanho; indexP++){ if(palpiteUsado[indexP]) continue; // 跳过已标记为黑棋或已匹配白棋的猜测项 for(indexT = 0; indexT < tamanho; indexT++){ if(tabuleiroUsado[indexT]) continue; // 跳过已标记的棋盘项 if(strcmp(palpite[indexP], tabuleiro[indexT]) == 0){ nDp++; palpiteUsado[indexP] = 1; tabuleiroUsado[indexT] = 1; break; // 找到匹配后跳出内层循环,避免同一猜测项匹配多个棋盘项 } } } return nDp; }
修改说明
- 新增两个标记数组
tabuleiroUsado和palpiteUsado,分别记录棋盘和猜测的棋子是否已被用于黑棋或白棋计数。 - 先遍历一次,标记所有黑棋的位置,这些位置直接跳过后续白棋计算。
- 遍历猜测和棋盘时,仅处理未被标记的项,匹配成功后同时标记双方位置,确保每个棋子只被计数一次。
验证示例
测试用例1:
- 棋盘:
["vermelho", "vermelho"] - 玩家猜测:
["vermelho", "azul"] - 预期结果:黑棋1,白棋0
- 修复后函数返回白棋0,符合预期。
- 棋盘:
测试用例2:
- 棋盘:
["vermelho", "verde", "vermelho"] - 玩家猜测:
["verde", "vermelho", "azul"] - 预期结果:黑棋0,白棋2
- 修复后函数返回白棋2,符合预期。
- 棋盘:
测试用例3:
- 棋盘:
["vermelho", "vermelho"] - 玩家猜测:
["azul", "vermelho"] - 预期结果:黑棋1,白棋0
- 修复后函数返回白棋0,符合预期。
- 棋盘:
内容的提问来源于stack exchange,提问作者PedroVFerreira
相关产品推荐
相关产品推荐

