Skip to content

Instantly share code, notes, and snippets.

@llatzhar
Created June 10, 2009 01:41
Show Gist options
  • Save llatzhar/126958 to your computer and use it in GitHub Desktop.
Save llatzhar/126958 to your computer and use it in GitHub Desktop.
HSM
# 1 state 1 block
module Hsm
class Event
def initialize(name)
@name = name
end
end
# system events
INIT = Event.new('INIT')
ENTER = Event.new('ENTER')
EXIT = Event.new('EXIT')
SUPER = Event.new('SUPER')
module Machine
def initHsm
@states = {}
@cur = nil
end
def register(name, &block)
@states[name] = block
end
def start(name)
# TODO 順に入っていく
@cur = name
dispatch(ENTER)
end
def to_top(from)
a = []
s = from
while s != :top
a << s
s = _super(s)
end
a << :top
end
def lca(from, to)
l = :top
i = 0
while true
if from[i] != to[i]
break
else
l = from[i]
end
i += 1
end
l
end
# TODO おかしい気がする? cur != src
def trans(dest)
#puts "TRANS: from=#{@cur.inspect} to=#{dest.inspect}"
if @cur == dest
trigger(@cur, EXIT)
trigger(dest, ENTER)
else
cur2top = to_top(@cur)
dest2top = to_top(dest)
ancestor = lca(cur2top.reverse, dest2top.reverse)
#puts "lca=#{ancestor.inspect}"
# EXIT: cur -> lca
cur2top[0, cur2top.index(ancestor)].each do |s|
trigger(s, EXIT)
end
# ENTER: lca -> dest
dest2top[0, dest2top.index(ancestor)].reverse.each do |s|
trigger(s, ENTER)
end
@cur = dest
end
end
def trigger(state, event)
@states[state].call(event)
end
def _super(state)
@states[state].call(SUPER)
end
def dispatch(event)
st = @cur
while true
#puts "START DISPATCH: st=#{st.inspect} ev=#{event.inspect}"
s = trigger(st, event)
#puts "return = #{s.inspect}"
if s != 0 and s != :top
st = s
else
break
end
end
#puts "END DISPATCH"
end
end
end
if __FILE__ == $0
#main
#define events
module Hsm
TIRE = Event.new('TIRE')
ALERM = Event.new('ALERM')
end
# define state machine
class MyMachine
include Hsm::Machine
def initialize
init
register(:sleeping) do |e|
puts @cur.inspect + ' ' + e.inspect
case e
when Hsm::ENTER
puts 'sleep.'
next 0
when Hsm::TIRE
puts 'sleeping.'
next 0
when Hsm::ALERM
puts 'ooohh'
trans(:sitting)
next 0
when Hsm::EXIT
puts 'awake?.'
next 0
end
next :top
end
register(:awake) do |e|
puts @cur.inspect + ' ' + e.inspect
case e
when Hsm::ENTER
puts 'awake.'
next 0
when Hsm::TIRE
puts 'im tired.'
trans(:sitting)
next 0
when Hsm::ALERM
puts 'uuum?'
next 0
when Hsm::EXIT
puts 'dance end.'
next 0
end
next :top
end
register(:dancing) do |e|
puts @cur.inspect + ' ' + e.inspect
case e
when Hsm::SUPER
next :awake
when Hsm::ENTER
puts 'dance start.'
next 0
when Hsm::TIRE
puts 'im tired.'
trans(:sitting)
next 0
when Hsm::EXIT
puts 'dance end.'
next 0
end
next :awake
end
register(:sitting) do |e|
puts @cur.inspect + ' ' + e.inspect
case e
when Hsm::SUPER
next :awake
when Hsm::ENTER
puts 'start sitting.'
next 0
when Hsm::TIRE
puts 'yes, im tired yet.'
trans(:sleeping)
next 0
when Hsm::EXIT
puts 'end sitting.'
next 0
end
next :awake
end
start(:dancing)
end
end
m = MyMachine.new
m.dispatch(Hsm::ALERM)
m.dispatch(Hsm::TIRE)
m.dispatch(Hsm::TIRE)
m.dispatch(Hsm::ALERM)
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment