Work

Wordle Clone

Frontend
Mobile
Dev

I reverse engineered and built a Wordle clone using React Native.

Screenshot of the Wordle application running on iOS

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:

  1. The row currently being used for guessing shakes when the guess isn’t a valid word
  2. 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.