mario_backup_reset.gif
日曜日の勉強会 の仲間が「マリオAIチャレンジ」をやっているのを見ていて、楽しそうだったので最近触っています。
karaage.hatenadiary.jp
まだ学習をさせるところまでは行けていなくて、マリオに行動を配列で指示したり、gifなどの画像に出力させるところをいじくっているところです。
ところで、途中まで進んだマリオを、そこから再開できる方法があるか考えていました。それができれば計算が早くなるという想定です。最初はdeepcopyでできるのではないかと考えたのですが、やってみるとうまくいきませんでした。おそらくNES emulator (=nes_env.pyの_LIBオブジェクト )がpython のdeepcopyでは適切にコピーされないのだと思います。
不慣れなPython なのですが、コードをがんばって追いかけると、nes_env.py の_backupメソッド とresetメソッド を呼べば良さそうなことまでわかりました。backupメソッドを呼ぶとその箇所が保存されて、その後のresetメソッドではそこに戻ることができるようです。
しかし、resetメソッドはSuperMarioBrosEnv から呼べるのですが、 backupメソッドは外部に公開されていないメソッドなので、使えないようなのです。困った。
いろいろ調べたところ、envオブジェクトはWrapper クラスのサブクラスの複数回の委譲を繰り返してSuperMarioBrosEnv(そしてNESEnv )に到達するようで、このWrapperクラスにbackupメソッドを追加すれば良さそうだということに気がつきました。
Pythonのクラスにメソッドを後から追加する方法 を調べて、手探りで書いてみました。
def backup (self):
if hasattr (self.env, "_backup" ):
self.env._backup()
else :
self.env.backup()
Wrapper.backup = backup
(↑2023/01/08 22:55修正)
backupメソッドを持つオブジェクトが見つかるまで委譲先を探して、backupメソッドを持つオブジェクト(SuperMarioBrosEnvクラスのオブジェクト)が見つかったらそれを実行します。
やってみると、うまくいくようです。やった!
ちなみに、Wrapperクラスは委譲の仕組みが入っている ので、resetメソッドは何もしなくても委譲されてSuperMarioBrosEnvクラスのresetメソッドが呼ばれます。SuperMarioBrosEnvクラスの_backupメソッドが委譲されていなかったのは、 _
で始まるメソッド名だからです。
(2023/01/08 22:55追記)
Google Colaboratoryも、最小限のコードでの再現環境として作っておきました。
colab.research.google.com
わかりにくいかもしれませんが、最初はクリボー にぶつかってやられているけど、ちょっと戻ってジャンプで回避しています。