Seriaの6角形のミラー風タイルシールでお手軽に鏡の中のサッカーボール

Seriaで「ミラー風タイルシール」という六角形のミラーの3つ入りを見つけたので買ってみました。

Seriaの「ミラー風タイルシール」

なんとなく、三角形に見立てて三角錐の万華鏡のようにしてみました。

三角錐風ミラー

そして、ルマンドの袋にくっつけて見ると、なんと、ルマンドの正二十面体が現れました!

ルマンド

後で調べてみると、「鏡の中のサッカーボール」に近いもののようです。

polyhedra.cocolog-nifty.com

平らなものにくっつけることでなんでも正二十面体化ができるので、今回の六角形のミラーから作るパターンの方が遊びやすいかも。

いくつか試してみました。

ダンボー

定規(方眼模様)

地球の画像を表示したスマホ

さてこれはなんでしょう。

青く光るもの

答えは、LED付きの加湿器でした。

LED付きの加湿器

gym-super-mario-brosのマリオのスピードを取得する

gym-super-mario-brosのマリオの座標だけでなくスピードを取得する方法がわかったのでメモします。

方針

スーパーマリオのメモリマップからx方向とy方向のスピードを探し出して、取得します。

メモリマップの参考

Super Mario Bros.:RAM map - Data Crystal

A Comprehensive Super Mario Bros. Disassembly · GitHub

実装

下記のように SuperMarioBrosEnv クラスに x_speed メソッドと y_speed メソッドを実装します。 元々あった_x_positionメソッド_y_positionメソッドをマネしています。

def x_speed(self):
  s = self.ram[0x57]
  return s if s < 0x80 else s - 0x100

def y_speed(self):
  s = self.ram[0x9f]
  return s if s < 0x80 else s - 0x100

SuperMarioBrosEnv.x_speed = x_speed
SuperMarioBrosEnv.y_speed = y_speed

_x_position メソッドや _y_position メソッドと同様に _ で始まるメソッド名にしようかとも考えたのですが、そうするとWrapperクラスもメソッドを追加する手間が増えるので、 _ はつけませんでした。

今回のColab

colab.research.google.com

Colabの中で動かすとコマ送りできるので研究がはかどります。

gym-super-mario-brosのジャンプの研究

前回からの続きです。 akiyah.hatenablog.com

今回は、gym-super-mario-brosのジャンプを研究します。

最大ジャンプのAボタンフレーム数

Aボタンを押すとジャンプするのですが、押している長さに応じて高さが変わるようです。 もちろんずーっと押し続けると最大ジャンプをするのですが、何フレーム押し続ければ最大ジャンプと同じジャンプをするのか調べてみました。

ジャンプ

Aボタンを押し続けるフレーム数を何パターンか調べたところ、25フレームが最大ジャンプであることがわかりました。それ以上押しても同じ高さですし、24フレームだと少しだけ滞空時間が短いようです。

連続ジャンプ

試してわかったのですが、ずーっとAボタンを押し続けても一回しかジャンプしてくれません。Aボタンを離してから再び押すと次のジャンプをしてくれるようです。(ファミコンスーパーマリオはこうだったのか、覚えていません。)

連続ジャンプ

調べてみると、最大ジャンプの場合、着地する45フレーム目の2フレーム前である43フレーム目でAボタンが離れていて、その次のフレームからAボタンを押し続けると、連続ジャンプをしてくれるようです。 ジャンプしてから落下中にAボタンを離しておいて、着地直前にAボタンを押せば、隙間なく連続でジャンプしてくれるのですね。(なかなかシビアです)

今回のColab

colab.research.google.com

アニメーションgifと違って、Colabの中だと1フレームずつ動かすことができるので、研究する時はこちらがオススメです。

Colabの中では1フレームずつ動かすことができる

gym-super-mario-bros 1-1を1歩ずつ5歩先のrewardを計算してクリアする

前回の続きです。 akiyah.hatenablog.com

backupした状態までresetで戻れるようになったので、それを使ってマリオの1-1をクリアしてみました。

行動は「走る(["right", "B"])」か「走りながらジャンプ(["right", "B", "A"])」の2通りです。5歩先までマリオを進めて、その時のrewardを記録し、resetして戻ります。25=32パターンのうちで一番大きいrewardに繋がる1歩目を採用して進み、そこでbackupします。

