changeset 33:6d574bd1644f

refactor controllers
author Dennis C. M. <dennis@denniscm.com>
date Sat, 12 Nov 2022 11:18:30 +0100
parents c62d6f92709d
children 6ec51a4ca897
files GeoQuiz/Controllers/CityGameController.swift GeoQuiz/Controllers/CountryGameController.swift GeoQuiz/Controllers/GameProtocol+Extension.swift GeoQuiz/GuessTheCapitalView.swift GeoQuiz/GuessTheCountryView.swift GeoQuiz/GuessTheFlagView.swift GeoQuiz/GuessThePopulationView.swift GeoQuiz/Helpers/GameAlertsModifier.swift screenshots/iPad Pro/store/image2.jpeg screenshots/iPad Pro/store/image4.jpeg screenshots/iPhone 11/store/image2.jpeg screenshots/iPhone 11/store/image4.jpeg screenshots/iPhone 8/store/image2.jpeg screenshots/iPhone 8/store/image4.jpeg
diffstat 14 files changed, 59 insertions(+), 135 deletions(-) [+]
line wrap: on
line diff
--- a/GeoQuiz/Controllers/CityGameController.swift	Fri Nov 11 09:05:41 2022 +0100
+++ b/GeoQuiz/Controllers/CityGameController.swift	Sat Nov 12 11:18:30 2022 +0100
@@ -8,30 +8,27 @@
 import Foundation
 import AVFAudio
 
-class CityGameController: Game, ObservableObject {
+@MainActor class CityGameController: Game, ObservableObject {
     
-    // Define type of generics
+    // Define generic type
     typealias T = CityModel.City
     
+    // Game
     var data: [String: T]
     var dataAsked = [String: T]()
     
-    // Data
-    @Published var correctAnswer = (
-        key: String(),
-        value: T(country: String(), lat: Double(), lon: Double())
-    )
-    
-    // User
     @Published var userChoices = [String: T]()
     @Published var userScore = 0
     @Published var userLives = 3
+    
+    @Published var correctAnswer = (key: String(), value: T(country: String(), lat: Double(), lon: Double()))
     @Published var correctAnswers = [String: T]()
     @Published var wrongAnswers = [String: T]()
     
     // Alerts
     @Published var alertTitle = String()
     @Published var alertMessage = String()
+    
     @Published var showingEndGameAlert = false
     @Published var showingWrongAnswerAlert = false
     @Published var showingExitGameAlert = false
@@ -45,11 +42,16 @@
     
     init() {
         let data: CityModel = Bundle.main.decode("cities.json")
-        let shuffledCities = data.cities.shuffled().prefix(100)
-        
+        let shuffledCities = data.cities.shuffled()
         var cities = [String: T]()
-        for shuffledCity in shuffledCities {
-            cities[shuffledCity.key] = shuffledCity.value
+        
+        for _ in 1...10 {
+            let countryNames = cities.map { $0.value.country }
+            let city = shuffledCities.first(where: {
+                !countryNames.contains($0.value.country)
+            })!
+            
+            cities[city.key] = city.value
         }
         
         self.data = cities
@@ -63,54 +65,8 @@
             }
         }
         
-        askQuestion {
-            selector()
-        }
+        ask()
     }
 }
 
-extension CityGameController {
-    func selector() {
-        
-        // Get random choices
-        var userChoices = [String: T]()
-        
-        while userChoices.count < 2 {
-            if let choice = data.randomElement() {
-                let userChoicesCountry = userChoices.map { $0.value.country }
-                
-                if !userChoicesCountry.contains(choice.value.country) {
-                    userChoices[choice.key] = choice.value
-                }
-            } else {
-                fatalError("Couldn't get a random value from data")
-            }
-        }
-        
-        // Get correct answer
-        let randomCityKeys = data.keys.shuffled()
-        let userChoicesCountry = userChoices.map { $0.value.country }
-        
-        let correctCityKey = randomCityKeys.first(where: {
-            !userChoices.keys.contains($0) &&                  // Avoid duplicated cities
-            !dataAsked.keys.contains($0) &&                    // Avoid cities already asked
-            !userChoicesCountry.contains(data[$0]!.country)    // Avoid duplicated country names in userChoices
-        })
 
-        // Unwrap optional
-        if let correctCityKey = correctCityKey {
-            let correctCityValue = data[correctCityKey]!
-            
-            userChoices[correctCityKey] = correctCityValue
-            dataAsked[correctCityKey] = correctCityValue
-            
-            let correctAnswer = (key: correctCityKey, value: correctCityValue)
-            self.correctAnswer = correctAnswer
-        } else {
-            fatalError("Couldn't unwrap optional value")
-        }
-        
-        self.userChoices = userChoices
-    }
-}
-
--- a/GeoQuiz/Controllers/CountryGameController.swift	Fri Nov 11 09:05:41 2022 +0100
+++ b/GeoQuiz/Controllers/CountryGameController.swift	Sat Nov 12 11:18:30 2022 +0100
@@ -16,7 +16,6 @@
     var data: [String: T]
     var dataAsked = [String: T]()
     
