package main import ( "bufio" "fmt" "os" "sort" ) type Game struct { Words map[string]*Word Length int } type Word struct { Word string Score int } func main() { game := NewGame() err := game.getWordsFromStdin() if err != nil { fmt.Printf("Error getting Words from stdin: %s\n", err) os.Exit(1) } err = game.scoreWordsByCommonLetterLocations() if err != nil { fmt.Printf("Error scoring Words: %s\n", err) os.Exit(1) } _, err = game.printSortedScores() if err != nil { fmt.Printf("Error printing sorted scores: %s\n", err) os.Exit(1) } for i := 0; i < 3; i++ { guess, score := getGuessAndScoreFromStdin() fmt.Printf("Guess: %s, Score: %d\n", guess, score) game.FilterWords(guess, score) err = game.scoreWordsByCommonLetterLocations() if err != nil { fmt.Printf("Error scoring Words: %s\n", err) os.Exit(1) } _, err = game.printSortedScores() if err != nil { fmt.Printf("Error printing sorted scores: %s\n", err) os.Exit(1) } if len(game.Words) == 1 { for word := range game.Words { fmt.Printf("The word is: %s\n", word) os.Exit(0) } } } } func NewGame() *Game { return &Game{ Words: make(map[string]*Word), } } func (g Game) FilterWords(guess string, score int) { for _, word := range g.Words { if !word.MatchesGuess(guess, score) { delete(g.Words, word.Word) } } } func (w Word) MatchesGuess(guess string, numMatchingChars int) bool { score := 0 for idx, letter := range w.Word { if string(letter) == string(guess[idx]) { score++ } } return score == numMatchingChars } func getGuessAndScoreFromStdin() (string, int) { reader := bufio.NewReader(os.Stdin) fmt.Print("Enter Guess: ") guess, _ := reader.ReadString('\n') guess = guess[:len(guess)-1] fmt.Print("Enter Score: ") var score int _, err := fmt.Scanf("%d", &score) if err != nil { fmt.Printf("Error reading score: %s\n", err) os.Exit(1) } return guess, score } func (g Game) printSortedScores() (string, error) { sortedWordScores := g.getSortedScores() fmt.Println("\n>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>") fmt.Print("Words sorted by Score:\n") for _, word := range sortedWordScores { fmt.Printf("%s: %d\n", word, g.Words[word].Score) } fmt.Println("") return sortedWordScores[0], nil } func (g Game) getSortedScores() []string { var sortedWordScores []string for _, word := range g.Words { sortedWordScores = append(sortedWordScores, word.Word) } // sort words by score sort.Slice(sortedWordScores, func(i, j int) bool { return g.Words[sortedWordScores[i]].Score > g.Words[sortedWordScores[j]].Score }) return sortedWordScores } func (g Game) getBestGuess() (string, error) { return g.getSortedScores()[0], nil } func (g Game) scoreWordsByCommonLetterLocations() error { letterIdxScores := make(map[int]map[string]int) var lastWord string for _, word := range g.Words { word.Score = 0 lastWord = word.Word } for idx := range lastWord { letterIdxScores[idx] = make(map[string]int) } for _, word := range g.Words { for idx, letter := range word.Word { letterIdxScores[idx][string(letter)]++ } } for _, word := range g.Words { for idx, letter := range word.Word { word.Score += letterIdxScores[idx][string(letter)] } } return nil } func (g Game) getWordsFromStdin() error { fmt.Println("Enter Words, one per line. Enter a period to end input.") for { reader := bufio.NewReader(os.Stdin) word, _ := reader.ReadString('\n') word = word[:len(word)-1] if word == "." { fmt.Println("got Words!") break } if g.Length == 0 { g.Length = len(word) } else { if len(word) != g.Length { fmt.Printf("Error: All words must be the same length (%d), skipping: %s\n", g.Length, word) continue } } g.Words[word] = &Word{Word: word} } return nil }