C#实现Mastermind游戏:玩家与电脑代码比对逻辑异常问题
Hey there! Let's tackle that annoying overcounting issue with your Mastermind pin markers. The core problem with your current code is that the alreadyOcurredNumber boolean is too simplistic—it only tracks a single flag per outer loop iteration, which can't properly handle duplicate numbers or prevent reusing the same position in either the player's or opponent's code for multiple matches.
Why Your Current Approach Fails
For example, if the opponent's code is [1,1,2,3] and the player guesses [1,1,1,4], your code would incorrectly count more "right number wrong position" pins than it should. This happens because you're not tracking which specific positions in either array have already been matched, so the same opponent's 1 might get counted multiple times against different player 1s.
The Correct Approach to Count Pins
Mastermind's pin counting needs two distinct steps to avoid overcounting:
- First count exact matches (same number, same position). Mark these positions as used so they aren't reused in the next step.
- Then count partial matches (same number, different position) using only the unused positions from both arrays.
Modified Code for Pin Counting
Replace your existing pin-counting loop with this updated logic:
int rightGuessRightIndex = 0; int rightGuessWrongIndex = 0; // Create boolean arrays to track which positions have been matched bool[] usedOpponent = new bool[codeOfOpponent.Length]; bool[] usedPlayer = new bool[codeOfPlayer.Length]; // Step 1: Count exact matches (right number, right position) for (int i = 0; i < codeOfOpponent.Length; i++) { if (codeOfOpponent[i] == codeOfPlayer[i]) { rightGuessRightIndex++; usedOpponent[i] = true; usedPlayer[i] = true; } } // Step 2: Count partial matches (right number, wrong position) for (int i = 0; i < codeOfPlayer.Length; i++) { if (!usedPlayer[i]) // Only check unused player positions { for (int j = 0; j < codeOfOpponent.Length; j++) { if (!usedOpponent[j] && codeOfOpponent[j] == codeOfPlayer[i]) { rightGuessWrongIndex++; usedOpponent[j] = true; // Mark this opponent position as used to avoid re-counting break; // Move to next player number once we find a match } } } }
How This Works
- The
usedOpponentandusedPlayerarrays keep track of which positions in each code have already been accounted for (either as exact matches or partial matches). - We first handle exact matches to ensure those positions aren't considered again for partial matches.
- For partial matches, we only look at unused positions in both arrays, and once we find a match, we mark the opponent's position as used so it can't be matched again to another player number.
Bonus: Fixing the Turn Loop
You might also notice your current code only lets the player guess once. To add proper turn handling, wrap the guess and pin-counting logic in a while loop, like this:
int amountOfTurns = 0; const int maxTurns = 20; bool[] usedOpponent = new bool[codeOfOpponent.Length]; bool[] usedPlayer = new bool[codeOfPlayer.Length]; while (amountOfTurns < maxTurns) { // Get player's guess codeOfPlayer = mastermind.createCodeOfPlayer(codeOfPlayer); // Reset pin counts and used flags for each turn rightGuessRightIndex = 0; rightGuessWrongIndex = 0; Array.Clear(usedOpponent, 0, usedOpponent.Length); Array.Clear(usedPlayer, 0, usedPlayer.Length); // Run exact match counting for (int i = 0; i < codeOfOpponent.Length; i++) { if (codeOfOpponent[i] == codeOfPlayer[i]) { rightGuessRightIndex++; usedOpponent[i] = true; usedPlayer[i] = true; } } // Run partial match counting for (int i = 0; i < codeOfPlayer.Length; i++) { if (!usedPlayer[i]) { for (int j = 0; j < codeOfOpponent.Length; j++) { if (!usedOpponent[j] && codeOfOpponent[j] == codeOfPlayer[i]) { rightGuessWrongIndex++; usedOpponent[j] = true; break; } } } } // Display results Console.WriteLine("\nRight number and right place: {0}", rightGuessRightIndex); Console.WriteLine("Right number and wrong place: {0}", rightGuessWrongIndex); // Check for win condition if (codeOfPlayer.SequenceEqual(codeOfOpponent)) { Console.WriteLine($"You won in {amountOfTurns + 1} turns!"); break; } amountOfTurns++; Console.WriteLine($"\nTry again! You have {maxTurns - amountOfTurns} turns left."); } if (amountOfTurns == maxTurns) { Console.WriteLine("\nGame over! The opponent's code was:"); foreach (int num in codeOfOpponent) { Console.Write(num); } }
This will let the player keep guessing until they win or run out of turns.
内容的提问来源于stack exchange,提问作者Elipse

