UPGRADE YOUR SKILLS: Learn advanced Swift and SwiftUI on Hacking with Swift+! >>

Trouble understanding code's logic in Guess The Flag

Forums > 100 Days of SwiftUI

In project 2: part 2, Paul delves into the logic for checking whether the correct flag has been tapped, but in all honesty this feels a bit like black magic to me for a couple reasons:

  1. The flag's text is displayed in the following:
Text(countries[correctAnswer])
                        .foregroundStyle(.white)
                        .font(.largeTitle)
                        .bold()
                }
  1. Once the text is displayed, we display three flags with a ForEach loop using a number variable:
ForEach(0..<3) { number in
                    Button {
                        flagTapped(number)
                    } label: {
                        Image(countries[number])
                    }
  1. To check that the number matches the initial index, Paul instructs us to use a method that compares the number variable with correctAnswer(a random integer).
func flagTapped(_ number: Int) {
        if number == correctAnswer {
            scoreTitle = "Correct"
        } else {
            scoreTitle = "Incorrect"
        }
        showingScore = true
    }

My question most revolves around how the flag's text is able to properly display itself in the ForEach loop. How does the code know to display both the text and flag for Germany, for example? And why does that method above claim to answer my question (when in reality it doesn't because I'm still left wondering how two different pieces of code can do the same thing, if that makes sense).

TLDR: I want to know how the code knows how to display both the correct country text and its corresponding flag.

2      

Hi!

When you ContentView is instantiated you have this part of code:

 @State private var correctAnswer = Int.random(in: 0...2)

When this var is intialized, it assigns random number, let's assume this number is 2

The code runs down the body and sees that part

ForEach(0..<3) { number in
                    Button {
                        flagTapped(number)
                    } label: {
                        Image(countries[number])
                    }

As it is a loop it will run 3 times and each time assigning the corrsponding digit (0..<3) to number.

In the Image part it will do as follows ->

As you have created these properties containing array

@State private var countries = allCountries.shuffled() // Takes allCountries and shuffles them
static let allCountries = ["Estonia", "France", "Germany", "Ireland", "Italy", "Nigeria", "Poland", "Russia", "Spain", "UK", "US"]

the number in loop will create your Image like so (beware that shuffle will change the order, i just show as example)

 Image(countries[number])

i.e.

Image("Estonia")
Image("France")
Image("Germany")

thus retrieving correspoding images from the assets and showing them on the screen.

Let's go to the flagTapped(number)

As each button assigned with number 0, 1, 2 in each loop, by pressing it, it will pass that number and compare that number to your correctAnswer which in our example was randomly chosen as 2.

Which is created by loop as button 3, i.e. Germany Flag.

You have question that was displayed as:

Text(countries[correctAnswer])
      .foregroundStyle(.white)
      .font(.largeTitle)
      .bold()
}

And countries it is our previous state var which is @State private var countries = allCountries.shuffled(). And countries[correctAnswer]), as our random number was as example chosen as 2 corresponds to

Image("Estonia")
Image("France")
Image("Germany") // <- Number 2 in array

So when you pressing button with number 2 and function checks that number is says ok number 2 == number 2. You got it right!

func flagTapped(_ number: Int) {
  // You pressed number 2 which is German Flag, and your correct answer was chosen as 2 so it's a match!
        if number == correctAnswer {
            scoreTitle = "Correct"
        } else {
            scoreTitle = "Incorrect"
        }
        showingScore = true
    }

TLDR: I want to know how the code knows how to display both the correct country text and its corresponding flag.

Correc answer is posted as question:

@State private var correctAnswer = Int.random(in: 0...2)

...

Text(countries[correctAnswer])
      .foregroundStyle(.white)
      .font(.largeTitle)
      .bold()
}

Your buttons are displayed as:

ForEach(0..<3) { number in
    Button {
        flagTapped(number)
    } label: {
    Image(countries[number])
    }
}

