# Reverse Engineering Wordle
# 1/9/2022
You've probably seen a lot of your friends share their Wordle emoji grids these past few weeks. It's a game, akin to Mastermind, that has gone viral for its simplicity yet challenge. I was curious how the game worked so I decided to pick apart the source code and see what it was doing. Read on to learn about how I was able to reverse engineer the algorithm and get the right answer on the first try, every time.
# Looking for Network Requests
The first thing I did was fire up the browser dev tools and watch the network requests. My default assumption was that there was a central server that the UI would interact with to submit answers to the word of the day. I clicked through and submitted a guess and, to my surprise, I didn't see any network requests. This meant that the word of the day was either embedded in the original page load or derived some other way.
# Looking at the source
I hopped over to Chrome's sources view and searched for the current word of the day gorge
. I had one hit: gorge
was in a static array that stored 2,315 words. So this was the wordlist itself! Now, we know which words are in the wordlist and which are not. The wordlist was assigned to a variable name that was a bit cryptic - La
. It seems like many of the variables are given names that are not descriptive at all to make it a bit more difficult to read.
So at this point I knew the following:
- Wordle doesn't make any web requests when verifying your answer - Everything is client-side.
- The word of the day doesn't get embedded in page load - It's derived from the wordlist somehow.
The next step was looking for references to the La
variable, which I'll refer to as the wordlist
variable going forward. The great news is there was only one function that used the wordlist. This function was equally ambiguously named Da()
.
function Da(e) {
var a, s = Ga(e);
return a = s % wordlist.length, wordlist[a]
}
This function does a few things: It calls another generic function Ga()
with a parameter then takes the result of that and uses it to index into the wordlist. So now we need to figure out two things:
- What does
Ga()
do? - What parameter does Da take?
We'll investigate Ga
first. Conveniently, Ga()
was immediately below Da()
.
function Ga(e) {
return Na(Ha, e)
}
Fun! Yet another function and a new mystery variable, Ha
. After some searching again, I found Ha
is assigned to a static date.
var Ha = new Date(2021,5,19,0,0,0,0);
My assumption is that this is the launch date for Wordle. Now turning our attention to Na, I searched yet again and found it.
function Na(e, a) {
var s = new Date(e)
, t = new Date(a).setHours(0, 0, 0, 0) - s.setHours(0, 0, 0, 0);
return Math.round(t / 864e5)
}
Woohoo! No more nested ambiguity! This function calculates the number of days between two dates provided to it and rounds to a whole integer. Now we know that Wordle is using Ha
to calculate the days between the dates. Now that we know the whole call chain of Ga()
, we can circle back to figure out what parameter Da()
takes.
With just one more quick search, I was able to quickly find that Da
was being passed a parameter that was likely a date type, and the result of Da was being assigned to the solution
property.
e.solution = Da(e.today),
How is e
assigned?
e.today = new Date;
# Putting it all together
At this point, we've done enough digging to know how Wordle is choosing the word of the day. We know that Wordle uses a client-side date-based algorithm to determine which word to use from a static wordlist. Each day is predictable so long as we have all of the code pieced together
So what is tomorrow's word?
query