Source code: wordle-clone
Wordle Clone
In this project, I reverse-engineered Wordle and built my own using React native.
How Wordle works
Wordle is a game where users have to guess a certain 5-letter word in 6 tries or less. The words have been pre-determined, and every single day, people have to play the game to all guess the same word. This can be a lot of fun, especially when the word is obscure yet someone guessed it on their first try.
These are the rules of the game:
- The player has 6 tries to guess the word
- For each letter in the guess’s the following coloring is applied:
- Green: The letter is in the word and in the correct position
- Yellow: The letter is in the word but in the wrong position
- Blank: The letter is not in the word
How I built it
I built the game using React Native and Expo. I used the Expo CLI to create the project, and I used the Expo Go app to run the app on my phone.
These were the primary components which made up the bulk of the code:
- Checking the guess
- Animating guesses and checks
Checking the guess
Checking the guess sounds simple enough at first right? For each letter in the user’s guess, first check to see if the letter is in the word. If it is, then check to see if it’s in the correct position. If it is, then color the letter green. If it’s not, then color it yellow.
The tricky part with this was handling the case when the user guesses the same letter twice.
In this case, you must first check to see that the letter hasn’t already been used correctly somewhere else,
and that there is still a space for the letter. The problem essentially occurs
when there are n
occurrences of the same letter in the word, and the user guesses the letter >=n
times.
To solve this, I used a Set
to keep track of the letters that have been used correctly.
I also used a Map
to keep track of the number of occurrences of each letter in the word.
This allowed me to check to see if the letter had already been used correctly, and if there
was still a space for the letter.
If the user had already used all possible instances of the letter, then any additional submissions must be colored blank.
Animations
In wordle, there are two primary animations that occur:
- The row currently being used for guessing shakes when the guess isn’t a valid word
- Each of the tiles are revealed in a stutter animation when the user checks their guess and it is a valid word
Shaking the row
To handle the row shaking animation, I created an empty list of guesses which
would have the first element be the user’s guess that gets written to.
I would have these empty guesses rendered and pass down an activeRowAnimationTranslation
reference to the current row. When the word wasn’t valid, I would have a function
trigger the animations like the following:
const shakeRowAnimation = () => {
const bounds = 5;
const animationDuration = 50;
const animationSequence = [];
const numShakes = 3;
for (let i = 0; i < numShakes; i++) {
animationSequence.push(
Animated.timing(activeRowTranslation, {
toValue: bounds,
useNativeDriver: true,
duration: animationDuration,
// easing: Easing.bounce,
}),
Animated.timing(activeRowTranslation, {
toValue: -bounds,
useNativeDriver: true,
duration: animationDuration,
// easing: Easing.bounce,
})
);
}
animationSequence.push(
Animated.timing(activeRowTranslation, {
toValue: 0,
useNativeDriver: true,
duration: animationDuration,
// easing: Easing.bounce,
})
);
Animated.sequence(animationSequence).start();
};
Animating the Tiles
Animating the tiles as the user’s guess is revealed is a bit more complicated. Since this animation involves the user’s unpainted tiles (blank) being flipped into their proper colors, you must have a way of keeping track of the tiles that have been flipped.
Since this animation only happens once, namely when the result is first revealed,
I added a reveal
property to the WordleRow
component which would be checked
by a useEffect
hook. If the reveal
property was true, then the animation would
be triggered.
To go one step further, you also need an animation where all of the tiles bounce up and down when the user has guessed the word correctly. This bounce happens after the reveal, so it’s a composite staggered animation. This is still easily handled in React Native, since animations themselves are composable.
Final Thoughts
React Native is super fun to work with, and I’d love to create more apps in it in the future. I tried uploading this app to the app store, but it was rejected for being a clone of another app.
There are other features which could be added, so maybe I’ll come back to this project at some point.