Skip to content

Instantly share code, notes, and snippets.

@shmerl
Last active February 7, 2022 07:59
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save shmerl/2d1860d2bdba921dccaf84abb98940cd to your computer and use it in GitHub Desktop.
Save shmerl/2d1860d2bdba921dccaf84abb98940cd to your computer and use it in GitHub Desktop.
A simple version of Wordle game
#!/bin/bash
#
# Uses ripgrep (rg)
#
length=${length:-5}
tries=${tries:-6}
# All words of given length from a dictionary
declare -a words
declare -A words_dict
words=( $(rg --color=never --no-line-number '^\w{'"${length}"'}$' /usr/share/dict/words) )
# Generate random position in the dictionary by reading
# 8-byte integer from system random generator
random_pos=$(( $(od --output-duplicates --address-radix=n --read-bytes=8 --format=u8 < /dev/urandom) % ${#words[@]} ))
# Select the secret word and convert to upper case
secret=${words[$random_pos]^^}
# Prepare fast search dictionary in upper case and empty the raw array
for word in ${words[@]}; do
words_dict[${word^^}]=""
done
words=()
function validate_word() {
local word="$1"
if (( ${#word} != $length )); then
echo "You have to use ${length}-letter word!"
false
return
fi
if ! [ -v words_dict["${word^^}"] ]; then
echo "${word} is not recognized, try again!"
false
return
fi
true
}
clr_no=$(printf "\x1b[0m")
clr_green_bg=$(printf "\x1b[48;2;83;140;78m")
clr_yellow_bg=$(printf "\x1b[48;2;181;159;59m")
clr_gray_bg=$(printf "\x1b[48;2;58;58;60m")
clr_white_fg=$(printf "\x1b[1;38;2;215;218;220m")
function process_guess() {
local guess="${1^^}"
local secret="$2"
# Important values to calculate for a specific letter:
# ${secret_letter_total[$letter]} - number of appearances of the letter in the secret.
# ${guess_letter_correct[$letter]} - number of correct guessed positions for the letter (green).
# ${secret_letter_total[$letter]} - ${guess_letter_correct[$letter]} = number of maximum possible mismatched
# guessed letters to be shown (yellow).
# All guesses that exceed ${secret_letter_total[$letter]} - ${guess_letter_correct[$letter]} even if that letter
# was found somewhere will be shown as misses (gray).
local -A secret_letter_total=()
local -A guess_letter_correct=()
local -A guess_letter_mismatches=()
local letter
local guessed_letters=0
# Secret letter frequencies
for ((i = 0; i < ${#secret}; i++)); do
letter=${secret:$i:1}
if ! [ -v "${secret_letter_total[$letter]}" ]; then
secret_letter_total[$letter]=1
else
(( secret_letter_total[$letter]++ ))
fi
done
# First pass - exact matches.
for ((i = 0; i < ${#guess}; i++)); do
letter=${guess:$i:1}
if [[ "$letter" == "${secret:$i:1}" ]]; then
(( guessed_letters++ ))
if ! [ -v "${guess_letter_correct[$letter]}" ] || (( guess_letter_correct[$letter] == 0 )); then
guess_letter_correct[$letter]=1
else
(( guess_letter_correct[$letter]++ ))
fi
elif ! [ -v "${guess_letter_correct[$letter]}" ]; then
guess_letter_correct[$letter]=0
fi
done
# Second pass - completing the markup
printf "${clr_white_fg}"
for ((i = 0; i < ${#guess}; i++)); do
letter=${guess:$i:1}
# exact match
if [[ "$letter" == "${secret:$i:1}" ]]; then
printf "${clr_green_bg} ${letter} "
continue
fi
# miss
if ! [ -v "${secret_letter_total[$letter]}" ]; then
printf "${clr_gray_bg} ${letter} "
continue
fi
# mismatch
# update the frequency of that mismatch
if ! [ -v "${guess_letter_mismatches[$letter]}" ]; then
guess_letter_mismatches[$letter]=1
else
(( guess_letter_mismatches[$letter]++ ))
fi
if (( ${guess_letter_mismatches[$letter]} <= ${secret_letter_total[$letter]} - ${guess_letter_correct[$letter]} )); then
printf "${clr_yellow_bg} ${letter} "
else
printf "${clr_gray_bg} ${letter} "
fi
done
printf "${clr_no}"
if ((guessed_letters == length)); then
return 1
fi
return 0
}
rc=0
while (( (tries > 0 ) && (rc == 0) )); do
printf "Enter your guess (${tries} tries left): "
read guess
if ! validate_word "$guess"; then
continue
fi
hints=$(process_guess "$guess" "$secret")
rc=$?
printf "${hints}\n"
((--tries))
done
if ((rc != 0)); then
echo "You win!"
else
echo "You lose!"
echo "The word was: ${secret}"
fi
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment