Eyes, JAPAN Blog > transitionsでステートマシンを扱う [Python]

transitionsでステートマシンを扱う [Python]

Seiya Kobayashi

この記事は1年以上前に書かれたもので、内容が古い可能性がありますのでご注意ください。

こんにちわ、アルバイトの小林です。

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を使ってステートマシンを記述しました。

便利!!!

Comments are closed.