開発
transitionsでステートマシンを扱う [Python]
Seiya Kobayashi
こんにちわ、アルバイトの小林です。
pythonでステートマシンを扱うライブラリが便利だったので紹介します。
transitionsです。他にもライブラリはありますが、transitionsはREADMEで’good example is worth’と言っているようにサンプルが整っているのと、開発も活発のようなので選びました。
$ pip install transitions
でインストールできます。
ステートマシンとは、状態遷移を管理する機会・システムです。現在の状態(と入力)から遷移先を決定します。
if文では書ききれず、コードが汚くなってしまう時にもステートマシンを使って遷移を記述するのも良いと思います。
ゲームではよく使われていて、分かりやすいのでゲームを例にとります。
以下の画像のように「歩き」「走り」「ジャンプ」「走りジャンプ」の状態があり、
- 「歩き」の時に、'×が押されれば'、「ジャンプ」
- 「歩き」の時に、'R1が押されれば'、「走り」
- 「走り」の時に、'×が押されれば'、「走りジャンプ」
- 「走り」の時に、'R1が離されれば'、「歩き」
- 「ジャンプ」の時に、'×が離されれば'、「歩き」
- 「走りジャンプ」の時に、'×が離されれば'、「走り」
という状態遷移をtransitionsで記述したいと思います。
と言っても簡単で、まずは状態を記述します。
states = ['walking', 'running', 'jumping', 'running_jump']
次に状態遷移をtransitionsとして記述します。
transitions = [
{ 'trigger': 'push_x', 'source': 'walking', 'dest': 'jumping' },
{ 'trigger': 'push_r1', 'source': 'walking', 'dest': 'running' },
{ 'trigger': 'push_x', 'source': 'running', 'dest': 'runnning_jump' },
{ 'trigger': 'pull_r1', 'source': 'running', 'dest': 'walking' },
{ 'trigger': 'pull_x', 'source': 'jumping', 'dest': 'walk' },
{ 'trigger': 'pull_x', 'source': 'running_jump', 'dest': 'runnning' }
]
「source」の時に、'trigger'が起きれば、「dest」に遷移すると言った感じです。
'after': text_func
と書くと遷移した後に、任意の関数を呼んだりもできます。
これらを元にステートマシンを作成します。initialに初期状態を渡します。
machine = Machine(states=states, transitions=transitions, initial='walking')
これで、最初に示したステートマシンができました。
遷移させるには、machine.trigger_name()
です.
初期状態(walking
)からjumping
に遷移させましょう。
>>> machine = Machine(states=states, transitions=transitions, initial='walking')
>>> machine.state
'walking'
>>> machine.push_x()
True
>>> machine.state
'jumping'
jumping
時にpush_r1
を呼んで見ましょう。
>>> machine.state
'jumping'
>>> machine.push_r1()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/Users/koba/.pyenv/versions/3.6.1/lib/python3.6/site-packages/transitions/core.py", line 284, in trigger
return self.machine._process(f)
File "/Users/koba/.pyenv/versions/3.6.1/lib/python3.6/site-packages/transitions/core.py", line 833, in _process
return trigger()
File "/Users/koba/.pyenv/versions/3.6.1/lib/python3.6/site-packages/transitions/core.py", line 304, in _trigger
raise MachineError(msg)
transitions.core.MachineError: "Can't trigger event push_r1 from state jumping!"
こんな感じで、未定義の遷移はできませんが、強制的に遷移させる関数が用意されます。to_state()
です。
>>> machine.state
'jumping'
>>> machine.to_running_jump()
True
>>> machine.state
'running_jump'
と言った感じで、transitionsを使ってステートマシンを記述しました。
便利!!!