diff GeoQuiz/Logic/Game.swift @ 3:4dbe0cd9dadc

first game prototype
author Dennis C. M. <dennis@denniscm.com>
date Thu, 22 Sep 2022 10:42:39 +0200
parents
children de54f05adb78
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/GeoQuiz/Logic/Game.swift	Thu Sep 22 10:42:39 2022 +0200
@@ -0,0 +1,121 @@
+//
+//  GameProtocol.swift
+//  GeoQuiz
+//
+//  Created by Dennis Concepción Martín on 18/9/22.
+//
+
+import Foundation
+import SwiftUI
+
+protocol Game: ObservableObject {
+    
+    // Define generic type
+    associatedtype T: Equatable
+    
+    // Game
+    var data: [String: T] { get set}
+    var dataAsked: [String] { 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 }
+    
+    // Alerts
+    var alertTitle: String { get set }
+    var alertMessage: String { get set }
+    var showingNoLivesAlert: Bool { get set }
+    var showingEndGameAlert: Bool { get set }
+    var showingWrongAnswerAlert: Bool { get set }
+    
+    // Animations
+    var scoreScaleAmount: Double { get set }
+    var livesScaleAmount: Double { get set }
+    
+    // Modal views
+    var showingBuyLivesView: Bool { get set }
+}
+
+extension Game {
+    var questionCounter: Int {
+       dataAsked.count
+    }
+    
+    func askQuestion() {
+        guard questionCounter < data.count else {
+            alertTitle = "Amazing!"
+            alertMessage = "You've completed the game."
+            showingEndGameAlert = true
+            
+            return
+        }
+        
+        // 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 question asked (correct answer)
+        let correctAnswer = data.first(where: {
+            !userChoices.keys.contains($0.key) && !dataAsked.contains($0.key)
+        })
+        
+        // Unwrap optional
+        if let correctAnswer = correctAnswer {
+            userChoices[correctAnswer.key] = correctAnswer.value
+            dataAsked.append(correctAnswer.key)
+            self.correctAnswer = correctAnswer
+        } else {
+            fatalError("Couldn't unwrap optional value")
+        }
+        
+        self.userChoices = userChoices
+    }
+    
+    func answer(_ choice: (key: String, value: T)) {
+        guard userLives > 0 else {
+            alertTitle = "Not enough lives!"
+            alertMessage = "Please buy more lives to keep playing"
+            showingNoLivesAlert = true
+
+            return
+        }
+        
+        if correctAnswer == choice {
+            hapticSuccess()
+            userScore += 1
+
+            withAnimation(.easeIn(duration: 0.5)) {
+                scoreScaleAmount += 1
+            }
+            
+            askQuestion()
+        } else {
+            hapticError()
+            userLives -= 1
+
+            withAnimation(.easeIn(duration: 0.5)) {
+                livesScaleAmount += 1
+            }
+
+            alertTitle = "Wrong!"
+            alertMessage = "You have \(userLives) lives left"
+            showingWrongAnswerAlert = true
+        }
+        
+        DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) { [self] in
+            withAnimation(.easeIn(duration: 0.5)) {
+                scoreScaleAmount = 1
+                livesScaleAmount = 1
+            }
+        }
+    }
+}