Skip to content

Instantly share code, notes, and snippets.

@pbosetti
Created November 17, 2011 10:16
Show Gist options
  • Save pbosetti/1372852 to your computer and use it in GitHub Desktop.
Save pbosetti/1372852 to your computer and use it in GitHub Desktop.
Simple State Machine
#!/usr/bin/env ruby
# stama.rb
# Created by Paolo Bosetti on 2011-10-07.
# Copyright (c) 2011 University of Trento. All rights reserved.
class State
attr_accessor :id, :next, :machine
def initialize(id, &action)
@next = nil
case id
when Symbol
@id = id
when Hash
@id = id.keys[0]
@next = id.values[0]
else
raise ArgumentError
end
if block_given?
@action = action
else
@action = Proc.new { p @id; sleep 0.5; @next }
end
@machine = nil
@count = 0
@last_call = Time.now
end
def exec
now = Time.now
@dt = now - @last_call
@last_call = now
@count += 1
result = @action.call(@count, @dt)
if self.respond_to? :action
result = self.action
end
if result != @id
@count = 0
warn "resetting"
end
@next || result
end
end
class Machine
attr_accessor :states
attr_accessor :running
attr_accessor :override
def initialize
@states = {}
@running = false
@state = nil
@override = nil
end
def <<(state)
raise ArgumentError unless state.kind_of? State
state.machine = self
@states[state.id] = state
end
def run(id)
@running = true
@state = @states[id]
while @running do
if @override
result = @override
@override = nil
else
result = @state.exec()
end
case result
when Symbol
@state = @states[result]
when nil
@running = false
end
end
end
end
m = Machine.new
Signal.trap("INT") do
warn "Restarting from :a"
m.override = :a
end
class MainState < State
def action
puts "This is an action \##{@count}"
end
end
m << MainState.new(:a => :b)
m << State.new(:b => :c) { puts "BING!"}
m << State.new(:c) do |i, dt|
puts "c:#{i}, #{dt}, #{@next}"
sleep 0.1
i > 50 ? :d : :c
end
m << State.new(:d => nil)
m.run(:a)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment