wordle-cli

Golang implementation of wordle in CLI.
git clone http://git.hanabi.in/repos/wordle-cli.git
Log | Files | Refs | README | LICENSE

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 }