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

SOLVED: Day 25 Challenge; End game alert

Forums > SwiftUI

I'm trying to figure out how to consistently delay the "finalScore" (ending game) alert to pop up after the "scoreTitle" (round ending) alert in challenge 25. I can't seem to get the alerts in a consistent order in whichever way I try.

.alert(scoreTitle, isPresented: $showingScore) {
            Button("Continue", action: askQuestion)
        } message: {
            Text("Your score is \(score)")
        }

        .alert(finalScore, isPresented: $showingScore1) {
            Button("Play Again", action: startOver)
        } message: {
            Text("Final score: \(score)/10")
        }
    }
}

func shoot(_ choice: Int) {
    switch (winLose, opponent, choice) {
    case (true, 0, 1):
        scoreTitle = "Correct"
        score += 1
    case (true, 1, 2):
        scoreTitle = "Correct"
        score += 1
    case (true, 2,0):
        scoreTitle = "Correct"
        score += 1
    case (false, 0, 2):
        scoreTitle = "Correct"
        score += 1
    case (false, 1, 0):
        scoreTitle = "Correct"
        score += 1
    case (false, 2, 1):
        scoreTitle = "Correct"
        score += 1
    default:
        scoreTitle = "Wrong"
    }
    showingScore = true

    if scoreCount == 10 {
        finalScore = "Game Over"
        showingScore1 = true
    }
}

func askQuestion() {
    winLose.toggle()
    opponent = Int.random(in: 0...2)
}

func startOver() {
    opponent = Int.random(in: 0...2)
    score = 0
    scoreCount = 0
}
}

1      

@Maz gives us a great opportunity to think about declarative vs procedural programming!

I can't seem to get the alerts in a consistent order in whichever way I try.

Procedural Approach

In a procedural programming approach, you might have pseudo code like this:

// Follow the step-by-step procedure.
// (1) First display one alert
showAlert("Code Green! Code Green! Put your socks on!")

// (2) Then you wait for user to dismiss the first alert.
do {
     // crazy ear splitting sirens and retina burning light effect
} until socksOnFeet == true

// (3) Next you show the next alert.
showAlert("Now!  Now you're cleared to put your shoes on.")

You see? When one task completes, the compiler will move onto the next statement in order. The compiler follows the procedure as dictated by the developer.

Declarative Approach

In a declarative approach, you add a view that your user will see and interact with. Then you declare that if some @State var changes to true, you update the view to show some change to the user interface.

If some other @State var changes to true, then you show that alert.

As a programmer, it's your job to declare what is shown to the user under the various application states.

    // Declare what your user will see.
    VStack {
         Image("galaxyExplosion").scaleToFit()
         Text("Hey Space Cadet! That was amazing!").font(.reallyReallyBig)
    }
    // Declare this alert is displayed only when continueGame is true
    .alert(questionCount, isPresented: $continueGame) 
            { Button("Continue playing?", action: processUsersRequest) } 
              message: { Text("Current score: \(score)/\(questionCount)") }

     // Declare this alert is displayed only when showingScore is true
    .alert(finalScore, isPresented: $showingScore) 
            { Button("Play Again", action: startOver) } 
              message: { Text("Final score: \(score)/10") }

Now your logic becomes: under which situations should $continueGame be set to true? And when that alert pane is dismissed, do some action: processUsersRequest

Logic in processUsersRequest may decide that it should set the $showingScore var to true, thus triggering the second alert to show.

States == Switches on a Dashboard

In short, you don't line up several alerts to trigger a chain reaction.
Instead, you decorate a view with all the possible alerts your program might need. Then you use logic to determine which @State variable to set to true.

To help visualize this, think of @State vars (especially Bool vars) as light switches in a room. If you turn one switch on, which light in the room is illuminiated? If you turn on more than one light switch, what should happen?

1      

Thanks, @Obelix, I figured it out.

 showingScore = true

    if showingScore {
        scoreCount += 1
    }

    if scoreCount == 10 {
        finalScore = "Game Over"
        showingScore1 = true
    }
}

1      

This code was using the correct alert order in the UI preview, but not when running the app so I changed it to this and it worked in the running the app.

 //Function & Switch statement ending...
    default:
        scoreTitle = "Wrong"
    }
    showingScore = true
}

func askQuestion() {
    winLose.toggle()
    opponent = Int.random(in: 0...2)
    scoreCount += 1

    if scoreCount == 10 {
        finalScore = "Game Over"
        showingScore1 = true
    }
}

func startOver() {
    opponent = Int.random(in: 0...2)
    score = 0
    scoreCount = 0
}
}

1      

Nice job figuring this out!

Here's a free hint to consider.

Consider adding a var to your GameView named roundsPerGame, or something similar. Then you can add a computed variable to determine if the game is over. This keeps you from hardcoding magic numbers in your logic code. Also may make your logic more readable.

    // Describe your logic using typical game terms.
    var roundCount    =  1 // <-- What round is player on?
    var roundsPerGame = 10 // <-- How many rounds to play?

    // computed parameter.  Returns true if you've been through all the rounds
    private var gameIsOver: Bool { roundCount > roundsPerGame }

    // Later in the logic...
    // I think this more accurately reflects the intentions of your end-of-game logic

    func askQuestion() {
        winLose.toggle()
        opponent    = Int.random(in: 0...2)
        roundCount += 1

        //  HERE.  Put the computed var here. I think this reflects your end-of-game logic.
        if gameIsOver {
            finalScore    = "Game Over"  // <- This is NOT a score. Consider changing to gameOverLabel, or similar
            showingScore1 = true  // This is confusing. Pick a more descriptive var name.
        }
    }

Just some suggestions.

1      

Hacking with Swift is sponsored by Essential Developer

SPONSORED Join a FREE crash course for mid/senior iOS devs who want to achieve an expert level of technical and practical skills – it’s the fast track to being a complete senior developer! Hurry up because it'll be available only until April 28th.

Click to save your free spot now

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

Archived topic

This topic has been closed due to inactivity, so you can't reply. Please create a new topic if you need to.

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.