so if there is a match between Text(countries[correctAnswer]) and Image(countries[number]) your answer is correct! If that make sense for you.

2      

Hi pill0bokeh,

the countries array is shuffled after every round and the logic is that the first three flags are shown in every round. By a random number between 0 and 2 the country is selected which flag the user shall guess. The number (between 0 and 2) is stored in correctAnswer. Lets say in the first round the 3 flags are the flags of ["Estonia", "France", "Germany"] and the correctAnswer is randomly selected as 2. Then the question is

Tap the flag of Germany

The flags are taken from the Images which have the exact same name as the countries, so the flags Estonia.jpg, France,jpg and Germany.jpg are shown as images for the button.

If you tap a button, its number (index in the array) is compared to correctAnswer and the answer is shown :-)

2      

TLDR:

I want to know how the code knows how to display both the correct country text and its corresponding flag.

Pull your big problem apart and look at smaller pieces of the problem.

You have an array of countries called, allCountries()

// This array has 11 items in it. They are numbered zero to ten. (0, 1, 2,... 10)
let allCountries = ["Estonia", "France", "Germany", "Ireland", "Italy", "Nigeria", "Poland", "Russia", "Spain", "UK", "US"]

Each level of the game is only played with the first three cards which are numbered 0, 1, and 2. It would be a boring game if Estonia, France, and Germany were played over and over again.

So at some point in the lesson you added the .shuffled() modifier to a copy of the array.

// This is a copy of the allCountries array, but in a random order.
@State private var countries = allCountries.shuffled() // Shuffle allCountries

Still, the game is only played with the first three entries which are still numbered, 0, 1 and 2.

ForEach, the View Factory

When I first learned the 100 Days of SwiftUI lessons, I was confused until I thought of the ForEach, not as a LOOP, but as a factory that makes views. Take a look at the code below, and ask yourself, WHAT is this FACTORY making? Also ask yourself, HOW MANY of these things is it making?

// What is this ForEach Factory making?
ForEach(0..<3) { number in  // <-- Here! It's making three of something (0, 1, and 2)
    Button {      // <-- Here! It's making a button!
        flagTapped(number)
    } label: {
        Image(countries[number])
    }
}

Making a Button

If it's easier to visualise, draw three boxes on a piece of paper, each representing ONE button. The factory needs some raw materials to make a button. Take a look at the code and write down WHAT that raw material is.

What I see, is the factory needs an image that it gets from your application's resources. The factory says I need the flag image for country #0, country #1, and country #2 from my shuffled array.

The factory also generates three function calls, one for each button. These are flagTapped(0), flagTapped(1), and flagTapped(2). Conveniently, the correct answer is also 0, 1 or 2. So the function just needs to see if the button has the same number as the correctAnswer variable.

After the factory finishes making these three buttons, it hands the finished buttons off to the HStack() to properly display on screen, so the user can tap them.

Here's the cool thing about SwiftUI and @State properties. When ever you change an @State property that is used in the view, SwiftUI will redraw that view. It will redraw all the views' parts and pieces.

In your GameView(), this means it redraws each of the three buttons based on the countries that are currently in positions, 0, 1, and 2.

Keep Coding

See -> View Factory
or See -> View Factory
or See -> View Factory

3      

TAKE YOUR SKILLS TO THE NEXT LEVEL If you like Hacking with Swift, you'll love Hacking with Swift+ – it's my premium service where you can learn advanced Swift and SwiftUI, functional programming, algorithms, and more. Plus it comes with stacks of benefits, including monthly live streams, downloadable projects, a 20% discount on all books, and free gifts!

Find out more

Sponsor Hacking with Swift and reach the world's largest Swift community!

Reply to this topic…

You need to create an account or log in to reply.

All interactions here are governed by our code of conduct.

 
Unknown user

You are not logged in

Log in or create account
 

Link copied to your pasteboard.