Connar Mordelt
Connar Mordelt

Reputation: 23

How do I get the variable with the highest Int and retrieve a String Swift

I am building a Quiz and I have a struct with 4 Variables which are countries.

I have around 15 View Controllers with 4 buttons, each button represents one Country and increments the score by 1.

Now at the end of the Quiz, I want to display the country with the highest score and make it open a new View Controller.

import Foundation

var ukScore = 0
var greeceScore = 0
var italyScore = 0
var austriaScore = 0

var finalCountry = ""

struct QuizScore {
    
     func ukScoreIncrement() {
        ukScore += 1
    }
    
     func greeceScoreIncrement() {
        greeceScore += 1
    }
    
     func italyScoreIncrement() {
        italyScore += 1
    }
    
     func austriaScoreIncrement() {
        austriaScore += 1
    }
    
     func getFinalScore(){
        
        
        if ukScore == max(ukScore, greeceScore, italyScore, austriaScore) {
           finalCountry = "Uk"
        } else if greeceScore == max(ukScore, greeceScore, italyScore, austriaScore) {
            finalCountry = "greece"
        } else if italyScore == max(ukScore, greeceScore, italyScore, austriaScore) {
           finalCountry = "italy"
        } else if austriaScore == max(ukScore, greeceScore, italyScore, austriaScore) {
            finalCountry = "austria"   
        } 
    } 
}
`

The idea is to figure out which country wins, and then pass the string to my last class which would then prepare the next segue depending on the winning country.

Upvotes: 2

Views: 124

Answers (2)

Paulw11
Paulw11

Reputation: 114975

I would create a struct to represent each country and create an array of these. The struct would have a name and a score.

struct Country: Comparable {
    
    let name: String
    var score = 0
    
    mutating func incrementScore() {
        self.score += 1
    }
    
    static func < (lhs: Country, rhs: Country) -> Bool {
        return lhs.score < rhs.score
    }
}

Then you can create an array of these structs for whichever countries you need:

var countries = [Country(name:"UK"),
                 Country(name:"Greece"),
                 Country(name:"Italy"),
                 Country(name:"Austria")]

You can then increment scores as required

self.countries[0].incrementScore()

Your winner can then easily be found by sorting the array

let winner = self.countries.sorted().last()!
print("The winner is \(winner.name) with a score of \(winner.score)")

If you use a closure to sort the array then you can have the winner in the first element rather than the last.

To find the winner you could also iterate through the array looking for the maximum score. My thought was that the array is fairly small, so sorting is inexpensive and sorting also gives you second place and third place etc.

Note that normally I wouldn't recommend the use of a force unwrap, but in this case you know the array isn't empty.

Using this approach you can easily create your four buttons by iterating over the array and creating a button for each element. If you add additional Country instances to the countries array then your UI would automatically adjust.

Upvotes: 1

Bradley Mackey
Bradley Mackey

Reputation: 7678

Using an enum with a Dictionary seems like a better way to model this. Using the .max() method on Sequence, you can then easily determine the winner.

enum Country: Hashable {
  case uk
  case greece
  case italy
  case austria
}

Using Country as a key, we then store the score for each.

struct Quiz {
  private var scores = [Country: Int]()

  /// Add 1 to the score of the given `Country`.
  mutating func increment(_ country: Country) {
    scores[country, default: 0] += 1
  }
  
  /// Determine the winner of the quiz.
  /// - returns: The winning `Country`, or `nil` if there are no winners.
  func winner() -> Country? {
    scores.max { first, second in
      // get the maximum score, sorting each dictionary element
      // by the score (the .value of the dictionary)
      first.value < second.value
    }.map { (country, _) in
      // transform the resultant element to the "key" value
      country
    }
  }
 
}

You then have code completion for each possible country, and have a maintainable API. You can then use a switch on the result to trigger a segue (or any other code).

var q = Quiz()

q.increment(.uk)
q.increment(.austria)
q.increment(.austria)
let winner = q.winner() // "austria"

switch winner {
case .uk:
  triggerUKSegue()
case .greece:
  triggerGreeceSegue()
case .italy:
  triggerItalySegue()
case .austria:
  triggerAustriaSegue()
case nil:
  print("no winner yet!")
}

This is just an example, it may be wise to just have a single "result" view, and pass it the winning Country to display some result. Additionally, we're not checking if there is more than 1 winner at the moment.

Upvotes: 3

Related Questions