-    // Data
     @Published var correctAnswer = (
         key: String(),
         value: T(flag: String(), currency: String(), population: Int(), capital: String())
@@ -45,15 +44,17 @@
     
     init() {
         let data: CountryModel = Bundle.main.decode("countries.json")
-        let shuffledCountries = data.countries.shuffled().prefix(100)
+        let shuffledCountries = data.countries.shuffled().prefix(5)
+        var countries = [String: T]()
         
-        var countries = [String: T]()
         for shuffledCountry in shuffledCountries {
             countries[shuffledCountry.key] = shuffledCountry.value
         }
         
         self.data = countries
         
+        print(countries)
+        
         let user = UserController()
         userLives = user.data.numberOfLives
         
@@ -63,47 +64,6 @@
             }
         }
         
-        askQuestion {
-            selector()
-        }
+        ask()
     }
 }
-
-extension CountryGameController {
-    func selector() {
-        
-        // Get random choices
-        var userChoices = [String: T]()
-        
-        while userChoices.count < 2 {
-            if let choice = data.randomElement() {
-                userChoices[choice.key] = choice.value
-            } else {
-                fatalError("Couldn't get a random value from data")
-            }
-        }
-        
-        // Get correct answer
-        let randomCountryKeys = data.keys.shuffled()
-        
-        let correctCountryKey = randomCountryKeys.first(where: {
-            !userChoices.keys.contains($0) &&   // Avoid duplicated countries
-            !dataAsked.keys.contains($0)        // Avoid countries already asked
-        })
-        
-        // Unwrap correct answer
-        if let correctCountryKey = correctCountryKey {
-            let correctCountryValue = data[correctCountryKey]!
-            
-            userChoices[correctCountryKey] = correctCountryValue
-            dataAsked[correctCountryKey] = correctCountryValue
-            
-            let correctAnswer = (key: correctCountryKey, value: correctCountryValue)
-            self.correctAnswer = correctAnswer
-        } else {
-            fatalError("Couldn't unwrap optional value")
-        }
-        
-        self.userChoices = userChoices
-    }
-}
--- a/GeoQuiz/Controllers/GameProtocol+Extension.swift	Fri Nov 11 09:05:41 2022 +0100
+++ b/GeoQuiz/Controllers/GameProtocol+Extension.swift	Sat Nov 12 11:18:30 2022 +0100
@@ -18,7 +18,7 @@
     case guessThePopulation
 }
 
