Wordle or how to win in 6 moves

An example of a real game in one of the applications
An example of a real game in one of the applications

Recently I came across a fairly well-known game – Wordle. The essence of the game is for six attempts to guess a random word of five letters, while after each attempt the letters are painted in different colors depending on how close you are. A gray letter means that the given symbol is not in the word, an orange letter means that the letter is present, but it is in a different place, and a green letter means that the letter is correctly located.

I was immediately interested in whether the game is deterministic, whether it is possible to develop a strategy that will always allow you to guess the intended word in no more than six attempts. With that thought in mind, I started playing around to test the mechanics.

If you don’t try, you won’t know

The first thing I tried was to enter a combination of letters from the most popular letters of the English alphabet, but it turned out that only existing words are counted. I had to more reasonably approach the solution of the problem, and remember the five-letter nouns. As it turned out, this was the most difficult part of the game, as either six-letter words came to mind (unfortunately), or trying to remember a word with certain letters could take an obscene amount of time.

After a couple of games, I compiled my list of favorite words: TANGO, WEIRD, BLOCK and JUMPS, which covered 19 different letters of the English alphabet and 5 vowels out of 6. The choice of these words is not justified by logic, but rather by a random combination of circumstances and associations generated by my imagination . However, the combination seemed so successful to me that I decided that with it I could identify any word. After discussing this theory with friends, we managed to improve the set by replacing TANGO with TANGY, thus covering 20 unique letters and all vowels.

After spending a little more time playing with these 4 words, and using combinatorics to determine the hidden word, I decided to proceed with a full-fledged proof, because even after playing hundreds of games it will not be possible to say with certainty that this strategy guarantees victory.

But what about the code?

I decided to choose the most boring proof – to check all possible options. Unfortunately, I couldn’t find the word list of the original game, so I used my ingenuity. After a couple of search queries, I found a useful site that helps to give out possible solutions for Wordle from a list of “good” and “bad” letters. Digging into their API, I made a custom query looking for all possible 5-letter words with a 20,000 word limit to ignore pagination. For those who are interested, here call. There were 2315 words in total.

Then the matter is small, I went through each of the words and calculated what result of the green and orange letters I would get after entering my “magic” combination:

const SUCCESS_STATUS = 's';
const WARNING_STATUS = 'w';
const INITIAL_WORDS = ['tangy', 'weird', 'block', 'jumps'];

// получаем из слова объект букв с зеленым или желтым статусом
const parseWord = world => {
  return [...world].reduce((mapping, letter, index) => {
    const initialWord = INITIAL_WORDS.find(initialWord => initialWord.includes(letter));
    // если буквы нет во введенных нами словах
    if (!initialWord) {
      return mapping;
    }

    // находится ли буква на своем месте
    const status = initialWord.indexOf(letter) === index ? SUCCESS_STATUS : WARNING_STATUS;
    
    // объединяем с предыдущими значениями
    return { ...mapping, [letter]: status };
  }, {});
};

// получаем ключ, уникальный для каждой комбинации букв со статусами
const getHashFromMapping = mapping => {
  return Object.entries(mapping)
    // сортируем буквы для гарантирования равенства
    // { a: 's', b: 'w' } и { b: 'w', a: 's' }
    .sort(([letter1], [letter2]) => letter1.charCodeAt(0) - letter2.charCodeAt(0))
    .map(([letter, status]) => `${letter}-${status}`)
    .join('|');
};

It remained to understand whether there are words, and if so, how many of them, which will have the same hash, which means they cannot be uniquely determined after 4 attempts (spoiler, yes). Let’s clarify right away that if there are only two words with the same hash, then you can definitely guess the correct one for the 5th and 6th attempt, respectively, which means that we are only interested in combinations of three or more words.

// опять достаточно простой вариант кода, чтобы это посчитать
const main = (words) => {
    const hashCounts = words.reduce((result, word) => {
        const mapping = parseWord(word);
        const hash = getHashFromMapping(mapping);
        // сохраняем список слов для каждого хэша
        const values = result[hash] || [];

        // используем Object.assign вместо ...result для повышения производительности
        // т.к. ...result будет пересоздавать объект каждый раз
        return Object.assign(result, { [hash]: [...values, word] })
    }, {});
  
  // вычисление любой интересующей статистики из hashCounts
};

After running the script on our dataset, it turned out that for 2315 five-letter words:
Unique hashes that uniquely name a word – 1999
Hashes with exactly two words – 119
Hashes with exactly three words – 19
Hashes with exactly four words – 4
Hashes with five words or more – 1

The first two categories are not of interest to us, since in six attempts we are guaranteed to name a word, but for three or more words, I decided to manually check for one hash.
The cases turned out to be simple when there was a letter that was in the same place only in two words out of three, then by entering one of these words, it was possible to determine the hidden word by the color of the common letter on the fifth attempt. If the word matched, we guessed, if not, but the common letter is green, then the word that contains it, otherwise, the remaining one. Below are examples and the word that is entered on the fifth attempt.

// в каждой строке слова с одинаковым хэшем и через | проверочное слово
hazel,halve,valve | halve
bezel,bevel,belle | bevel
fixer,river,eerie | river
graze,grave,agree | grave
shaft,staff,stash | staff
avail,flail,villa | flail
earth,hater,eater | hater
false,salve,easel | salve
filer,liver,rifle | liver
filet,lithe,title | lithe
frail,rival,viral | rival
lathe,valet,latte | lathe
loath,allot,total | loath
stave,asset,state | stave
puree,purer,rupee | purer
ester,reset,steer | ester

The situation is similar for hashes with 4 or more words, one word from the list can either be randomly guessed or the hidden word can be unambiguously determined on the 6th attempt, although the logic is a little more complicated.

fever,verve,freer,refer        | freer
hover,offer,rover,error        | rover
horde,odder,order,rodeo        | order
forte,other,voter,otter        | voter
fresh,serve,sever,sheer,verse  | verse

As you can see, the lists above are missing 3 hashes that give interesting combinations of words – the last four letters in each combination are the same and only the first character differs. For them, I separately selected the fifth check word, which helps to check which of the first characters is still contained in the search word

// Пример, вводя слово fever
// если оранжевая f, то искомое слово focal
// если оранжерая v, то искомое слово vocal
// если ни f, ни v не оранжевые, то искомое слово local
focal,vocal,local | fever
viper,piper,riper | privy
haunt,vaunt,taunt | vouch

And what is it all for?

Thus, by a rather rough method, but I managed to make sure that there is still a strategy for the Wordle game that always leads to victory (at least on the dataset used).

This knowledge is unlikely to bring much benefit, but I received moral satisfaction, stretched my brain a little, thinking about strategies and remembering words, and now I share it with you. I hope this puzzle is at least a little interesting for you, or maybe you can find a counterexample when this strategy does not work and share it.

Thank you for your attention.

Similar Posts

Leave a Reply Cancel reply