Skip to content

Instantly share code, notes, and snippets.

@mattmc3
Last active May 9, 2023 16:54
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mattmc3/4faac3224800be98c76d4738ddc569af to your computer and use it in GitHub Desktop.
Save mattmc3/4faac3224800be98c76d4738ddc569af to your computer and use it in GitHub Desktop.
Fish Shell - Wordle Helper

Fish Wordle Helper

Wordle is a simple word game where you try to guess a 5-letter word each day. This gist contains a small Fish function to help you narrow down the list of possible answers based on the scores from each guess.

How To Play

Guess the Wordle in 6 tries.

  • Each guess must be a valid 5-letter word.
  • The color of the tiles will change to show how close your guess was to the word.

Examples

W is in the word and in the correct spot.

I is in the word but in the wrong spot.

U is not in the word in any spot.

wordle_helper.fish

To play with this function, install fish. Then add the code in this gist to a new function file: ~/.config/fish/functions/fish_helper.fish.

Usage

$ wordle_helper -h
wordle_helper - Fish function to help with Wordle puzzles

Usage:
  wordle_helper [--green <exact_positions>] [--yellow <not_exact_positions>] <guess>

Options:
  -h, --help     Print help
  -g, --green    Position of letters that matched exactly (format: 12345)
  -y, --yellow   Position of letters that are not exact (format: 12345)

Example:
$ wordle_helper -y 3 SLATE | wordle_helper -g 14 -y 2 CAROM
COCOA

Play a game

Make a guess on today's Wordle.

Let's say you start by guessing SLATE. You get a score of:

We got yellow in position 3, and no green. That means there's an A, but no S, L, T, or E. Let's run wordle_helper -y 3 SLATE. You should get 800+ possible words that match that score. We didn't do very well on our first guess. Let's take another.

From that list, let's guess CAROM.

This time we did a lot better. We got green in positions 1 and 4, and got yellow in position 2 this time. That means C and O are right, but we still haven't found where A goes. Let's run wordle_helper again, but this time let's pipe the words from the first result into the second. That way, the all our guesses filter the word list. Pressing the up arrow on a Fish prompt gets your last command.

$ wordle_helper -y 3 SLATE | wordle_helper -g 14 -y 2 CAROM
COCOA
...

Whoa! For our 3rd guess, there's only one choice left that fits! Thanks Wordle Helper!

How it works

The Fish function is pretty well commented, but there are a few regex tricks we use.

First, we need to get all the possible 5-letter words. We get that either from the system dictionary file (on macOS, that is /usr/share/dict/words), or we pipe the filtered word list in from the results of a prior guess.

Next, if our guess gets scored with green letters, we can narrow the word list down really fast. For example, our CAROM guess where the C and O in positions 1 and 4 were correct, the string match regex is simply ^C..O.$.

Similarly, if our guess gets scored with yellow letters, we know that the letter is in the wrong place, but also exists in the word. Filtering words on a single letter match is simple, and then similar to the green regex, we filter words with A in the wrong place with ^.[^A]...$.

How it could be improved

Instead of just showing the possible answers alphabetically, the helper could simulate the best next guesses based on the remaining possible answers and sort by which guesses would be better than the others. It wouldn't be that hard to turn this into a complete Wordle solver, but the goal isn't to take all the fun out of playing.

Depending on your system's dictionary file, you may run across a word that isn't in your dictionary, in which case this function won't work and will lead you astray. For example, the word SANER is not in my macOS dictionary file, but is a valid 5-letter Wordle answer:

$ cat /usr/share/dict/words | string match -re '^sane'
sane
sanely
saneness
# change this to whatever dictionary file you want
set -q DICT_FILE || set -U DICT_FILE /usr/share/dict/words
function _validate_wordle_score -d "argparse validator for Wordle score args"
# scores are in the format '12345' with digits representing the score position
_validate_int; or return 1
if not string match -qr '^[1-5]+$' -- $_flag_value
set -l msg (_ "%s: Value '%s' for flag '%s' contains out-of-range numbers. Expecting 1-5.\n")
printf $msg $_argparse_cmd $_flag_value $_flag_name >&2 && return 1
end
end
function __wordle_helper_usage -d "Print usage string for Fish Wordle Helper"
echo "wordle_helper - Fish function to help with Wordle puzzles"
echo
echo "Usage:"
echo " wordle_helper [--green <exact_positions>] [--yellow <not_exact_positions>] <guess>"
echo
echo "Options:"
echo " -h, --help Print help"
echo " -g, --green Position of letters that matched exactly (format: 12345)"
echo " -y, --yellow Position of letters that are not exact (format: 12345)"
echo
echo "Example:"
echo "\$ wordle_helper -y 3 SLATE | wordle_helper -g 14 -y 2 CAROM"
echo "COCOA"
end
function wordle_helper -d "Show possible remaining guesses for a Wordle puzzle"
argparse --name wordle_helper 'h/help' 'g/green=+!_validate_wordle_score' \
'y/yellow=+!_validate_wordle_score' -- $argv
or return 1
if test -n "$_flag_help"
__wordle_helper_usage && return
end
if not string match -rq '^[A-z]{5}$' -- $argv[1]
echo >&2 "Expecting a 5-letter word argument. Got '$argv[1]'."
return 1
end
# Use standard dictionary, or whatever words were piped in.
set --local dictwords
if not test -t 0
while read --line word
if string match -qr '^[A-z]{5}$' -- $word
set -a dictwords (string upper $word)
end
end
else
set dictwords (cat $DICT_FILE | string match -re '^[A-z]{5}$' | string upper)
end
set --local guess (string upper -- $argv[1] | string split '')
set --local not_found_letters
# Make a regex like 'A..D.' for green (exact) matches (ex: wordle_helper -g 14 ABIDE)
set --local green_match (string split '' '.....')
for idx in (string split '' $_flag_green)
set green_match[$idx] $guess[$idx]
end
# Make a regex like '..[^I][^D].' for yellow (non-exact) matches to indicate where
# the charaters aren't, but also filter dict to only words with those letters.
set --local yellow_match (string split '' '.....')
for idx in (string split '' $_flag_yellow)
set yellow_match[$idx] "[^"$guess[$idx]"]"
set dictwords (string match -er $guess[$idx] -- $dictwords)
end
# Collect letters that aren't in the answer.
for idx in (seq 5)
if not contains $idx -- (string split '' $_flag_green $_flag_yellow)
set -a not_found_letters $guess[$idx]
end
end
# Regex filter on green, yellow, and not found.
string upper $dictwords | sort | uniq |
string match -er (string join '' $green_match) |
string match -er (string join '' $yellow_match) |
string match -er '^[^'(string join '' $not_found_letters)']+$'
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment