/// <summary> /// One of the AI's secondary logic algorithms. This one infers which characters in which spots /// might be responsible for a bull, by comparing similar guesses. /// </summary> /// <returns>A list of AISpots that most likely have bulls.</returns> private List <AISpot> AIinferredBulls() { // The AI needs to be able to look at the board, look at which spots have bulls, and then try to // deduce which spots they have in common that are probably responsible for those bulls. // Then, look at my list of candidates, and figure out which of those contain these spots in their proper positions. List <string> pastGuessesWith2Bulls = new List <string>(); List <AISpot> unfilteredBullSpots = new List <AISpot>(); List <AISpot> inferredBullSpots = new List <AISpot>(); // Loop through the player's list of results labels. for (int i = 0; i < this.gameControl.ActivePlayer.ListOfResults.Count(); i++) { // If there are are more than two bulls on this label... // Look at the row next to this label. What's the corresponding guess in the player's guess list? // Add this guess to the new list. if (Regex.Matches(this.gameControl.ActivePlayer.ListOfResults[i].Text, "🐂").Count > 1) { pastGuessesWith2Bulls.Add(this.gameControl.ActivePlayer.Guesses[i]); } } // If there are at least two guesses with at least two bulls, compare each guess to find similarities. if (pastGuessesWith2Bulls.Count() > 1) { Console.WriteLine("Found " + pastGuessesWith2Bulls.Count() + " past guesses with 2 bulls."); // For each member of this list... for (int i = 0; i < pastGuessesWith2Bulls.Count(); i++) { // Compare it to all other members of this list... for (int j = 0; j < pastGuessesWith2Bulls.Count(); j++) { // And see if they have any chars in common. for (int k = 0; k < this.gameControl.CodeLength; k++) { if (pastGuessesWith2Bulls[i][k] == pastGuessesWith2Bulls[j][k]) { // Note: It's okay (though not ideal) to include self-matches with those that match others in here. AISpot bullSpot = new AISpot(); bullSpot.Name = k.ToString(); bullSpot.Value = pastGuessesWith2Bulls[i][k].ToString(); // Add them to the master list that will later be returned from this method. unfilteredBullSpots.Add(bullSpot); } } } } } Console.WriteLine("Found " + unfilteredBullSpots.Count + " unfiltered bull spots."); foreach (AISpot i in unfilteredBullSpots) { int matchCounter = 0; foreach (AISpot j in unfilteredBullSpots) { if (i.Name == j.Name && i.Value == j.Value) { matchCounter++; if (matchCounter > 1) { // Console.WriteLine("Found a self match?"); inferredBullSpots.Add(i); } } } } Console.WriteLine("Permutations with inferred bull matches: " + inferredBullSpots.Count); return(inferredBullSpots); }
/// <summary> /// One of the AI's secondary logic algorithms. This one deduces which characters in which spots /// are not responsible for any bulls, by comparison, which can then be ruled out from future /// consideration. /// </summary> /// <returns>A list of AISpots that do not have bulls.</returns> private List <AISpot> AIdeducedNoBulls() { /* * Just as we can infer the position of where a bull is located, we can rule out positions where * we are sure a bull is not. Sometimes the main AI is satisfied with cow after cow instead of * trying to get more bulls. This should curb that tendency. */ List <string> pastGuessesWith2Cows = new List <string>(); List <AISpot> preFilteredCows = new List <AISpot>(); List <AISpot> deducedNoBullSpots = new List <AISpot>(); // Loop through the player's list of results labels. for (int i = 0; i < this.gameControl.ActivePlayer.ListOfResults.Count(); i++) { if (Regex.Matches(this.gameControl.ActivePlayer.ListOfResults[i].Text, "🐄").Count > 1 && Regex.Matches(this.gameControl.ActivePlayer.ListOfResults[i].Text, "🐂").Count == 0) { pastGuessesWith2Cows.Add(this.gameControl.ActivePlayer.Guesses[i]); } } List <AISpot> unfilteredCowSpots = new List <AISpot>(); // If there are at least two guesses with at least two cows, compare each guess to find similarities. if (pastGuessesWith2Cows.Count() > 1) { Console.WriteLine("Found " + pastGuessesWith2Cows.Count + " past guesses with two cows and no bulls."); // For each member of this list... for (int i = 0; i < pastGuessesWith2Cows.Count(); i++) { // Compare it to all other members of this list... for (int j = 0; j < pastGuessesWith2Cows.Count(); j++) { // And see if they have any chars in common. for (int k = 0; k < this.gameControl.CodeLength; k++) { if (pastGuessesWith2Cows[i][k] == pastGuessesWith2Cows[j][k]) { AISpot noBullSpot = new AISpot(); noBullSpot.Name = k.ToString(); noBullSpot.Value = pastGuessesWith2Cows[i][k].ToString(); unfilteredCowSpots.Add(noBullSpot); } } } } } Console.WriteLine("Found " + unfilteredCowSpots.Count + " unfilted cow spots."); foreach (AISpot i in unfilteredCowSpots) { int matchCounter = 0; foreach (AISpot j in unfilteredCowSpots) { if (i.Name == j.Name && i.Value == j.Value) { matchCounter++; if (matchCounter > 1) { deducedNoBullSpots.Add(i); } } } } Console.WriteLine("Permutations that match deduction of where bulls are not: " + deducedNoBullSpots.Count()); return(deducedNoBullSpots); }
private async void FindPossibleBullsOrCows() { int myBullsCount = 0; int guessCounter = 0; // Loop through every previous guess. foreach (string guess in this.gameControl.ActivePlayer.Guesses) { if (this.gameControl.ActivePlayer.MyInputList.Count() > 0) { await this.UpdateBotMouth("Considering " + this.gameControl.ActivePlayer.MyInputList.Count() + " possibilities."); List <AISpot> permSpots = new List <AISpot>(); List <AISpot> guessSpots = new List <AISpot>(); // For each guess, loop through every permutation in MyInputList. foreach (string perm in this.gameControl.ActivePlayer.MyInputList) { // Compare the permutation to the guess. // Turn each of the two strings into a list of AISpots. for (int i = 0; i < this.gameControl.CodeLength; i++) { AISpot tempPermSpot = new AISpot(); tempPermSpot.Name = "a" + i; tempPermSpot.Value = perm.Substring(i, 1); permSpots.Add(tempPermSpot); } for (int i = 0; i < this.gameControl.CodeLength; i++) { AISpot tempGuessSpot = new AISpot(); tempGuessSpot.Name = "b" + i; tempGuessSpot.Value = guess.Substring(i, 1); guessSpots.Add(tempGuessSpot); } myBullsCount = 0; // Compare spots. A match means this character might be responsible for either a bull or a cow. for (int k = 0; k < this.gameControl.CodeLength; k++) { if (guessSpots[k].Value == permSpots[k].Value) { myBullsCount++; guessSpots[k].Value = string.Empty; permSpots[k].Value = string.Empty; } } // See if this permutation gets the same number of bulls as what we just had. // If so, add it to the new OUTPUT list. if (myBullsCount == Regex.Matches(this.gameControl.ActivePlayer.ListOfResults[guessCounter].Text, "🐂").Count) { this.gameControl.ActivePlayer.MyOutputList.Add(perm); } permSpots.Clear(); guessSpots.Clear(); } // end cycling through input list. } if (this.gameControl.ActivePlayer.MyOutputList.Count() > 0) { // Assuming MyOutputList has multiple guess candidates inside, clear out the inputList // and put the output list into it. This way, next time it analyzes the previous turn // it will be re-sorting a previously sorted list to further eliminate possiblities. this.gameControl.ActivePlayer.MyInputList.Clear(); foreach (string myValue in this.gameControl.ActivePlayer.MyOutputList) { this.gameControl.ActivePlayer.MyInputList.Add(myValue); } this.gameControl.ActivePlayer.MyOutputList.Clear(); } else { MessageBox.Show("Congratulations! BessieBot's brain is broken in such a way \n that should not even be possible. \n"); } guessCounter++; } }