-protocol Game: ObservableObject {
+@MainActor protocol Game: ObservableObject {
     
     // Define generic type
     associatedtype T: Equatable
@@ -26,18 +26,19 @@
     // Game
     var data: [String: T] { get set}
     var dataAsked: [String: T] { get set }
-    var correctAnswer: (key: String, value: T) { get set }
     
-    // User
     var userChoices: [String: T] { get set }
     var userScore: Int { get set }
     var userLives: Int { get set }
+    
+    var correctAnswer: (key: String, value: T) { get set }
     var correctAnswers: [String: T] { get set }
     var wrongAnswers: [String: T] { get set }
     
     // Alerts
     var alertTitle: String { get set }
     var alertMessage: String { get set }
+    
     var showingEndGameAlert: Bool { get set }
     var showingWrongAnswerAlert: Bool { get set }
     var showingExitGameAlert: Bool { get set }
@@ -48,8 +49,6 @@
     
     // Sound effects
     var player: AVAudioPlayer? { get set }
-    
-    func selector()
 }
 
 extension Game {
@@ -57,7 +56,8 @@
        dataAsked.count
     }
     
-    func askQuestion(selector: () -> Void) {
+    // MARK: - Ask new question
+    func ask() {
         guard questionCounter < data.count else {
             alertTitle = "⭐️ Congratulations ⭐️"
             alertMessage = "You completed the game."
@@ -66,10 +66,28 @@
             return
         }
         
-        selector()
+        var userChoices = [String: T]()
+        
+        while userChoices.count < 2 {
+            let choice = data.randomElement()!
+            userChoices[choice.key] = choice.value
+        }
+        
+        let correctKey = data.keys.shuffled().first(where: {
+            !userChoices.keys.contains($0) &&               // Avoid duplicated items
+            !dataAsked.keys.contains($0)                    // Avoid items already asked
+        })!
+        
+        let correctValue = data[correctKey]!
+        
+        userChoices[correctKey] = correctValue
+        dataAsked[correctKey] = correctValue
+        correctAnswer = (key: correctKey, value: correctValue)
+        self.userChoices = userChoices
     }
     
-    func answer(choice: (key: String, value: T), wrongMessage: String, selector: () -> Void) {
+    // MARK: - Answer question
+    func answer(choice: (key: String, value: T), wrongMessage: String) {
         let haptics = HapticsController()
         
         if correctAnswer == choice {
@@ -82,17 +100,15 @@
             }
             
             correctAnswers[correctAnswer.key] = correctAnswer.value
-            askQuestion {
-                selector()
-            }
+            ask()
         } else {
             haptics.error()
             playSound("wrongAnswer")
 
-            withAnimation(.easeIn(duration: 0.5)) {
-                livesScaleAmount += 1
-                userLives -= 1
-            }
+//            withAnimation(.easeIn(duration: 0.5)) {
+//                livesScaleAmount += 1
+//                userLives -= 1
+//            }
             
             wrongAnswers[choice.key] = choice.value
             
@@ -115,6 +131,7 @@
         }
     }
     
+    // MARK: - Save game
     func save(_ gameType: GameType, with moc: NSManagedObjectContext) {
         let playedGame = PlayedGame(context: moc)
 
@@ -131,6 +148,7 @@
         }
     }
     
+    // MARK: - Play sound effect
     private func playSound(_ filename: String) {
         let user = UserController()
         
--- a/GeoQuiz/GuessTheCapitalView.swift	Fri Nov 11 09:05:41 2022 +0100
+++ b/GeoQuiz/GuessTheCapitalView.swift	Sat Nov 12 11:18:30 2022 +0100
@@ -65,9 +65,7 @@
                                     gameController.answer(
                                         choice: (key: countryName, value: gameController.data[countryName]!),
                                         wrongMessage: "That's the capital of \(countryName)"
-                                    ) {
-                                        gameController.selector()
-                                    }
+                                    )
                                 } label: {
                                     AnswerButton(
                                         name: gameController.data[countryName]!.capital,
--- a/GeoQuiz/GuessTheCountryView.swift	Fri Nov 11 09:05:41 2022 +0100
+++ b/GeoQuiz/GuessTheCountryView.swift	Sat Nov 12 11:18:30 2022 +0100
@@ -48,9 +48,7 @@
                                     gameController.answer(
                                         choice: (key: cityName, value: gameController.data[cityName]!),
                                         wrongMessage: "\(gameController.correctAnswer.key) is located in \(gameController.correctAnswer.value.country)"
-                                    ) {
-                                        gameController.selector()
-                                    }
+                                    )
                                 } label: {
                                     AnswerButton(
                                         name: gameController.data[cityName]!.country,
--- a/GeoQuiz/GuessTheFlagView.swift	Fri Nov 11 09:05:41 2022 +0100
+++ b/GeoQuiz/GuessTheFlagView.swift	Sat Nov 12 11:18:30 2022 +0100
@@ -48,9 +48,7 @@
                                 gameController.answer(
                                     choice: (key: countryName, value: gameController.data[countryName]!),
                                     wrongMessage: "That's the flag of \(countryName)"
-                                ) {
-                                    gameController.selector()
-                                }
+                                )
                             } label: {
                                 
                                 /*
--- a/GeoQuiz/GuessThePopulationView.swift	Fri Nov 11 09:05:41 2022 +0100
+++ b/GeoQuiz/GuessThePopulationView.swift	Sat Nov 12 11:18:30 2022 +0100
@@ -65,9 +65,7 @@
                                     gameController.answer(
                                         choice: (key: countryName, value: gameController.data[countryName]!),
                                         wrongMessage: "That's the population of \(countryName)"
-                                    ) {
-                                        gameController.selector()
-                                    }
+                                    )
                                 } label: {
                                     let population = gameController.data[countryName]!.population
                                     AnswerButton(
--- a/GeoQuiz/Helpers/GameAlertsModifier.swift	Fri Nov 11 09:05:41 2022 +0100
+++ b/GeoQuiz/Helpers/GameAlertsModifier.swift	Sat Nov 12 11:18:30 2022 +0100
@@ -20,9 +20,7 @@
         content
             .alert(gameController.alertTitle, isPresented: $gameController.showingWrongAnswerAlert) {
                 Button("Continue", role: .cancel) {
-                    gameController.askQuestion {
-                        gameController.selector()
-                    }
+                    gameController.ask()
                 }
             } message: {
                 Text(gameController.alertMessage)
Binary file screenshots/iPad Pro/store/image2.jpeg has changed
Binary file screenshots/iPad Pro/store/image4.jpeg has changed
Binary file screenshots/iPhone 11/store/image2.jpeg has changed
Binary file screenshots/iPhone 11/store/image4.jpeg has changed
Binary file screenshots/iPhone 8/store/image2.jpeg has changed
Binary file screenshots/iPhone 8/store/image4.jpeg has changed