|
@@ -0,0 +1,192 @@
|
|
|
+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
|
|
|
+}
|