gameplay-fns.go (5570B)
1 package gameplay 2 3 import ( 4 "fmt" 5 "math/rand" 6 "strings" 7 8 "git.hanabi.in/dev/wordle-cli/src/algos" 9 "git.hanabi.in/dev/wordle-cli/src/colours" 10 "git.hanabi.in/dev/wordle-cli/src/data" 11 ) 12 13 const ( 14 chances = 6 15 word_size = 5 16 ) 17 18 // From a pre-defined sorted list of words, pick a random word which is the answer. 19 func SelectAnswer() string { 20 words := []string{} 21 for _, elem := range data.Answers { 22 words = append(words, elem) 23 } 24 algos.Shuffle(words) 25 index := rand.Intn(len(words)) 26 return words[index] 27 } 28 29 // Create a lookup table for alphabet, initialise them to grey colour. 30 func initAlphabetTable() algos.Lookup { 31 var alphabet_table = make(algos.Lookup, 0) 32 letters := "abcdefghijklmnopqrstuvwxyz" 33 for _, elem := range letters { 34 letter_char := string(elem) 35 alphabet_table[letter_char] = colours.Code_grey 36 } 37 return alphabet_table 38 } 39 40 // Check if the word is of the size of answer. Returns true if size mismatch. 41 func isWrongGuessSize(guess string) bool { 42 return len(guess) != word_size 43 } 44 45 // Get user input for the guess, and process it (lower case) 46 func fetchGuess() string { 47 var guess string 48 fmt.Scanf("%s", &guess) 49 guess = strings.ToLower(guess) 50 return guess 51 } 52 53 // Check if guessed word is not in the list of possible words. Returns true if not found. 54 func isNotValidWord(guess string) bool { 55 idx1 := algos.BinarySearch(data.Answers, guess) 56 idx2 := algos.BinarySearch(data.Guesses, guess) 57 return idx1 == -1 && idx2 == -1 58 } 59 60 // returns either a valid guess, XOR an error. 61 func getValidGuess(prev_guesses []string) (string, error) { 62 guess := fetchGuess() 63 var error_msg error = nil 64 if isWrongGuessSize(guess) { 65 error_msg = fmt.Errorf("Word should be of length %d.\n", word_size) 66 } else if isNotValidWord(guess) { 67 error_msg = fmt.Errorf("Not a valid word.\n") 68 } else if isOldGuess(guess, prev_guesses) { 69 error_msg = fmt.Errorf("You already guessed this word.\n") 70 } 71 return guess, error_msg 72 } 73 74 // Check if the current guess was already guessed or not. 75 func isOldGuess(guess string, prev_guesses []string) bool { 76 for _, elem := range prev_guesses { 77 if elem == guess { 78 return true 79 } 80 } 81 return false 82 } 83 84 // Print the guess prompt. 85 func guessPrompt(chance int) { 86 msg := colours.Bold(fmt.Sprintf("Guess #%d?: ", chance)) 87 fmt.Print(msg) 88 } 89 90 // Look at colour_string (Y,G,R) and print the characters of word in colour. 91 func printColouredGuess(colour_string, word string) { 92 for idx, word_elem := range word { 93 col_str_char := string(colour_string[idx]) 94 word_char := string(word_elem) 95 if col_str_char == "R" { 96 fmt.Print(colours.Red(word_char)) 97 } else if col_str_char == "Y" { 98 fmt.Print(colours.Yellow(word_char)) 99 } else if col_str_char == "G" { 100 fmt.Print(colours.Green(word_char)) 101 } 102 } 103 fmt.Println() 104 } 105 106 // Print coloured alphabet for aiding which words to guess. 107 func printColouredAlpha(alphabet algos.Lookup) { 108 kbd_rows := []string{"qwertyuiop", "asdfghjkl", "zxcvbnm"} // keyboard layout printing. 109 for _, kbd_row := range kbd_rows { 110 for _, kbd_key := range kbd_row { 111 kbd_key_char := string(kbd_key) 112 char_col_code := alphabet[kbd_key_char] 113 if char_col_code == colours.Code_grey { 114 fmt.Print(colours.Grey(kbd_key_char)) 115 } else if char_col_code == colours.Code_red { 116 fmt.Print(colours.Red(kbd_key_char)) 117 } else if char_col_code == colours.Code_yellow { 118 fmt.Print(colours.Yellow(kbd_key_char)) 119 } else if char_col_code == colours.Code_green { 120 fmt.Print(colours.Green(kbd_key_char)) 121 } 122 fmt.Print(" ") 123 } 124 fmt.Println() 125 } 126 fmt.Println() 127 } 128 129 // Print share emoji. 130 func printShare(guesses []string) { 131 if shouldPrintShareEmojis() { 132 fmt.Println() 133 for _, row := range guesses { 134 for _, elem_byte := range row { 135 elem := string(elem_byte) 136 if elem == "R" { 137 fmt.Print("🌑") 138 } else if elem == "Y" { 139 fmt.Print("🌕") 140 } else if elem == "G" { 141 fmt.Print("✅") 142 } 143 } 144 fmt.Println() 145 } 146 } 147 } 148 149 // Prompt if the answer should be printed. 150 func shouldPrintAnswer() bool { 151 var ans string 152 fmt.Print(colours.Bold("Show answer?[yN]: ")) 153 fmt.Scanf("%s", &ans) 154 if ans == "Y" || ans == "y" { 155 return true 156 } 157 return false 158 } 159 160 // Prompt if the share emojies be printed. 161 func shouldPrintShareEmojis() bool { 162 var ans string 163 fmt.Print(colours.Bold("Share your results?[yN]: ")) 164 fmt.Scanf("%s", &ans) 165 if ans == "Y" || ans == "y" { 166 return true 167 } 168 return false 169 } 170 171 // The guessing function, returns guess history and if the user won the game. 172 func StartGuessing(answer string) ([]string, bool) { 173 174 var alphabet = initAlphabetTable() 175 var anslookup = algos.GenAnsLookup(answer) 176 var prev_guesses = []string{} 177 var colouredChoices = []string{} 178 didWin := false 179 fmt.Printf("Guess a %d-letter word. You have %d tries.\n", word_size, chances) 180 181 for cur_chance := 1; cur_chance <= chances; { 182 guessPrompt(cur_chance) 183 guess, err := getValidGuess(prev_guesses) 184 if err != nil { 185 fmt.Printf("%v", err) 186 } else { 187 cur_chance++ 188 prev_guesses = append(prev_guesses, guess) 189 colour_string := algos.GetColours(answer, guess, anslookup, alphabet) 190 colouredChoices = append(colouredChoices, colour_string) 191 printColouredGuess(colour_string, guess) 192 if guess == answer { 193 didWin = true 194 break 195 } 196 } 197 printColouredAlpha(alphabet) 198 } 199 return colouredChoices, didWin 200 } 201 202 // Handle end of the game once correct answer is reached, or when all chances are over. 203 func GracefullyFinishGame(answer string, guesses []string, didWin bool) { 204 if !didWin && shouldPrintAnswer() { 205 fmt.Printf("Answer was: %s.\n", answer) 206 } 207 printShare(guesses) 208 }