⬜️ Hacking WORDLE 🟩
My curiosity got the better of me and I ruined the game for myself
Wed Jan 19 2022
WORDLE, a word jumble game, has been rocketing in populartiy amongst young adults on the internet since late 2021 and January of 2022. I was first introduced to the game by a colleague in January and I quickly became hooked. It's a really fun puzzle game, but what made it even more fun and alluring was that there was only one word to guess every single day.
My curiosity got the better of me and I decided to go digging to see if I could figure out how the game was implemented. I expected to find obfuscated API calls that hide the solutions from nosey people like me, clues as to some features that may be hidden or that were in progress, a bug or 2 that I could report to the creator to help contribute to the project, but what I found was even more surprising.
I discovered that the game's implementation was simple... like really really simple.
A quick rundown on how WORDLE is currently implemented
Every day, at the stroke of midnight, there's a new solution to the daily puzzle. "Where does this word come from?", you might ask. Well, it just comes from the word bank, embedded directly in the game. Looking at the code, there are actually 2 interesting word banks. The first, is the list of valid words. It's a big list too: there are 10657 valid words that WORDLE will accept. However, the second is the more interesting one. this list is the list of all our puzzle solutions, 2315 words to be exact.
The first thing that I noticed about the list of solutions is that they're not sorted in alphabetical order like our list of acceptable words. No, the list of solutions looked to be in an intentional order.
The order, turns out to be the solutions for each game, day by day. To find out our solution for the day, all we need to do is find out how many days have past since the games' inception (May 19, 2021) and then go to that index in our list of game solutions. The code looks something like this:
const list_of_solutions = [...] # May 19, 2021 const date_of_inception = new Date(2021, 5, 19, 0, 0, 0, 0) # How many days have past since the day of inception? const days_past_in_utc = new Date().setHours(0,0,0,0) - new Date(date_of_inception).setHours(0, 0, 0, 0) # `864e5` is the number of milliseconds in a day const game_day = Math.round(days_past_in_utc / 864e5) # Voila! our solution for the day: const solution = list_of_solutions[game_day]
Surely that can't be it right? The game saves my score and keeps track of my guesses! Well, yes, but again, it's trivial. All of your progress is stored in your browsers localstorage, so it lacks any sort of integrity. Modifying your stats is as simple as popping open the console and editing it in place.
I don't mean to shit on the guy from Brooklyn that made WORDLE; he didn't intend for it to get this big as far as I'm aware. I thought about ending my blog post here since after a few minutes of reading through the front end code, I had entirely reverse engineered the game. But I thought that might be boring and instead I'd like to do 2 more things...
What's the actual best starting word?
Doing a simple analysis of the letter frequency in the list of puzzle solutions, you get the letter frequency distribution, below. And just like Tyler Glaiel wrote here, the best word to guess to uncover the most frequently used letters (EAROT), would be to guess ROATE.
However, ROATE is currently not in the list of solution words. If we want to guess a word that could appear as a solution, then look no further than the solution for the day 873 puzzle: LATER. LATER is the best word to start with to narrow down the most common letters, while also potentially guessing the solution on your first word. That being said, there's a 1/2315 chance of you guessing correctly on your first try with LATER as your first guess.
Here's how I'd build WORDLE 💭
My current issue is not that WORDLE is necessarily built poorly, but that it's too easy to poke around like I've just done. Nosey tech savvy people like myself can cheat or ruin it for ourselves too easily. Building WORDLE with a different perspective could really improve the game for everyone. I would model it after the very popular programming challenge that takes place in December: Advent of Code.
1. Make sure all the future solutions are unavailable.
Instead of having all the solutions hardcoded into the JS bundle that runs the game, hide them on your server and don't allow them to be accessed by the client. This way, the mystery for tomorrow and the following days stays alive.
2. Don't load the solution to the client
Similar to 1, keep the solution away from the user. The user should make guesses to the server and the server should then respond back with how close you are to the solution. With a model like this, you now don't have to worry about people manipulating their guesses. In the frontend and you can verify, better, the guesses that each user makes.
3. Authenticate your users
It doesn't have to be fancy, but at least you'll be able to have some sort of integrity this way. Authenticating users creates other opportunities to build leaderboards too, which I've thought could be really fun for groups who play together, like families, groups of friends, or in my case, colleagues.
Since part of the fun is that everyone has the same solution for the day, you can't really ensure that people aren't taking others' solutions. You also can't make sure that people aren't going to try to break the game and inadvertently ruin it for themselves... But there's opportunity to make the game more fun and more competitive.
Anyways, go play WORDLE – it's super fun and wholesome. Remember, it's just a game so have fun and don't take it too seriously. And Josh, if you're looking to build a WORDLE V2, I'd love to collab.
Thanks for reading and hopefully I see you soon 😊