Code Monkey home page Code Monkey logo

persephone's Introduction

persephone

Persephone is an Abstract Finite State Machine/Transducer, which means, the primary usage is pretty much just embedding it to any form of an FSM struct/implementation (mealy or moore machine) one is creating. For efficiency, it uses bitset for states and inputs.

// STATES
const (
	OPENED State = iota
	CLOSED
	CLOSED_AND_LOCKED
)

// INPUTS
const (
	OPEN Input = iota
	CLOSE
	LOCK
	UNLOCK
)

// Sample DoorFSM, a classic one. AbstractFSM will be embedded here (to compensate for Golang's lack of inheritance).
type DoorFSM struct {
	*persephone.AbstractFSM
}

func NewDoorFSM(states States, inputs Inputs) *DoorFSM {
	// pass states and inputs to abstractFSM
	return &DoorFSM{
		AbstractFSM: New(states, inputs),
	}
}

func (fsm *DoorFSM) UnlockAction() error {
	fmt.Println("unlocking action.")
	return nil
}

// Callback on an action, say, actions that affects recognized lexemes
func (fsm *DoorFSM) InputAction() error {
	fmt.Println("input detected.")
	return nil
}

// sample transition callback when transitioning from closed to opened
func (fsm *DoorFSM) OpenAction() error {
	fmt.Println("open action.")
	return nil
}

func (fsm *DoorFSM) CloseEntryAction() error {
	fmt.Println("close entry action.")
	return nil
}

func (fsm *DoorFSM) CloseExitAction() error {
	fmt.Println("close exit action.")
	return nil
}

func main() {
	// initialize states, either do the things below inside the NewDoorFSM, init() or outside.
	// when initial state isn't set, the first added state defaults as the initial state. Please be cautious with state orders when no 
	// INITIAL_STATE is specified.
	var states States
	states.Add(OPENED, INITIAL_STATE)
	states.Add(CLOSED, NORMAL_STATE)
	states.Add(CLOSED_AND_LOCKED, NORMAL_STATE)

	// initialize accepted inputs, either do the things below inside the NewDoorFSM, init() or outside.
	var inputs Inputs
	inputs.Add(OPEN)
	inputs.Add(CLOSE)
	inputs.Add(LOCK)
	inputs.Add(UNLOCK)

	fsm := NewDoorFSM(states, inputs)

	// Either do these inside our NewDoorFSM, an init() or outside, just like below.
	// Call convention pattern is utilized since AbstractFSM is embedded.
	// Add transition rules [entryState, input, targetState, transitionCallback]
	fsm.AddRule(OPENED, CLOSE, CLOSED, nil)
	fsm.AddRule(CLOSED, OPEN, OPENED, nil)
	fsm.AddRule(CLOSED, LOCK, CLOSED_AND_LOCKED, nil)
	fsm.AddRule(CLOSED_AND_LOCKED, UNLOCK, CLOSED, fsm.UnlockAction)

	fsm.AddInputAction(CLOSED_AND_LOCKED, UNLOCK, fsm.UnlockAction)
	fsm.AddTransitionAction(CLOSED, OPENED, fsm.OpenAction)
	fsm.AddEntryAction(CLOSED, fsm.CloseEntryAction)
	fsm.AddExitAction(CLOSED, fsm.CloseExitAction)

	// Now let's process inputs
	fsm.Process(CLOSE)
	fmt.Printf("%d \n\n", fsm.GetState())

	fsm.Process(LOCK)
	fmt.Printf("%d \n\n", fsm.GetState())

	fsm.Process(UNLOCK)
	fmt.Printf("%d \n\n", fsm.GetState())

	fsm.Process(OPEN)
	fmt.Printf("%d \n\n", fsm.GetState())

	// to check if it accepts invalid transitions
	err := fsm.Process(LOCK)
	fmt.Printf("%s \n", err.Error())                // you could stop here now
	fmt.Printf("%d \n\n", fsm.GetState()) // still opened, the door's last state.

	// to check if it accepts further valid transitions after previous invalid
	fsm.Process(CLOSE)
	fmt.Printf("%d \n\n", fsm.GetState())

	// can't do this too when it's just closed, door should be locked first
	err_a := fsm.Process(UNLOCK)
	fmt.Printf("%s \n", err_a.Error()) // you could stop here now
	fmt.Printf("%d \n\n", fsm.GetState()) // still closed

	// Can() checks if you can go to a certain state without tripping the callbacks
	fmt.Println(fsm.Can(OPEN)) // you can open
	fmt.Println(fsm.Can(LOCK)) // or lock
	fmt.Println(fsm.Can(CLOSE)) // but not close
	fmt.Println(fsm.Can(UNLOCK)) // or unlock
}

Example

Go to the sample DoorFSM for a classic FSM example.

More examples to come.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.