## SOLVED: How do I create random answers for the edutainment app?

I'm currently working through Day 35 for the edutainment app. To me this app feels like it could be really similar to GuessTheFlag when it comes down to the game logic, so I'm working in that direction. However, I'm having a hard time translating some of the logic from GuessTheFlag to this project for a number of reasons. So far, this is what I'm trying to accomplish:

``````    VStack(spacing: 20) {
Text("What is \(selectedTable) x \(timesTable)")
.font(.largeTitle)

HStack(spacing: 10) {
Button {
// code
} label: {
Rectangle()
.stroke(Color.blue, lineWidth: 3)
.frame(maxWidth: 100, maxHeight: 100)
}
}
}
}

My goal is to generate three random answers for a user to choose from (they each appear in a blue box), while only one of them is the correct answer. Again this is super similar to GuessTheFlag but I'm stuck on implementing it. How do I generate both the random answers and the correct answer for a user to select?

1

@swiftdoc is mixing what the program does with what the program shows....

I'm having a hard time translating some of the logic from GuessTheFlag to this project
My goal is to generate three random answers for a user to choose from
while only one of them is the correct answer

Take your big problem and break it down into several, smaller solvable problems. To make it easier, put each problem in a separate room in your house, and only solve the problem in that room. Don't try to solve two problems at once.

#### Problem #1

You have two numbers, `selectedTable` and `timesTable`. You want to multiply these two numbers and have a correct answer. First observation is that in maths, you typically multiply operands together. So consider renaming your variables to `operand1` and `operand2`. Just a suggestion that may help clarify your logic.

Rather than having a bunch of logic polluting your `View` (what you see) consider moving all the logic for your answer to brand new `struct`!

#### Game Logic

Your game logic can all be neatly packaged into a convenient `struct`. When you create a new `struct` it will generate two random operands, a display string, and three random guesses. All the logic for your quiz is in this `struct`.

``````// Put your game play LOGIC in a separate struct!
// Keep your game play logic OUT of the view.
struct Problem {
private var operand1 = 0  // These are private and generated
private var operand2 = 0  // by a new game function.

// Your solution may need different logic here
mutating func newProblem() {
operand1 = Int.random(in: 3...12)
operand2 = Int.random(in: 3...12)
}
var correctAnswer: Int { operand1 * operand2 }

var problemString: String {  // Convenience string
String("\(operand1) X \(operand2)")
}

// Array of guesses
// You can make this more challenging
var guesses: [Int] {
[
].shuffled()
}
}``````

#### Problem #2

Now that you've created a `struct` you have to grab the operands, solution, and possible guesses and use them in a `View`. I will leave this to you to noodle through.

``````// One function creates two new random operands.
// The computed variable calculates the only correct answer
/// Your solution may need different logic here
mutating func newProblem() {
operand1 = Int.random(in: 3...12)
operand2 = Int.random(in: 3...12)
}
var correctAnswer: Int { operand1 * operand2 }``````

#### Problem #3

Now that you have a `struct` initialised with two operands, it's time to build the `ProblemView`. You'll want to display the two operands as a proper multiplication problem. Then you'll show a `Picker` with the possible choices.

Possibly you'll want to show a success message when the player selects the correct answer.

Maybe the New Problem `button` is inactive until the correct answer is found? Your call.

#### What did you learn?

First, pull your logic into `struct`s whenever possible. This keeps your logic separate from what you want to display.

Second remember that SwiftUI is declarative. Re-read that statement. It's declarative.

Declare what you WANT TO SEE.

I want to see three options from this array of `possibleGuesses`.
Don't write logic in the `View` code saying print the value of `operand1` times `operand2`. Declare a computed variable named `correctAnswer` and tell SwiftUI to display the `correctAnswer`! Declare your intentions.
I want to verify the user's guess matches the one and only `correctAnswer`.

Don't multiply the two operands in your `View` structure. The `View` should just display data. Do the calculations in your `Problem` struct. Use the power of structs to encapsulate your game logic. Keep it separate from your `view` logic.

#### Full Example

``````struct ProblemView: View {
@State private var gameProblem = Problem()
@State private var playerGuess = 0

private var isCorrectResponse: Bool {
}

var body: some View {
VStack {
Text(gameProblem.problemString)
Picker(selection: \$playerGuess) {
ForEach( gameProblem.guesses, id:\.self) { guess in
Text("\(guess)").tag(guess)
}
} label: {
}.pickerStyle(.segmented)
if isCorrectResponse {
}
}
Button("New Problem") {
gameProblem.newProblem() // Ask logic struct for a new problem
.disabled(!correctResponse)
}
}

// ======================================= Problem Game Logic
// Put your game play LOGIC in a separate struct!
// Keep your game play logic OUT of the view.
struct Problem {
private var operand1 = 0  // these are passed in from the
private var operand2 = 0  // user interface

mutating func newProblem() {
operand1 = Int.random(in: 3...12)
operand2 = Int.random(in: 3...12)
}
var correctAnswer: Int { operand1 * operand2 }

var problemString: String {
String("\(operand1) X \(operand2)")
}

// Array of guesses
// You can make this more challenging
var guesses: [Int] {
[
].shuffled()
}
}``````

2

#### Homework

There's a bug in the `Picker` logic!

2

#### Homework #2

The `ProblemView` should just reflect the variables that are in the `Problem` struct.

But in the sample code above, I created a computed variable in the `View` to determine if the user's tapped selection is the correct answer.

This violates one of the lessons from above namely, keep your game logic in a separate struct.
Use the `ProblemView` to simply interact with the user.

Can you think of a way to move the `isCorrectResponse` calculation OUT of the view and into the `Problem` struct?

#### Keep Coding

Please return here and let us know how you solved this.

2

Thank you!

1

The solution for the picker bug was using an `onAppear` modifier that performed `problem.newProblem()` to refresh the UI so that a new problem would be presented to the user. Otherwise the game would always start with "What is 0 X 0?"

Further, the `@State private var playerGuess` variable was stuck on `= 0`, which affected how the user saw the picker selctions. The above solution solved that as well.

1

To get the `isCorrectResponse` computed property out of the `ProblemView`, I had to first copy and paste the computed property into the `Problem` struct. Once I did that, I created the variable `var playerGuess = 0` so that it could hold the player's initial selection when a new game started. In this case the selection would be nothing.

Another step was to cut out the `gameProblem` part of the property because it was no longer a part of the `ProblemView` struct. The property would now read as `var isCorrectResponse: Bool { playerGuess == correctAnswer }`. Given that everything was now placed inside the `Problem` struct, I no longer needed the `gameProblem` variable.

To have this reflect in the UI, I added `problem.isCorrectResponse` under the picker label and created a binding to the `Problem` struct inside the `Picker(selection:`.

I may have missed something here, but your responses were very helpful and I now have a much better development process :)

1

SAVE 50% To celebrate WWDC24, all our books and bundles are half price, so you can take your Swift knowledge further without spending big! Get the Swift Power Pack to build your iOS career faster, get the Swift Platform Pack to builds apps for macOS, watchOS, and beyond, or get the Swift Plus Pack to learn advanced design patterns, testing skills, and more.