Home > AI > IOS >

Finite State Machine

Get a taste. This example shows using finite state machine to App Page management. It incudes reduce func to transit state, error handling for transition failure and backup plan.

import SwiftUI



struct Episode { }
struct Level { }


enum State {
    case introduction // On the first page of the game
    case help // In the help screen
    case choosingEpisode // Choosing an episode
    case choosingLevel(Episode) // After choosing an episode, player is now choosing
        // a level
    case playingLevel(Episode, Level) // Now playing the chosen level
    case finishedLevel(Episode, Level, Int) // Finished a level, displaying their
        // score.
}


enum Event {
    case displayHelp // Takes the user from the intro to the help screen.
    case dismissHelp // Takes the user back to the intro from help.
    case startPlaying // Takes the user from the intro to the episode chooser.
    case chooseEpisode(Episode) // The user selected an episode, so take
        // the user from the episode chooser to the level chooser.
    case chooseLevel(Level) // The user selected a level, so take the user
        // from the level chooser to the gameplay.
    case completeLevel(Int) // Takes the user from gameplay to the completed
        // level screen, displaying their achieved score.
    case dismissFinishedLevel // Takes the user from the completed level
        // screen back to the level chooser to play again.
}




class FiniteStateMachine {
    /// singleton
    static let shared = FiniteStateMachine()
    
    
    ///. initial state
    var state = State.introduction
    

    /// This selects the appropriate transition to handle the event.
    /// The choice of transition may depend upon the old state.
    func reduce(event: Event) throws -> State {
        switch (state, event) {
        
        case (.introduction, .displayHelp):
            return presentHelp()
            
        case (.help, .dismissHelp):
            return dismissHelp()
            
        case (.introduction, .startPlaying):
            return presentEpisodeChooser()

        case (.choosingEpisode, .chooseEpisode(let episode)):
            return presentLevelChooser(episode: episode)
            
        case (.choosingLevel(let episode), .chooseLevel(let level)):
            return presentGamePlay(level: level)
        
        default:
            throw MyErrors.transitionNotFound
        }
    }
    
    enum MyErrors: Error {
        case transitionNotFound
    }
    
    
    func presentHelp() -> State {
        return State.help
    }
    
    func dismissHelp() -> State {
        // ?
        return State.introduction
    }
    
    func presentEpisodeChooser() -> State {
        return State.choosingEpisode
    }
    
    
    func presentGamePlay(level: Level) -> State {
        return State.playingLevel(Episode(), Level())
    }
    
    
    func presentLevelChooser(episode: Episode) -> State {

//        let levelChooser = ...create level chooser view controller...
//        levelChooser.levels = episode.levels
//        NavigationManager.shared.rootNavController
//            .pushViewController(levelChooser, animated: true)

        // Return the new state
        return State.choosingLevel(episode)
    }

}

Leave a Reply