前回まで、ハードウェアがないとプログラムを動作させられなかったので、読者の皆さんにも疑似体験していただけるようパソコンの上で動作が再現できるシミュレータを開発しました。まずこれをご紹介しましょう。
ちなみに、第2回補足ではハードウェアトラブルが起きてしまいましたが、ソフトウェアの方はこのシミュレータを使ってテストしています。
シミュレータとその使い方
シミュレータの動作環境として、PHPの4または5を利用しています。Webサーバから利用できる必要があり、gdライブラリも使いますが、一般的なLinuxのディストリビューションであればどれもパッケージが用意されていると思います。サンプルの制御プログラムを動かす場合にはコマンドライン版のPHPも必要ですが、これもLinux環境なら問題ないと思います。Windowsでも問題なく利用できます。
まず、シミュレータや関連ファイルを以下のリンクからダウンロードしてください。
なお、前回まではコントローラを指すようURLを192.168.0.100にしていましたが、今回からはシミュレータを指すようにしています。
ダウンロードしたファイルを解凍したら、適当なWeb公開用のディレクトリに、simrail.php(シミュレータ本体)とrailconf.txt(設定ファイル)を置きます。railconf.txtはWebサーバから書き換えますので、chmod a+rw railconf.txt
などとして、書き込み権限を与えておいてください。
なお、サンプルはすべて/gh/rail/simrail.phpにアクセスするようになっていますので、ここにファイルを配置すると簡単です。ただしインターネットには公開しない方がよいでしょう(usleepを使っているのでサーバの負荷が高くなります)。
この状態で、上記のsimrail.phpにWebブラウザからアクセスすると、シミュレータの画面が表示されます。初期状態では、環状のレールを車両が2つ走行している状態になります。
先にも書きましたが、プログラムをテストするときは、まずレール配置などを記述したrailconf.txtという名前のファイルを用意します。railconf.txtは実行に従って上書きされてしまいますので、別に用意したテキストファイルからコピーするのがよいでしょう。たとえば前回の最後に紹介した2重ループのレイアウトサンプルであれば、ダウンロードして解凍した中のrail22.txtを使用します。
cp rail22.txt railconf.txt
などとして、railconf.txtに反映してください。これで、シミュレータの画面が変わるはずです。
最後に、線路のレイアウトに応じたプログラム(スクリプト)を実行します。このとき、リスト中のURLを自分のサーバのsimrail.phpを指すように変更してください。
コマンドラインから./rail22.php
などと入力してスクリプトを実行すると、シミュレータの画面に様子が表示されます。起動できない場合は、php -f rail22.php
も試してみてください。
サンプルには、そのほかにも第1回、第2回で扱ったレイアウトに対応したプログラムが入っています。それぞれのスクリプトと設定ファイル(railconf.txtにコピーするもの)は、以下のようになりますので試してみてください。
表1 プログラム(レールレイアウト)とファイル名
直線レイアウト | rail11.txt |
第1回サンプル | rail10.php、rail11.php、rail11a.php |
第2回サンプル | rail21.php |
引き込み線レイアウト | rail12.txt |
第1回サンプル | rail12.php |
2重ループレイアウト | rail22.txt |
第2回サンプル | rail22.php |
シミュレータの仕組み
本題とはあまり関係ないのですが、シミュレータの仕組みについて説明しておきましょう。普通、連続的なシミュレーションには常駐プロセスを使用し、そこと他のプログラムが通信するスタイルを取るのが普通だと思います。ただ、ここではあまり複雑なことをしたくなかったので、以下のような方法にしました。
ブラウザや制御プログラムからsimrail.phpがアクセスされると、railconf.txtを読み込んだあと、前回からの経過時間を調べます。そして、その時間分のシミュレーションをおこなったあと、リクエストや画面表示の処理をおこないます。ゲームで、プレイヤーがいない間に起こったできごとを、前回セーブしたときからの経過時間に応じて、ロード時に再現するものがありますが、それと似たような考え方です。
この方法を使うには、あるリクエストのときに行ったシミュレーションの途中の状態を、次のリクエストに引き継げる必要があります。そこで、railconf.txtにシミュレーションの結果を毎回書き出しています。複数のリクエストが同時に来る可能性があるため、flockで排他処理を行っています。またrefreshを使い、定期的にブラウザに再読み込みさせることで画面を更新し、定期的にリクエストが発生することでシミュレーションが進むようになっています。
車両のオブジェクト化
シミュレータができましたので、さっそく使ってみましょう。今回のテーマは、車両のオブジェクト化です。メインループから、それぞれの車両オブジェクトのstepメソッドを順番に呼び出す形にします。stepメソッドの中では、自分の前方のレールが空いているかどうかを調べ、空いていたらそこまで車両を進めるようにします。stepメソッドの中で待つと、他の車両も動かなくなってしまうので、注意が必要です。
車両の有無は、起動時に全部のレールをセンスすることで自動的に見つけるようにしてみました。これで、車両を適当に配置してからプログラムを実行すれば、自動的に処理に反映されることになります。なお実際には、レールと車輪の接触不良などがあると検出に失敗することがあります(今までのサンプルで、現在のレールから去ったのを検出するのではなく、次のレールに現れたことを検出するようにしていたのは、このためです)。
2つの車両が1つのレールに入らないように、レールのオブジェクトの中に「使用中」のフラグを用意しました。これから進もうとする先のレールが使用中であれば、いったんstepメソッドからリターンし、次回stepメソッドが呼ばれたときにもう一度挑戦します。使用中でなければ、自分が使用中にして、そこまで車両を進めます。進んだら、いま来たレールの使用中を解除します。今回は、使用中フラグの管理をlockメソッドで行うようにしました。
次回は、今回作成したシミュレータ用のレイアウトエディタを作ってみます。