How to Make a Game Like Wordle in SwiftUI: Part One

Learn how to create your own Wordle word-game clone in SwiftUI. Understand game logic as you build an onscreen keyboard and letter tile game board. By Bill Morefield.

5 (5) · 4 Reviews

Download materials
Save for later
Share

Though it’s been around since the fall of 2021, the web game Wordle became popular in early 2022. For a time, you could barely scroll through social media without seeing your friend’s daily puzzle results. The simple rules make the game easy to pick up, and the variety of English words keeps the game challenging.

In case you missed or chose to ignore the game, the rules of Wordle are simple. Each day, the game presents a random five-letter English word for you to guess. You get six guesses to find the word, and all guesses must be valid English words. After each guess, the game evaluates each letter. It then tells you whether each letter isn’t in the word at all, is in the word but incorrectly placed or is correctly placed in position. If you get the word right in six guesses, you win. If not, Wordle tells you the correct word.

In this tutorial, you’ll design and implement a version of Wordle in SwiftUI called Guess the Word.

Getting Started

Download the project by clicking Download Materials at the top or bottom of this page. Open the project in the starter folder in Xcode. Have a look at the views, models and resources, then build and run. You’ll interleave building the model for the game with views that show the player these elements. Time to get to work!

Starting project with just the keyboard view

Guessing a Letter

The game consists of a game board and a keyboard used to enter letters. It also provides “Delete” and “Return” keys the player uses to confirm their guess. You can find the keyboard implemented in the KeyboardView.swift and KeyButtonView.swift files in the KeyboardViews group.

Each game shows the current and past guesses. After the user confirms a guess by tapping Enter, the game checks the guess against the target word. In this app, the Dictionary class loads a dictionary of five-letter words and provides access to it for the program.

First, you’ll implement the basic element of the game, the guessed letter. Open GuessedLetter.swift in the Models group. From the description, you can see you need a way to reflect the status of each letter after the player submits a guess. Above the declaration of the GuessedLetter struct, add the following code:

enum LetterStatus: String {
  case unknown = "Unknown"
  case notInWord = "Not in Word"
  case notInPosition = "In Word, But Not This Position"
  case inPosition = "Correct and In Position"
}

This enumeration contains a state for each possible outcome for a letter, including the initial unknown state before the player submits the guess. You provide a string for each state to describe the result.

Now, replace the contents of the GuessedLetter struct with:

var id = UUID()
var letter: String
var status: LetterStatus = .unknown

This struct contains the letter the player guesses and the status of the guess, which defaults to unknown.

Diagram of the items contained in the struct

Now that you have a struct to hold a guessed letter, you can update the view to show this letter, which you’ll do in the next section.

Displaying a Guessed Letter

Just like you started with the data model for the simplest element of the game, a GuessedLetter, you’ll now work on its related view. Open GuessBoxView.swift in the GameBoardViews group. This view shows the letters that make up each guess. It will show the player the letter and its status in an overall guess. Add the following properties at the top of the struct:

var letter: GuessedLetter
var size: Double
var index: Int

These hold the GuessedLetter to show along with a size for the view and the zero-based index of which guess you show. Now, replace the current placeholder view with:

Text(letter.letter)
  .font(.title)
  .frame(width: size, height: size)
  .cornerRadius(size / 5.0)

Next, replace the preview with:

let guess = GuessedLetter(letter: "S", status: .inPosition)
GuessBoxView(letter: guess, size: 50, index: 1)

Activate the preview and see the result.

Screen showing the letter S

This letter is from a checked guess so it should provide feedback to the player on the status of this guess. You’ll do that by adding color to the tile. First, open GuessedLetter.swift under the Models group and add the following computed property to the GuessedLetter struct:

var statusColor: Color {
  switch status {
  case .unknown:
    return .primary
  case .notInWord:
    return .gray
  case .notInPosition:
    return .yellow
  case .inPosition:
    return .green
  }
}

This method returns a Color based on the current status. An unknown letter uses the current primary color. A letter not in the word appears in gray, a letter in the wrong position appears in yellow and a letter in the correct position appears in green. Now, go back to GuessBoxView.swift and replace the body of the view with:

Text(letter.letter)
  .font(.title)
  // 1
  .foregroundColor(Color(UIColor.systemBackground))
  // 2
  .frame(width: size, height: size)
  // 3
  .background(letter.statusColor)
  // 4
  .cornerRadius(size / 5.0)

You show the letter for the guess in a Text view with the title font style. Then, you modify the Text view by:

  1. Setting the foreground color to the UIColor.systemBackground. This makes the text the same color as the current background color of the view.
  2. Setting the width and height of the view to the passed value.
  3. Setting the background color for the view to the color determined by the statusColor computed property you added in the previous step.
  4. Adding a corner radius to give the letter tile a nice, rounded appearance.

After being checked, the result clearly shows the letter and status of the guessed letter.

Screen showing the letter S in a green box

With the view to show the letters of each guess implemented, you can now move on to the player’s guess. You’ll do that in the next section.

Making a Guess

Just like each letter has a status, the guess as a whole also has a status. Open Guess.swift in the Models group and add the following above the Guess struct:

enum GuessStatus {
  case pending
  case complete
  case invalidWord
}

Until the player submits the guess, it will be pending. If the player doesn’t submit a valid word, it will be invalidWord. Once a valid word is checked, the guess is complete. Now, add the following code to the Guess struct:

var word: [GuessedLetter] = []
var status: GuessStatus = .pending

var letters: String {
  return word.reduce("") { partialResult, nextLetter in
    partialResult.appending(nextLetter.letter)
  }
}

A guess consists of an array of GuessedLetter structs that hold the guessed letters. You also store a status that defaults to pending. The letters computed property provides access to the letters in the guess as a string. The property uses the reduce method on the word array to concatenate each letter into a single string and return this value.

Diagram showing string of guessed letters

With the Guess implemented, you can now turn your attention to the view that displays it.