simulator.go 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192
  1. package main
  2. import (
  3. "fmt"
  4. "os"
  5. )
  6. type Simulation struct {
  7. Game *Game
  8. BestGuess string
  9. BestGuessRounds int
  10. SuccessCount int
  11. FailCount int
  12. TotalRounds int
  13. }
  14. func NewSimulator(g Game) *Simulation {
  15. return &Simulation{
  16. Game: &g,
  17. }
  18. }
  19. func (s Simulation) SimulateAllPossibleGames() (string, error) {
  20. bestGuessLossCount := 99
  21. bestGuessMaxRounds := 99
  22. bestGuessTotalRounds := 99
  23. wordLossCounts := make(map[string]int)
  24. totRoundCounts := make(map[string]int)
  25. maxRoundCounts := make(map[string]int)
  26. for initialWord := range s.Game.Words {
  27. fmt.Println(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>")
  28. simulatedGame := NewGame()
  29. simulatedGame.Words = make(map[string]*Word)
  30. for word := range s.Game.Words {
  31. simulatedGame.Words[word] = &Word{Word: word}
  32. }
  33. lossCount, maxRounds, totalRounds := s.SimulateOneInitialWord(simulatedGame, initialWord)
  34. wordLossCounts[initialWord] = lossCount
  35. totRoundCounts[initialWord] = totalRounds
  36. maxRoundCounts[initialWord] = maxRounds
  37. if lossCount < bestGuessLossCount {
  38. bestGuessLossCount = lossCount
  39. bestGuessTotalRounds = totalRounds
  40. bestGuessMaxRounds = maxRounds
  41. } else if lossCount == bestGuessLossCount && maxRounds < bestGuessMaxRounds {
  42. bestGuessTotalRounds = totalRounds
  43. bestGuessMaxRounds = maxRounds
  44. } else if lossCount == bestGuessLossCount && maxRounds == bestGuessMaxRounds && totalRounds < bestGuessTotalRounds {
  45. bestGuessTotalRounds = totalRounds
  46. }
  47. }
  48. fmt.Println(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>")
  49. fmt.Print("Simulation completed\n\n")
  50. err := s.Game.scoreWordsByCommonLetterLocations()
  51. if err != nil {
  52. return "", fmt.Errorf("Error scoring Words: %s", err)
  53. }
  54. var bestGuess string
  55. for _, word := range s.Game.getSortedScores() {
  56. if wordLossCounts[word] == bestGuessLossCount && totRoundCounts[word] == bestGuessTotalRounds && maxRoundCounts[word] == bestGuessMaxRounds {
  57. fmt.Printf("Best Guess: %s Failed Branches: %d Total Rounds: %d Max Rounds: %d\n\n", word, bestGuessLossCount, bestGuessTotalRounds, bestGuessMaxRounds)
  58. bestGuess = word
  59. break
  60. }
  61. }
  62. return bestGuess, nil
  63. }
  64. func (s Simulation) SimulateOneInitialWord(game *Game, initialWord string) (lossCount, maxRounds, totalRounds int) {
  65. debugPrint("Initial Word: %s\n", initialWord)
  66. for answer := range s.Game.Words {
  67. debugPrint(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n")
  68. debugPrint("Target Word: %s\n", answer)
  69. simulatedGame := NewGame()
  70. simulatedGame.Words = make(map[string]*Word)
  71. for word := range game.Words {
  72. simulatedGame.Words[word] = &Word{Word: word}
  73. }
  74. won, rounds := s.SimulateOneGame(simulatedGame, initialWord, answer)
  75. if !won {
  76. lossCount++
  77. }
  78. totalRounds += rounds
  79. if rounds > maxRounds {
  80. maxRounds = rounds
  81. }
  82. }
  83. fmt.Printf("Summary: Initial Word: %s Loss Count: %d Max Rounds: %d Total Rounds: %d\n", initialWord, lossCount, maxRounds, totalRounds)
  84. return lossCount, maxRounds, totalRounds
  85. }
  86. func (s Simulation) SimulateOneGame(simulatedGame *Game, initialWord, answer string) (bool, int) {
  87. guess := initialWord
  88. // 10 rounds max just to prevent infinite loops
  89. var round int
  90. for round = 1; round <= 10; round++ {
  91. if len(simulatedGame.Words) == 1 {
  92. debugPrint("Only one guess remaining after filtering: %s\n", guess)
  93. break
  94. }
  95. if round == 1 {
  96. debugPrint("First guess, initial Word: %s\n", initialWord)
  97. } else {
  98. //debugPrint(">>>>>>>>>>>>>>>>>>>>>>>>>>>>\n")
  99. //fmt.Printf("Starting Sub Simulation: %+v\n", simulatedGame.Words)
  100. //simulatedSubGame := NewGame()
  101. //simulatedSubGame.Words = make(map[string]*Word)
  102. //for word := range simulatedGame.Words {
  103. // simulatedSubGame.Words[word] = &Word{Word: word}
  104. //}
  105. //subSimulator := NewSimulator(*simulatedSubGame)
  106. //
  107. //var err error
  108. //guess, err = subSimulator.SimulateAllPossibleGames()
  109. //if err != nil {
  110. // fmt.Printf("Error simulating all possible games: %s\n", err)
  111. // os.Exit(1)
  112. //}
  113. //fmt.Printf("RESULT OF SUB Guess: %s\n", guess)
  114. var err error
  115. guess, err = simulatedGame.getBestGuess()
  116. if err != nil {
  117. fmt.Printf("Error calculating best guess: %s\n", err)
  118. os.Exit(1)
  119. }
  120. debugPrint("Round %d, guess: %s\n", round, guess)
  121. }
  122. if guess == answer {
  123. break
  124. }
  125. score := s.getScore(guess, answer)
  126. debugPrint("guess '%s' matches %d locations in answer '%s'\n", guess, score, answer)
  127. simulatedGame.FilterWords(guess, score)
  128. debugPrint("Words remaining after filtering: %+v\n", simulatedGame.Words)
  129. err := simulatedGame.scoreWordsByCommonLetterLocations()
  130. if err != nil {
  131. fmt.Printf("Error scoring Words: %s\n", err)
  132. os.Exit(1)
  133. }
  134. debugPrint("End round %d, not solved, %d words remaining\n", round, len(simulatedGame.Words))
  135. }
  136. if round > 4 {
  137. fmt.Printf(" Loss in %d rounds => %s .. %s\n", round, initialWord, answer)
  138. return false, round
  139. }
  140. fmt.Printf(" Win in %d rounds => %s .. %s\n", round, initialWord, answer)
  141. return true, round
  142. }
  143. func (s Simulation) getScore(guess string, answer string) int {
  144. score := 0
  145. for idx, letter := range answer {
  146. if string(letter) == string(guess[idx]) {
  147. score++
  148. }
  149. }
  150. return score
  151. }