simulator.go 4.7 KB

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