Webプログラマの夏休み PHPでNゲージ模型を自由自在に動かそう[動画つき]

第3回 シミュレータ作りました

この記事を読むのに必要な時間:およそ 5 分

車両のオブジェクト化

シミュレータができましたので,さっそく使ってみましょう。今回のテーマは,車両のオブジェクト化です。メインループから,それぞれの車両オブジェクトのstepメソッドを順番に呼び出す形にします。stepメソッドの中では,自分の前方のレールが空いているかどうかを調べ,空いていたらそこまで車両を進めるようにします。stepメソッドの中で待つと,他の車両も動かなくなってしまうので,注意が必要です。

車両の有無は,起動時に全部のレールをセンスすることで自動的に見つけるようにしてみました。これで,車両を適当に配置してからプログラムを実行すれば,自動的に処理に反映されることになります。なお実際には,レールと車輪の接触不良などがあると検出に失敗することがあります(今までのサンプルで,現在のレールから去ったのを検出するのではなく,次のレールに現れたことを検出するようにしていたのは,このためです)⁠

2つの車両が1つのレールに入らないように,レールのオブジェクトの中に「使用中」のフラグを用意しました。これから進もうとする先のレールが使用中であれば,いったんstepメソッドからリターンし,次回stepメソッドが呼ばれたときにもう一度挑戦します。使用中でなければ,自分が使用中にして,そこまで車両を進めます。進んだら,いま来たレールの使用中を解除します。今回は,使用中フラグの管理をlockメソッドで行うようにしました。

図1 レールセンスできるように接続したループレイアウト

図1 レールセンスできるように接続したループレイアウト

レールセンスできるように接続したループレイアウト

リスト3 rail31.txt(シミュレータ用設定ファイル)

R00,2010,2713
R01,2713,3020
R02,3020,2727
R03,2727,2030
R04,2030,1327
R05,1327,1020
R06,1020,1313
R07,1313,2010

TA,2010,1313,50
TB,2030,2727,50
S0000,AAAAAAAA

リスト4 rail31.php(オブジェクト化サンプルスクリプト)

#! /usr/local/bin/php
<?php

$url = "http://localhost/gh/rail/simrail.php5";

class	rail {
    var    $number;
    var    $lockcount = 0;
    function    rail($number = "00") {
        $this->number = $number;
    }
    function    drive($speed = 0) {
        global    $url;
        
        if ($speed >= 0)
            $command = substr("ABCDEF", min($speed, 5), 1);
        else
            $command = substr("abcdef", min(-$speed, 5), 1);
        file_get_contents($url."?".$this->number."=".$command);
    }
    function    sense() {
        global    $url;
        
        return file_get_contents($url."?".$this->number."=S") + 0;
    }
    function    lock($mode = 1) {
        printf("rail(%s)->lock(%d) lockcount(%d)\n", $this->number, $mode, $this->lockcount);
        switch ($mode) {
            default:
                die("lock({$mode})");
            case    0:
                if (($this->lockcount--) <= 0)
                    die("unlock failed.");
                return;
            case    1:
                if ($this->lockcount > 0)
                    return -1;    /* failed. */
                $this->lockcount++;
                return 0;
            case    -1:
                $this->lockcount = 0;
                return;
        }
    }
}

class    revrail extends rail {
    function    drive($speed = 0) {
        parent::drive(-$speed);
    }
}

#
# +---r7---|---r0---|---r1---+
# |                          |
# |                          |r2
# |r6                        |
# |                          |
# +---r5---|---r4---|---r3---+
#

$raillist = array();
$raillist[] =& new rail("00");
$raillist[] =& new rail("01");
$raillist[] =& new rail("02");
$raillist[] =& new rail("03");
$raillist[] =& new rail("04");
$raillist[] =& new rail("05");
$raillist[] =& new rail("06");
$raillist[] =& new rail("07");


class    train {
    var    $pos;
    var    $starttime = 0;    /* >0: wait in station */
    var    $mode = 0;    /* 0:in station 1:run */
    function    train($currentpos = 0) {
        global    $raillist;
        
        $this->pos = $currentpos;
        if (($raillist[$this->pos]->lock(1)) < 0)
            die("lock({$this->pos}) failed.");
    }
    function    step() {
        global    $raillist;
        
        if ($this->starttime > 0) {
            if (time() < $this->starttime - 60)
                ;    /* system-clock changed */
            else if (time() > $this->starttime)
                ;
            else
                return;
            $this->starttime = 0;
        }
        
        $currentrail =& $raillist[$this->pos];
        $nextrail =& $raillist[($this->pos + 1) % count($raillist)];
        switch ($this->mode) {
            default:
                die("mode: ".$this->phase);
            case    0:
                if ($nextrail->lock(1) < 0)
                    return;        /* lock failed. */
                $currentrail->drive(3);
#                $currentrail->drive(rand(1, 5));
                $this->mode++;
                return;
            case    1:
                if ($nextrail->sense() == 0)
                    return;        /* not arrived yet */
                $this->starttime = time() + 5;
                $this->mode++;
                return;
            case    2:
                $currentrail->drive(0);
                $currentrail->lock(0);    /* unlock */
                $this->pos = ($this->pos + 1) % count($raillist);
                $this->mode = 0;
                $this->starttime = time() + 5;
                return;
        }
    }
}


$trainlist = array();
foreach ($raillist as $key => $dummy) {
    $raillist[$key]->drive(0);
    if (($raillist[$key]->sense()))
        $trainlist[] =& new train($key);
}


for (;;) {
    foreach ($trainlist as $key => $dummy)
        $trainlist[$key]->step();
}

?>

車両をオブジェクト化して制御

ニコニコ動画:http://www.nicovideo.jp/watch/sm7926405

次回は,今回作成したシミュレータ用のレイアウトエディタを作ってみます。

著者プロフィール

木元峰之(きもとみねゆき)

独立系ソフトハウスに8年間勤務,パッケージソフトの開発や記事執筆などを行う。現在はフリーのコンサルタント。SWESTなどのワークショップで分科会のコーディネータを務める。デジタル回路設計歴30年,プログラミング歴27年。

きもと特急電子設計
URL:http://business.pa-i.org/