Live data from Hacker News

Best Wordle guessing strategy

slc.is

141–150 of 159 posts

Re: Best Wordle guessing strategy

#141
post #71
post #64

Do any bots incorporate the history of wordle words? Wordle never repeats previous words so I wonder if the “best Xth word to guess” could change at some point?

I would consider that cheating. If you consider a history you might get all past (as well as future) words from the source code. For example this Saturday's word will be panic.

No post body was provided.

Re: Best Wordle guessing strategy

#142
post #71
post #64

Do any bots incorporate the history of wordle words? Wordle never repeats previous words so I wonder if the “best Xth word to guess” could change at some point?

I would consider that cheating. If you consider a history you might get all past (as well as future) words from the source code. For example this Saturday's word will be panic.

I meant for a bot perspective.

Re: Best Wordle guessing strategy

#143

I modeled my Wordle solver[1] after Donald Knuth's Mastermind strategy[2]. An optimal guess is found by looking at the list of possible solutions and for each of those possible solutions checking how much each possible guess would narrow down the list of possible solutions. Once you have a list of all possible guesses and how much each of those possible guesses would narrow down the total number of possible solutions…

Thanks for sharing your code. I had seen other people also mention that these 5 guesses (AESIR, ARISE, RAISE, REAIS, SERAI) all narrow down the list to 168 (in the worst case), but I was curious why the code I wrote to play with this was giving different answers.

After reading your code, I see an error in it. In fact, only RAISE is optimal; the others are worse, and leave bigger lists (according to my code):

    RAISE: 168
    …
    REAIS: 203
    …
    AESIR: 220
    ARISE: 220
    …
    SERAI: 241
