multi colored paper on brown cardboard box

100 Days of SwiftUI – Project 2: Guess the Flag

In the second project of the course we’re shown how to create a completely custom-looking UI with the built-in functionality of SwiftUI.

Over the course of this 3 day project we’re introduced to VStack, HStack and ZStack as well as Color, different kinds of gradient, frames, buttons and how to show alerts – so quite a lot really!

This is all pulled together into a game where the user is shown a country name and three flags then needs to tap the correct one. Although it is a pretty simple game, it’s still engaging enough. It’s surprising just how much you can achieve with very little code.

Challenge

After completing the project we have 3 challenges to complete to extend the game.

Scoring

First we add score tracking to the app. This is achieved with a new @State property named score which is initially set to 0 and then incremented within the flagTapped method if number == correctAnswer.

func flagTapped(_ number: Int) {
  if number == correctAnswer {
      scoreTitle = "Correct"
      score += 1
  } else { ...

There’s also a couple of places in the code that Paul has us write Score: ???. We replace ??? with \(score) to correctly interpolate the actual score into these labels.

Wrong answer message

We’re asked to enhance the message displayed when the user selects the wrong flag to inform them of the correct answer. This is a simple one-line change in the flagTapped method where the scoreTitle text is set where we interpolate the name of the flag the user tapped.

func flagTapped(_ number: Int) {
  if number == correctAnswer {
      scoreTitle = "Correct"
      score += 1
  } else {
      scoreTitle = "Wrong! That's the flag of \(countries[number])"
  } ...

Question limit and final score

Our last challenge is to limit the quiz to 8 questions and then display a final score to the user.

We’ll need another couple of @State properties for this. First is questionsAsked which is an Int initialised to 0 that we’ll use to count how many questions are asked. We’ll also need a Bool called endOfGame, set to false, which we’ll use to trigger the final alert message. Finally, I need a new method called resetGame which puts everything back to their initial state and randomises the countries array and correctAnswer again for a new game.

At the end of the outer VStack I add an alert trigger for endOfGame that shows the final score and calls resetGame.

.alert("Game over", isPresented: $endOfGame) {
    Button("Start again", action: resetGame)
} message: {
    Text("Your final score is \(score)!")
}

The flagTapped method is amended to increment questionsAsked each time it’s called.

func flagTapped(_ number: Int) {
    if number == correctAnswer {
        scoreTitle = "Correct"
        score += 1
    } else {
        scoreTitle = "Wrong! That's the flag of \(countries[number])"
    }
    
    showingScore = true
    questionsAsked += 1
}

I also need to amend the askQuestion method to check the value of questionsAsked and then either trigger the endOfGame alert or ask another question depending on whether we’ve asked the user 8 questions or not.

func askQuestion() {
    if questionsAsked == 8 {
        endOfGame = true
    } else {
        countries.shuffle()
        correctAnswer = Int.random(in: 0...2)
    }
}

Last, but not least, is my resetGame method.

func resetGame() {
    score = 0
    questionsAsked = 0
    countries.shuffle()
    correctAnswer = Int.random(in: 0...2)
}

Phew! That was quite a lot of change but now we have a better gaming experience with scoring, a game over screen and a reset.

Complete solution

Guess the Flag on GitHub