Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

hugo/feature/Handle Exercise status and displays it #567

Merged
merged 5 commits into from
Jan 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ extension DragAndDropIntoZonesView {
node.zPosition = 10
node.isDraggable = false
self.onDropAction(node)
if self.viewModel.exercicesSharedData.state == .completed {
if case .completed = self.viewModel.exercicesSharedData.state {
DispatchQueue.main.asyncAfter(deadline: .now() + 1.5) { [self] in
self.exerciseCompletedBehavior()
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ extension DragAndDropToAssociateView {
node.isDraggable = false
self.playedDestination?.isDraggable = false
self.onDropAction(node)
if self.viewModel.exercicesSharedData.state == .completed {
if case .completed = self.viewModel.exercicesSharedData.state {
DispatchQueue.main.asyncAfter(deadline: .now() + 1.5) { [self] in
self.exerciseCompletedBehavior()
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,37 @@
import SwiftUI

public class ExerciseSharedData: ObservableObject {
// MARK: Lifecycle

public init(sequenceIndex: Int, exerciseIndex: Int) {
self.sequenceIndex = sequenceIndex
self.exerciseIndex = exerciseIndex
}

public init() {
self.exerciseIndex = 0
self.sequenceIndex = 0
}

// MARK: Internal

// TODO: (@HPezz): Add state setter function, and makes it private

Check warning on line 22 in Modules/GameEngineKit/Sources/_NewSystem/Exercises/ExerciseSharedData.swift

View workflow job for this annotation

GitHub Actions / swiftlint

TODOs should be resolved ((@HPezz): Add state setter fun...) (todo)
@Published var state: ExerciseState = .idle

let sequenceIndex: Int
let exerciseIndex: Int

var completionLevel: ExerciseState.CompletionLevel? {
guard case let .completed(level) = state else { return nil }
return level
}

var isExerciseNotYetCompleted: Bool {
switch self.state {
case .completed:
false
default:
true
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,19 @@
// Copyright APF France handicap
// SPDX-License-Identifier: Apache-2.0

enum ExerciseState {
enum ExerciseState: Equatable {
case idle
case playing
case completed
case completed(level: CompletionLevel)

// MARK: Internal

enum CompletionLevel {
case fail
case belowAverage
case average
case good
case excellent
case nonApplicable
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -48,12 +48,12 @@ extension DanceFreezeView {
}

func randomSwitch() {
guard self.viewModel.exercicesSharedData.state != .completed else { return }
if self.viewModel.progress < 1.0, self.viewModel.exercicesSharedData.state != .completed {
if case .completed = self.viewModel.exercicesSharedData.state { return }
if self.viewModel.progress < 1.0 {
let rand = Double.random(in: 2..<10)

DispatchQueue.main.asyncAfter(deadline: .now() + rand) {
guard self.viewModel.exercicesSharedData.state != .completed else { return }
if case .completed = self.viewModel.exercicesSharedData.state { return }
self.viewModel.onDanceFreezeToggle()
self.randomSwitch()
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ extension DanceFreezeView {

public func onDanceFreezeToggle() {
if self.progress == 1.0 {
self.exercicesSharedData.state = .completed
self.completeDanceFreeze()
return
}
if self.audioPlayer.isPlaying {
Expand All @@ -55,7 +55,7 @@ extension DanceFreezeView {
func completeDanceFreeze() {
self.robotManager.stopRobot()
self.audioPlayer.stop()
self.exercicesSharedData.state = .completed
self.exercicesSharedData.state = .completed(level: .nonApplicable)
}

// MARK: Private
Expand Down Expand Up @@ -84,7 +84,7 @@ extension DanceFreezeView {
}

private func robotLightFrenzy() {
guard self.exercicesSharedData.state != .completed, self.isDancing else { return }
if case .completed = self.exercicesSharedData.state, !self.isDancing { return }

self.robotManager.shineRandomly()

Expand All @@ -94,7 +94,7 @@ extension DanceFreezeView {
}

private func robotRotation() {
guard self.exercicesSharedData.state != .completed, self.isDancing else { return }
if case .completed = self.exercicesSharedData.state, !self.isDancing { return }

let duration = self.robotManager.rotationDance()

Expand All @@ -104,7 +104,7 @@ extension DanceFreezeView {
}

private func robotMovement() {
guard self.exercicesSharedData.state != .completed, self.isDancing else { return }
if case .completed = self.exercicesSharedData.state, !self.isDancing { return }

let duration = self.robotManager.movementDance()

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ extension HideAndSeekView {
Spacer()

Button {
self.exercicesSharedData.state = .completed
self.exercicesSharedData.state = .completed(level: .nonApplicable)
HPezz marked this conversation as resolved.
Show resolved Hide resolved
} label: {
ButtonLabel(self.textButtonRobotFound, color: .cyan)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ extension MelodyView {
self.midiPlayer.play()

DispatchQueue.main.asyncAfter(deadline: .now() + self.midiPlayer.getDuration()) {
self.exercicesSharedData.state = .completed
self.exercicesSharedData.state = .completed(level: .nonApplicable)
self.robot.stopLights()
self.midiPlayer.stop()
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,23 +16,38 @@
}

extension GameplayAssociateCategories where ChoiceModelType == GameplayAssociateCategoriesChoiceModel {
// TODO: (@HPezz): Create gameplay related grading table search function & allowedTrials in args

Check warning on line 19 in Modules/GameEngineKit/Sources/_NewSystem/Gameplays/AssociateCategories/GameplayAssociateCategories+DragAndDrop.swift

View workflow job for this annotation

GitHub Actions / swiftlint

TODOs should be resolved ((@HPezz): Create gameplay rela...) (todo)
convenience init(choices: [GameplayAssociateCategoriesChoiceModel], shuffle _: Bool = false) {
self.init()
self.choices.send(choices)
state.send(.playing)

let numberOfChoices = self.choices.value.count
let numberOfRightAnswers = self.getNumberOfRightAnswers(choices: choices)

self.allowedTrials = kDefaultGradingTable[numberOfChoices]![numberOfRightAnswers]!
}

func process(_ choice: ChoiceModelType, _ destination: ChoiceModelType) {
numberOfTrials += 1

if choice.choice.category == destination.choice.category {
updateChoice(choice, state: .rightAnswer)
updateChoice(destination, state: .rightAnswer)

} else {
updateChoice(choice, state: .wrongAnswer)
}

if choices.value.allSatisfy({ $0.state == .rightAnswer }) {
state.send(.completed)
let level = evaluateCompletionLevel(allowedTrials: allowedTrials, numberOfTrials: numberOfTrials)
state.send(.completed(level: level))
}
}

func getNumberOfRightAnswers(choices: [GameplayAssociateCategoriesChoiceModel]) -> Int {
let numberOfCategories = Set(choices.map(\.choice.category)).count
let numberOfCategorizableChoices = choices.map { $0.choice.category != .none }.count

return numberOfCategorizableChoices - numberOfCategories
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ class GameplayAssociateCategories<ChoiceModelType>: StatefulGameplayProtocol
{
var choices: CurrentValueSubject<[GameplayAssociateCategoriesChoiceModel], Never> = .init([])
var state: CurrentValueSubject<ExerciseState, Never> = .init(.idle)
var numberOfTrials: Int = 0
var allowedTrials: Int = 0

func updateChoice(_ choice: ChoiceModelType, state: GameplayChoiceState) {
guard let index = choices.value.firstIndex(where: { $0.id == choice.id }) else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,18 +16,26 @@
}

extension GameplayFindTheRightAnswers where ChoiceModelType == GameplayDragAndDropIntoZonesChoiceModel {
// TODO: (@HPezz): Create gameplay related grading table search function & allowedTrials in args

Check warning on line 19 in Modules/GameEngineKit/Sources/_NewSystem/Gameplays/FindTheRightAnswers/GameplayFindTheRightAnswers+DragAndDropIntoZones.swift

View workflow job for this annotation

GitHub Actions / swiftlint

TODOs should be resolved ((@HPezz): Create gameplay rela...) (todo)
convenience init(choices: [GameplayDragAndDropIntoZonesChoiceModel]) {
self.init()
self.choices.send(choices)
rightAnswers = choices.filter { $0.choice.dropZone != .none }
state.send(.playing)

let numberOfChoices = self.choices.value.count
let numberOfRightAnswers = self.rightAnswers.count

self.allowedTrials = kDefaultGradingTable[numberOfChoices]![numberOfRightAnswers]!
}

func process(_ choice: ChoiceModelType, _ dropZone: DragAndDropIntoZones.DropZone) {
guard rightAnswers.isNotEmpty else {
return
}

numberOfTrials += 1
HPezz marked this conversation as resolved.
Show resolved Hide resolved

if choice.choice.dropZone == dropZone {
updateChoice(choice, state: .rightAnswer)
rightAnswers.removeAll { $0.id == choice.id }
Expand All @@ -36,7 +44,8 @@
}

if rightAnswers.isEmpty {
state.send(.completed)
let level = evaluateCompletionLevel(allowedTrials: allowedTrials, numberOfTrials: numberOfTrials)
state.send(.completed(level: level))
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,18 +16,26 @@
}

extension GameplayFindTheRightAnswers where ChoiceModelType == GameplayTouchToSelectChoiceModel {
// TODO: (@HPezz): Create gameplay related grading table search function & allowedTrials in args

Check warning on line 19 in Modules/GameEngineKit/Sources/_NewSystem/Gameplays/FindTheRightAnswers/GameplayFindTheRightAnswers+TouchToSelect.swift

View workflow job for this annotation

GitHub Actions / swiftlint

TODOs should be resolved ((@HPezz): Create gameplay rela...) (todo)
convenience init(choices: [GameplayTouchToSelectChoiceModel], shuffle: Bool = false) {
self.init()
self.choices.send(shuffle ? choices.shuffled() : choices)
rightAnswers = choices.filter(\.choice.isRightAnswer)
state.send(.playing)

let numberOfChoices = self.choices.value.count
let numberOfRightAnswers = self.rightAnswers.count

self.allowedTrials = kDefaultGradingTable[numberOfChoices]![numberOfRightAnswers]!
HPezz marked this conversation as resolved.
Show resolved Hide resolved
}

func process(_ choice: ChoiceModelType) {
guard rightAnswers.isNotEmpty else {
return
}

numberOfTrials += 1
HPezz marked this conversation as resolved.
Show resolved Hide resolved

if choice.choice.isRightAnswer, rightAnswers.isNotEmpty {
updateChoice(choice, state: .rightAnswer)
rightAnswers.removeAll { $0.id == choice.id }
Expand All @@ -36,7 +44,8 @@
}

if rightAnswers.isEmpty {
state.send(.completed)
let level = evaluateCompletionLevel(allowedTrials: allowedTrials, numberOfTrials: numberOfTrials)
state.send(.completed(level: level))
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ class GameplayFindTheRightAnswers<ChoiceModelType>: StatefulGameplayProtocol
var choices: CurrentValueSubject<[ChoiceModelType], Never> = .init([])
var rightAnswers: [ChoiceModelType] = []
var state: CurrentValueSubject<ExerciseState, Never> = .init(.idle)
var numberOfTrials: Int = 0
var allowedTrials: Int = 0

func updateChoice(_ choice: ChoiceModelType, state: GameplayChoiceState) {
guard let index = choices.value.firstIndex(where: { $0.id == choice.id }) else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,20 @@
import ContentKit
import Foundation

// MARK: - kDefaultGradingTable

typealias GradingTable = [Int: [Int: Int]]

// TODO: (@HPezz): Split into several gameplays gradingTables

Check warning on line 12 in Modules/GameEngineKit/Sources/_NewSystem/Gameplays/GameplayChoiceModels.swift

View workflow job for this annotation

GitHub Actions / swiftlint

TODOs should be resolved ((@HPezz): Split into several g...) (todo)
let kDefaultGradingTable: GradingTable = [
1: [1: 1],
2: [1: 1, 2: 2],
3: [1: 1, 2: 2, 3: 3],
4: [1: 2, 2: 2, 3: 3, 4: 4],
5: [1: 2, 2: 3, 3: 3, 4: 4, 5: 5],
6: [1: 3, 2: 3, 3: 4, 4: 4, 5: 5, 6: 6],
]

// MARK: - GameplayChoiceState

enum GameplayChoiceState {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,28 @@

import Combine

// MARK: - StatefulGameplayProtocol

protocol StatefulGameplayProtocol {
var state: CurrentValueSubject<ExerciseState, Never> { get }

func evaluateCompletionLevel(allowedTrials: Int, numberOfTrials: Int) -> ExerciseState.CompletionLevel
}

extension StatefulGameplayProtocol {
func evaluateCompletionLevel(allowedTrials: Int, numberOfTrials: Int) -> ExerciseState.CompletionLevel {
let trialsPercentage = Double(allowedTrials) / Double(numberOfTrials) * 100.0
switch trialsPercentage {
case 90...:
return .excellent
case 80..<90:
return .good
case 70..<80:
return .average
case 60..<70:
return .belowAverage
default:
return .fail
}
}
}
Loading
Loading