Dyota's blog

Power Query: Wordle cheat!

Warrior in the garden

Have you heard this saying before?

"It is better to be a warrior in a garden than a gardener in a war".

One who knows how to war and chooses not to do it is peaceful; one who doesn't war because he doesn't know how to is helpless. I wonder if it applies just as well at games and cheating - is it better to know to how to cheat but choose not to, rather than not know how to cheat at all?

I've made a tool to cheat at Wordle and some days I like to pretend I'm the warrior in the garden.

Anyway, all pretense aside, I actually did find this fun. PowerShell and Power Query are my tools of choice at the moment and this is a good way of having fun with them.

Steps

  1. Get the word list
  2. Extract the word list into a data file
  3. Set up spreadsheet
  4. Write logic

Get the word list

TL;DR: The JavaScript source code is here.

I already knew from a friend that the full word list is in the source code itself. The first step is finding out where the source code lives.

If you just view the source for the main Wordle website.

You need to scan the file, ignore all of the ads and other junk, and find the file main.5d21d0d0.js.

It turns out that NYT sometimes moves their files and links around. At this time of writing (October 2022), the JavaScript code is here

Extract the word list

Once you get the .js file, save it somewhere.

This PowerShell script will fetch just the words and save them in a file called words.txt (you'll need to change the filename if your target filename isn't wordle-main.js).

using System.Collections;

$root = "" # put your folder location here

(Get-Content "$root\wordle-main.js")[0] -match "(?<=ke=\[).*?(?=\])";
$raw = $matches[0]

$split = $raw -split ','

[ArrayList] $wordlist = @()

$split |
    % {
        $withoutQuotes = $_ -replace '"', ''
        [void] $wordList.Add($withoutQuotes)
    }

$wordList > "$root\words.txt"

Code

Here is all of the Power Query code.

include, exclude, and lock are one-column tables. lock should only have 5 rows, only (this column represents that positions of letters that you definitely know to be correct, i.e. are green).

words is the output file. It will show you all of the possible words that matches the pattern of included, excluded, and locked letters.

thisFile

let
    Source = Excel.CurrentWorkbook()
in
    Source

raw

This takes in the file "words.txt" and uses it as a List.

let
    Source = Table.FromColumns({Lines.FromBinary(File.Contents("C:\Users\dyota\OneDrive\Projects\Power Query\Wordle cheat\words.txt"), null, null, 1252)}),
    Column1 = Source[Column1]
in
    Column1

words

let
    textContainsList = (reference as list, word as text, optional extent as nullable number) as logical => 
        let
            selection = (if extent = 0 then List.AllTrue else List.AnyTrue)
        in
            selection(
                List.Transform(
                    reference,
                    each Text.Contains(word, _)
                )
            ),

    indeces = List.Buffer({0..(List.Count(lock)-1)}),

    lock = List.Buffer(lock),

    filters = List.Select(
        raw, 
        each 
            let 
                word = _
            in
                textContainsList(include, word, 0)
                and List.AllTrue(
                    List.Select(
                        List.Transform(
                            indeces, 
                            (_) => 
                                let 
                                    thisLetter = lock{_}
                                in
                                    if thisLetter = null or Text.Trim(thisLetter) = "" 
                                    then null 
                                    else thisLetter = Text.At(word, _)
                        ),
                        each _ <> null
                    )
                )
                and not textContainsList(exclude, word)
    )
in
    filters

include

let
    Source = thisFile,
    include = Source{[Name="include"]}[Content],
    #"Changed Type" = Table.TransformColumnTypes(include,{{"Include", type text}}),
    Include = List.Select(
        #"Changed Type"[Include],
        each not (_ = null)
    )
in
    Include

exclude

let
    Source = thisFile,
    exclude1 = Source{[Name="exclude"]}[Content],
    #"Changed Type" = Table.TransformColumnTypes(exclude1,{{"Exclude", type text}}),
    Exclude = List.Select(
        #"Changed Type"[Exclude],
        each not (_ = null)
    )
in
    Exclude

lock

let
    Source = thisFile,
    lock1 = Source{[Name="lock"]}[Content],
    #"Changed Type" = Table.TransformColumnTypes(lock1,{{"Lock", type text}}),
    Lock = #"Changed Type"[Lock]
in
    Lock

#excel #powerquery