ローファイ日記

出てくるコード片、ぼくが書いたものは断りがない場合 MIT License としています http://udzura.mit-license.org/

wasmbotsをRubyで遊ぼう

まず、wasmbotsとは

という話をしないといけません。これはwasmバイナリを作って、ダンジョン探索をするゲームです。

shaneliesegang.com

具体的には?

ダンジョンを探索するためのプログラムを書いて、それを特定のインタフェースを満たしたWASMファイルにコンパイルすれば、あとはそれをアップロードすることでプレイヤーに自動でダンジョン探索をさせることができる、というブラウザゲームです。

プロジェクトのサンプルダンジョンにアクセスしてみれば即イメージが掴めると思います。

shaneliesegang.com

アクセスしたら、いくつかプリセットでアルゴリズムが用意されていることがわかります。

プリセットのプログラムのリスト

適当に1つ選んだら ▶️ のボタンを押すと探索が始まります。

同じように、ダンジョン探索のアルゴリズムを任意の言語で書いて、WASMにコンパイルしてアップロードしたら、自分のコードでプレイヤーにダンジョンを探索させられます。

ただ、任意の言語と言っても、以下の条件を満たしたWASMを生成できないといけません*1

  • 特定の関数をexportするよう指定しなければならない
    • 以下の4つ
      • void clientInitialize(void)
      • size_t setup(size_t requestReserve)
      • bool receiveGameParams(size_t offset)
      • void tick(size_t offset)
  • 特定の関数をimportして利用することも可能である
    • int32_t getRandomInt(int32_t min, int32_t max), void logFunction(int logLevel, unsigned int msgPtr, unsigned int msgLen), void shutdown(void) が用意されている

この条件では例えばGo(GOARCH=wasm などの場合)、そしてRuby.wasmではちょっと難しいかもしれません。また、WASM GCの環境に依存した言語だと動くブラウザと動かないブラウザが出てきそうに思います。

公式のサンプルでは以下の言語が用意されています。

  • C
  • Rust
  • Zig
  • AssemblyScript
  • tinygo

これらのサンプルをベースにコードを少しずつ変えて遊んでみることができそうです。WASMの素振りにも良い題材ではないでしょうか。

ところで、せっかくなので...

wasmbotsをRubyで遊ぶ手順を紹介しますね...。

*1:インタフェースの表現はC関数に合わせました

続きを読む

mruby/edge バージョン 1.0.3 の話【募集あり】

mruby/edge バージョン 1.0.3 を出した。

これは mruby/edge バージョン 1.0.0 ではないのかという話だが、ちょっと前に 1.0.0 を出したのだが、その時点では Hash と Object#== がなかったりしたので後から追加していたらバージョンを上げることになったため。

続きを読む

Rust + WASM Component + mruby/edge (w/ WASI p2!) のバイナリを作る【令和最新版】

令和最新版、と一度言ってみたかった。

先日、手作りでWASM Componentのバイナリを作ってみたんですが、mruby/edgeは全部Rustで書いているので、では最近のRustではどうするといいかをしゅっと残しときます。

結論ファースト

zenn.dev

ここに書いてある通りです 〜完〜

が、世の中割とcargo-componentベースの手順が多かったりするので、少しでも新しい情報を多くしようかなと思って(あと自分の理解のため)ブログに残しておきます。

続きを読む

RubyスクリプトからComponent Model対応WASMバイナリを作った(実験的バージョン)

まずは実験的ツールの紹介

componentize_any というコマンドラインツールを作りました。Rubyで書いたので以下の方法でインストールしてください。

$ gem install componentize_any
## もしくは
$ git clone https://github.com/udzura/componentize_any.git && cd componentize_any
$ bundle install

以下のようなスクリプトを用意します。(wittyファイルとでも名付けました)

witty do
  world do
    export "wasi:cli/run@0.2.0"
  end

  package "wasi:cli@0.2.0" do
    interface "run" do
      define "run", :func, {[] => :result}, counterpart: "component_run"
    end
  end
end

以下のようなRubyRBSのファイルを用意し、 mec コマンドをインストールしていわゆる普通の(WASI p1依存なしの)WASMバイナリを用意。

# run.rb
def component_run
  0
end
# run.export.rbs
def component_run: () -> Integer
$ cargo install mec --version=1.0.0-rc3
$ mec --no-wasi run.rb
$ file run.wasm
run.wasm: WebAssembly (wasm) binary module version 0x1 (MVP)

mec とはRubyスクリプトをCore WASMのバイナリにコンパイルするコマンドです。以下の記事などで解説しています。

udzura.hatenablog.jp

これらが揃ったら componentize_any でComponentを作ることができます。

$ bundle exec componentize_any \     
      -witty-file witty.rb \
      --input run.wasm \
      --output out.wasm

Writing WAT to /var/folders/sv/...
Compiling WAT to WASM0: /var/folders/sv/...
joining WASM0 files with run.wasm
created out.wasm
run to check: `wasm-tools dump out.wasm 2>&1 | less`

ちゃんとWIT表現を取り出せることを確認。

$ wasm-tools component wit out.wasm
package root:component;

world root {
  export wasi:cli/run@0.2.0;
}
package wasi:cli@0.2.0 {
  interface run {
    run: func() -> result;
  }
}

このComponentは wasi:cli/run@0.2.0 を実装しているので、現在の wasmtime ならそのままファイルを渡して実行可能です。実行が(何も警告を吐かずに)成功することを確認します。

$ wasmtime out.wasm
$ echo $?          
0

この時、RubyスクリプトKernel#component_run1 を返すようにして再度この手順を踏めば、実行は正しく失敗します。

続きを読む

mruby/edge のVMを書き換えた

明けましておめでとうございます!

タイトルの通り。mruby/edge のVMを、mruby/c 1.2 相当の内容に書き換えた。

mruby/c 1.2 の実装は以前軽く読んだ。

udzura.hatenablog.jp

PRはめちゃでかい。 +2,605 −1,376 だそうです。

github.com

合わせてcrateをいくつかリリースした。

mruby/edgeとmecのcrateを更新した。以下でmecを更新してください。なぜかもう rc3 ですが、ええじゃないですか。

$ cargo install mec --version=1.0.0-rc3
$ mec --version                        
Version: 1.0.0-rc3
続きを読む