The error in your code is that your "evaluateGuess" function (right at the top, in the first 10 or so lines of https://github.com/christiangenco/wordlesolver/blob/9c3bd94a...):

    function evaluateGuess({ solution, guess }) {
      return [...guess].map((letter, index) => {
        return {
          letter,
          included: solution.includes(letter),
          position: letter === solution[index],
        };
      });
    }
is too simplistic, and not actually what the real game does. In the game, for each letter position, there are three possible responses:

• Correct (Green), what you call "position"

• Present (Yellow), what you call "included"

• Absent (Grey)

Here are three test cases, that you could try out on the real Wordle in recent days:

• When the solution is "FAVOR" and our guess is "ERROR", Wordle's response is [Grey, Grey, Grey, Green, Green] — note that for the first two Rs in "ERROR", the correct response is Grey (Absent), because the last R has already "used up" the "Green" response.

• When the solution is "FAVOR" and our guess is "ROARS", Wordle's response is [Yellow, Yellow, Yellow, Grey, Grey] — note that only the first R in "ROARS" gets a Yellow response and the second one gets Grey, because there's only one R in the solution.

• (As pointed out by @pedrosorio in a sibling comment) When the solution is "ABBEY" and our guess is "APNEA", Wordle's response is [Green, Grey, Grey, Green, Grey], but your solver thinks that the second "A" would get a "Yellow" response too.

You mentioned Donald Knuth's Mastermind paper; in fact in the paper (http://www.cs.uni.edu/~wallingf/teaching/cs3530/resources/kn...) Knuth points this out on the very first page:

> Rule 2 is somewhat difficult to state precisely and unambiguously, and the manufacturers have in fact not succeeded in doing so on the directions they furnish with the game […]

and gives an exact rule that you may want to study carefully.

In my code, the `response` function I use (it's not the most efficient, but we can just memoize it) is:

    def response(h, g):
        '''
        - The hidden word is h.
        - The guess is g.
        For each position in the word g, some color:
        - 'green' if in the same position
        - 'yellow' if present (after subtracting 'green's)
        - 'grey' if absent (after subtracting "green"s and "yellow"s)
        '''
        assert len(h) == len(g)
        L = len(h)
        green = [i for i in range(L) if h[i] == g[i]]
        yellow = []
        for i in range(L):
            # We want to check whether g[i] is "present" in h
            if i in green: continue
            for j in range(L):
                if j in green: continue
                if j in yellow: continue
                if h[j] == g[i]:
                    yellow.append(i)
                    break
        return (green, yellow)

Note the three "continue" statements — they are crucial, to match the behaviour of the real Wordle (or Master Mind) on the three test cases I mentioned above.

Re: Best Wordle guessing strategy

#144
post #51

Earlier quoted context omitted.

This is pretty much what I did, but I mixed in a regexp to hold the location restrictions, and a penalty for using the same letter multiple times. (eg guessing “added” is worse than “aspen” for “a..e.”) I do wonder if looking at how a letter splits the space of letters and words would be interesting

Yeah, I wasn't sure how I wanted to deal with duplicates so I mostly ignored them. I track letter positions directly (just a bunch of tuples), but don't actually do anything with this other than restricting candidates words. I think if I work on this some more I'd try to factor in letter positioning when deciding what to guess. My hunch is that it won't make too much of a difference though.

So I tried an experiment using 15,918 five letter English words. I used a basic scoring strategy of scoring a word by summing up the frequency of the candidate letters in the candidate words as determined by a regexp of included and excluded letters. (e.g. `.aves` would score `waves` 1, but `saves` as 0 since `s` is already included)

Variations included adding in the frequency of the letter at a particular position, and adding in the frequency of two letter combinations.

Interestingly enough, the winning strategy was using single letters and using figuring in the position. Second second best was using two letters and position.

ngram=1 posfreq=True mean attempts: 4.34 WinPct 91.280%

ngram=2 posfreq=True mean attempts: 4.35 WinPct 91.186%

ngram=2 posfreq=False mean attempts: 4.37 WinPct 90.074%

ngram=1 posfreq=False mean attempts: 4.38 WinPct 90.445%

Since my base dictionary is way bigger than the Wordle one, I also mixed in a smaller 1,382 word dictionary (google-10000-english.txt) and then combined them by either just sorting by the score, or normalizing the scores, and then sorting. Normalizing the scores was strictly worse.

normalize=False ngram=1 posfreq=True mean attempts: 4.34 WinPct 91.280%

normalize=True ngram=1 posfreq=True mean attempts: 4.43 WinPct 90.281%

FWIW, the absolute worse one was:

normalize=True ngram=1 posfreq=False mean attempts: 4.43 WinPct 89.835%

I should write this up.

Re: Best Wordle guessing strategy

#145

5.291 soare 5.294 roate 5.299 raise 5.311 raile 5.311 reast 5.321 slate 5.342 crate 5.342 salet 5.345 irate 5.346 trace 5.356 arise 5.360 orate 5.370 stare 5.382 carte 5.390 raine 5.400 caret 5.402 ariel 5.406 taler 5.406 carle 5.407 slane Shown are the twenty best initial guesses using Claude Shannon's definition of information entropy. Each number is the expected number of yes/no questions needed to resolve the rem…

Maximising the information gained using Shannon's entropy is a very good strategy (assuming the goal is to minimise the expected number of guesses), however it is not necessarily optimal!

I have a counter example for a simplified version the game with the following rule changes:

1. The player is only told which letters in the guess are correct (i.e. they are not told about letters that are present but in a different location).

2. If the player knows there is only one possible solution, the player wins immediately (without having to explicitly guess that word).

3. The set of words that the player is allowed to guess may be disjoint from the set of possible solutions.

Here is the list of possible solutions:

    aaaa
    aaab
    aaba
    babb
    abaa
    bbab
    bbba
    bbbb
(There are 8 words. The 2nd, 3rd and 4th letters are the binary patterns of length 3, and the 1st letter is a carefully chosen "red herring".)

Here is the dictionary of words the player is allowed go guess:

    axxx
    xaxx
    xxax
    xxxa
(Each guess effectively lets the player query a single letter of the solution.)

The information gain for each possible initial guess is identical (all guesses result in a 4-4 split), so a strategy based on information gain would have to make an arbitrary choice.

If the initial guess is axxx (the "red herring"), the expected number of guesses is 3.25.

But a better strategy is to guess xaxx (then guess xxax and xxxa). The expected number of guesses is then 3.

(In this example information gain was tied, but I have a larger example where the information gain for the "red herring" is greater than the information gain for the optimal first guess.)

Re: Best Wordle guessing strategy

#146
post #145

5.291 soare 5.294 roate 5.299 raise 5.311 raile 5.311 reast 5.321 slate 5.342 crate 5.342 salet 5.345 irate 5.346 trace 5.356 arise 5.360 orate 5.370 stare 5.382 carte 5.390 raine 5.400 caret 5.402 ariel 5.406 taler 5.406 carle 5.407 slane Shown are the twenty best initial guesses using Claude Shannon's definition of information entropy. Each number is the expected number of yes/no questions needed to resolve the rem…

Maximising the information gained using Shannon's entropy is a very good strategy (assuming the goal is to minimise the expected number of guesses), however it is not necessarily optimal! I have a counter example for a simplified version the game with the following rule changes: 1. The player is only told which letters in the guess are correct (i.e. they are not told about letters that are present but in a different…

Interesting. There can't be a proof of general optimality for Shannon entropy, because the words are irregularly distributed. However, (unlike your lists) they're not distributed by an adversary trying to foil Wordle/Jotto strategies.

I suspect a law of large numbers / central limit theorem type result that Shannon entropy is asymptotically optimal for randomly chosen lists, even those generated by state machines like gibberish generators that nearly output English words. In other words, I conjecture that your configurations are rare for long lists.

Early in my career, I was naive enough to code up Grobner bases with a friend, to tackle problems in algebraic geometry. I didn't yet know that computer scientists at MIT had tried random equations with horrid running times, and other computer scientists at MIT had established special cases with exponential space complete complexity. Our first theorem explained why algebraic geometers were lucky here. This is a trichotomy one often sees: "Good reason for asking" / "Monkeys at a keyboard" / "Troublemakers at a demo".

Languages evolve like coding theory, attempting a Hamming distance between words to enhance intelligibility. It could well be that the Wordle dictionary behaves quasirandomly, more uniformly spaced that a true random dictionary, so Shannon entropy behaves better than expected.

Re: Best Wordle guessing strategy

#147
post #143

I modeled my Wordle solver[1] after Donald Knuth's Mastermind strategy[2]. An optimal guess is found by looking at the list of possible solutions and for each of those possible solutions checking how much each possible guess would narrow down the list of possible solutions. Once you have a list of all possible guesses and how much each of those possible guesses would narrow down the total number of possible solutions…

Thanks for sharing your code. I had seen other people also mention that these 5 guesses (AESIR, ARISE, RAISE, REAIS, SERAI) all narrow down the list to 168 (in the worst case), but I was curious why the code I wrote to play with this was giving different answers. After reading your code, I see an error in it. In fact, only RAISE is optimal; the others are worse, and leave bigger lists (according to my code): RAISE: 1…

The testcases notwithstanding, I found a bug in my code as well. Fixed my `response` function to:

    def response(h, g):
        assert len(h) == len(g)
        L = len(h)
        correct = [i for i in range(L) if h[i] == g[i]]
        present_h = []
        present_g = []
        for i in range(L):
            # We want to check whether g[i] is "present" in h
            if i in correct: continue
            for j in range(L):
                if j in correct: continue
                if j in present_h: continue
                if h[j] == g[i]:
                    present_g.append(i)
                    present_h.append(j)
                    break
        return (correct, present_g)
and now I too get (AESIR, ARISE, RAISE, REAIS, SERAI) all leaving 168 words. (But the testcases in the above comment still hold, though, make sure your code works for them.)

Re: Best Wordle guessing strategy

#148
post #51

Earlier quoted context omitted.

Yeah, I wasn't sure how I wanted to deal with duplicates so I mostly ignored them. I track letter positions directly (just a bunch of tuples), but don't actually do anything with this other than restricting candidates words. I think if I work on this some more I'd try to factor in letter positioning when deciding what to guess. My hunch is that it won't make too much of a difference though.

So I tried an experiment using 15,918 five letter English words. I used a basic scoring strategy of scoring a word by summing up the frequency of the candidate letters in the candidate words as determined by a regexp of included and excluded letters. (e.g. `.aves` would score `waves` 1, but `saves` as 0 since `s` is already included) Variations included adding in the frequency of the letter at a particular position,…

Which solution list did you use to calculate the mean attempts?

Another comment mentioned https://botfights.io/game/wordle, if you evaluate your solver on their word list you could compare scores.

Re: Best Wordle guessing strategy

#149

5.291 soare 5.294 roate 5.299 raise 5.311 raile 5.311 reast 5.321 slate 5.342 crate 5.342 salet 5.345 irate 5.346 trace 5.356 arise 5.360 orate 5.370 stare 5.382 carte 5.390 raine 5.400 caret 5.402 ariel 5.406 taler 5.406 carle 5.407 slane Shown are the twenty best initial guesses using Claude Shannon's definition of information entropy. Each number is the expected number of yes/no questions needed to resolve the rem…

[deleted]

Re: Best Wordle guessing strategy

#150
post #145

Earlier quoted context omitted.

Maximising the information gained using Shannon's entropy is a very good strategy (assuming the goal is to minimise the expected number of guesses), however it is not necessarily optimal! I have a counter example for a simplified version the game with the following rule changes: 1. The player is only told which letters in the guess are correct (i.e. they are not told about letters that are present but in a different…

Interesting. There can't be a proof of general optimality for Shannon entropy, because the words are irregularly distributed. However, (unlike your lists) they're not distributed by an adversary trying to foil Wordle/Jotto strategies. I suspect a law of large numbers / central limit theorem type result that Shannon entropy is asymptotically optimal for randomly chosen lists, even those generated by state machines lik…

For the entropy strategy, the expected number of guesses on the full dictionary (allowing all 12972 words as possible solutions) is 4.233 (54910/12972)* according to my tests.

The best score on https://botfights.io/game/wordle is currently 4.044 (4044/1000).

*Spoiler: The score of the entropy strategy can be improved to 4.086 (53007/12972) by tweaking the entropy formula as follows: Let n be the number of possible solutions and let ki be the size of the i-th partition after the current guess. The usual entropy formula is sum{pi * -log(pi)} where pi = ki / n. The improved formula is sum{pi * -log((ki+1) / n)}. This formula aligns more closely with the expected number of guesses required to solve small partitions.

Post reply on HN