package main import ( "fmt" "os" ) type Simulation struct { Game *Game BestGuess string BestGuessRounds int SuccessCount int FailCount int TotalRounds int } func NewSimulator(g Game) *Simulation { return &Simulation{ Game: &g, } } func (s Simulation) SimulateAllPossibleGames() (string, error) { bestGuessLossCount := 99 bestGuessMaxRounds := 99 bestGuessTotalRounds := 99 wordLossCounts := make(map[string]int) totRoundCounts := make(map[string]int) maxRoundCounts := make(map[string]int) for initialWord := range s.Game.Words { fmt.Println(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>") simulatedGame := NewGame() simulatedGame.Words = make(map[string]*Word) for word := range s.Game.Words { simulatedGame.Words[word] = &Word{Word: word} } lossCount, maxRounds, totalRounds := s.SimulateOneInitialWord(simulatedGame, initialWord) wordLossCounts[initialWord] = lossCount totRoundCounts[initialWord] = totalRounds maxRoundCounts[initialWord] = maxRounds if lossCount < bestGuessLossCount { bestGuessLossCount = lossCount bestGuessTotalRounds = totalRounds bestGuessMaxRounds = maxRounds } else if lossCount == bestGuessLossCount && maxRounds < bestGuessMaxRounds { bestGuessTotalRounds = totalRounds bestGuessMaxRounds = maxRounds } else if lossCount == bestGuessLossCount && maxRounds == bestGuessMaxRounds && totalRounds < bestGuessTotalRounds { bestGuessTotalRounds = totalRounds } } fmt.Println(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>") fmt.Print("Simulation completed\n\n") err := s.Game.scoreWordsByCommonLetterLocations() if err != nil { return "", fmt.Errorf("Error scoring Words: %s", err) } var bestGuess string for _, word := range s.Game.getSortedScores() { if wordLossCounts[word] == bestGuessLossCount && totRoundCounts[word] == bestGuessTotalRounds && maxRoundCounts[word] == bestGuessMaxRounds { fmt.Printf("Best Guess: %s Failed Branches: %d Total Rounds: %d Max Rounds: %d\n\n", word, bestGuessLossCount, bestGuessTotalRounds, bestGuessMaxRounds) bestGuess = word break } } return bestGuess, nil } func (s Simulation) SimulateOneInitialWord(game *Game, initialWord string) (lossCount, maxRounds, totalRounds int) { debugPrint("Initial Word: %s\n", initialWord) for answer := range s.Game.Words { debugPrint(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n") debugPrint("Target Word: %s\n", answer) simulatedGame := NewGame() simulatedGame.Words = make(map[string]*Word) for word := range game.Words { simulatedGame.Words[word] = &Word{Word: word} } won, rounds := s.SimulateOneGame(simulatedGame, initialWord, answer) if !won { lossCount++ } totalRounds += rounds if rounds > maxRounds { maxRounds = rounds } } fmt.Printf("Summary: Initial Word: %s Loss Count: %d Max Rounds: %d Total Rounds: %d\n", initialWord, lossCount, maxRounds, totalRounds) return lossCount, maxRounds, totalRounds } func (s Simulation) SimulateOneGame(simulatedGame *Game, initialWord, answer string) (bool, int) { guess := initialWord // 10 rounds max just to prevent infinite loops var round int for round = 1; round <= 10; round++ { if len(simulatedGame.Words) == 1 { debugPrint("Only one guess remaining after filtering: %s\n", guess) break } if round == 1 { debugPrint("First guess, initial Word: %s\n", initialWord) } else { //debugPrint(">>>>>>>>>>>>>>>>>>>>>>>>>>>>\n") //fmt.Printf("Starting Sub Simulation: %+v\n", simulatedGame.Words) //simulatedSubGame := NewGame() //simulatedSubGame.Words = make(map[string]*Word) //for word := range simulatedGame.Words { // simulatedSubGame.Words[word] = &Word{Word: word} //} //subSimulator := NewSimulator(*simulatedSubGame) // //var err error //guess, err = subSimulator.SimulateAllPossibleGames() //if err != nil { // fmt.Printf("Error simulating all possible games: %s\n", err) // os.Exit(1) //} //fmt.Printf("RESULT OF SUB Guess: %s\n", guess) var err error guess, err = simulatedGame.getBestGuess() if err != nil { fmt.Printf("Error calculating best guess: %s\n", err) os.Exit(1) } debugPrint("Round %d, guess: %s\n", round, guess) } if guess == answer { break } score := s.getScore(guess, answer) debugPrint("guess '%s' matches %d locations in answer '%s'\n", guess, score, answer) simulatedGame.FilterWords(guess, score) debugPrint("Words remaining after filtering: %+v\n", simulatedGame.Words) err := simulatedGame.scoreWordsByCommonLetterLocations() if err != nil { fmt.Printf("Error scoring Words: %s\n", err) os.Exit(1) } debugPrint("End round %d, not solved, %d words remaining\n", round, len(simulatedGame.Words)) } if round > 4 { fmt.Printf(" Loss in %d rounds => %s .. %s\n", round, initialWord, answer) return false, round } fmt.Printf(" Win in %d rounds => %s .. %s\n", round, initialWord, answer) return true, round } func (s Simulation) getScore(guess string, answer string) int { score := 0 for idx, letter := range answer { if string(letter) == string(guess[idx]) { score++ } } return score }