複数パターンに分裂するマリオのイメージ

この手順をゴールするかゲームオーバーまで繰り返します。20分ほどの計算で、見事ゴールしてくれました!

1-1をゴールするマリオ

「走る」と「走りながらジャンプ」のうち、「走る」の方を優先しているロジックになっているからか、低いジャンプで進んでいることがわかりますね。

Google Colaboratoryも貼っておきます。 colab.research.google.com

ちなみに、1歩=4フレームです。1フレームごとに操作できるので、1フレームごとに次の行動を計算してもいいのですが、計算が多くなるので1歩=4フレームくらいが良さそうです。

クリアした後にソースコードを少し変更したりして試してみたのですが、どうもこのクリアは偶然らしくて、ちょっといじるとゴールできなかったりします。どう操作しても5歩先でゲームオーバーになってしまうような状況におちいってしまうことがあるようです。ジャンプしてしまって10歩先くらいでガケに落ちるような。(行動が「走る」か「走りながらジャンプ」だけでやっているのでブレーキとかかけられないんですよね)

5歩先ではなく10歩先、あるいはもっと先までを計算対象にしたらいいのでしょうが、そうすると計算量が爆発的に増えてしまうので、何かいい方法がないか考えてみようと思っています。

gym-super-mario-brosで途中から再開する方法

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のクラスにメソッドを後から追加する方法を調べて、手探りで書いてみました。

# Wrapperクラスにbackupメソッドを追加
def backup(self):
  if hasattr(self.env, "_backup"):
    self.env._backup() # gym_super_mario_bros.smb_env.SuperMarioBrosEnv#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

わかりにくいかもしれませんが、最初はクリボーにぶつかってやられているけど、ちょっと戻ってジャンプで回避しています。

Maker Faire Tokyo 2022 にベランダラボで出展しました

前回の続きです。出展してきました。

akiyah.hatenablog.com

 

9月2日(金)は会社を休んで作品を半分運んで、9月3日(土)に残りの半分の作品を運んで、そのままイベントに入りました。

9月4日(日)は、家族(奥さんとむすめ2人)も来て、手伝ってくれました。

 

今回は、牛乳パックフエを展示・販売したのですが、多くの子供たちに触ってもらえてとても嬉しかったです。押したら音が出るという単純さがよかったのかなと思いました。

 

下のむすめ(小学1年生)がPOPみたいなものをたくさん作ってくれました。お客さんにテンセグリティの作り方の説明もしてくれました。本当の(?)お店屋さんをするのが楽しかったみたいですね。

("2しゅるい"というのは、牛乳パックフエにはまっすぐねじるタイプの2種類の折り方があるという意味です)

 

まえこっかくのSUZUKIさんが見に来てくれたのはとても嬉しかったです。紙パックフエの前に円筒ねじり折りに興味を持ったのはまえこっかくのSUZUKIさんが何年か前のMakerFaireで発表されていた人工筋肉でした。今回も、まっすぐよりねじるタイプの方が伸縮がいいという助言をその場で教えてもらって、参考になりました。

その後、紙パックの研究を始めたようで、フットワークが軽いですね!

 

ところで、ベランダラボはD-02-01だったのですが、お隣のD-02-02twitterでよく拝見していた藤田伸さんで、とてもハイクオリティなテンセグリティを展示されていました!販売していたテンセグリティキットも完売されていましたよ。

 

牛乳パックフエは20個くらい販売することができました。作ったものの2/3くらいですかね。牛乳パックフエは、もうちょっと成長させて新しい形に挑戦していきたいです。 いずれ牛乳パックフエの知名度が上がって、小学校の夏休みの工作に使われたりしたら嬉しいなぁ。

Maker Faire Tokyo 2022 にベランダラボで出展します(牛乳パックフエとテンセグリティ)

2022年9月3日(土)、4日(日)のMaker Faire Tokyo 2022にベランダラボで出展します。

 

makezine.jp

 

 

いつものテンセグリティに加えて、今回から作成した牛乳パックフエを展示します。

牛乳パックが伸び縮みして、音を出すことができます。よく見ると2種類ありますよ。

今回は販売ができるようなので、たくさん作ってみました。