RPGクラス

<?php
    // RPGクラス
    class tuwGameUtl
    {
        // 魔物番号
        private $Monster = 2;
        // 粉砕可能画像の先頭番号
        private $crushIndex = 3;
        // マップのセルサイズ
        private $ChipSize = 66;
        // 魔物URLリスト
        private $Devils = array(
            "./media/npc/mst01.png"
            , "./media/npc/mst02.png"
            , "./media/npc/mst03.png"
            , "./media/npc/mst04.png"
            , "./media/npc/mst05.png"
        );
        // 経路探索未訪問リスト
        private $oHash = array();
        // 経路探索訪問済リスト
        private $cHash = array();
        // 生成
        public function __construct()
        {
        }
        // プロパティ設定
        public function __set($key, $value)
        {
            if ($key == "Monster")
                $this->Monster = $value;
            else if ($key == "crushIndex")
                $this->crushIndex = $value;
            else if ($key == "ChipSize")
                $this->ChipSize = $value;           
            else
                throw new Exception('Undefined Property['.$key."]");
        }
        // プロパティ取得
        public function __get($key)
        {
            if ($key == "Monster")
                return $this->Monster;
            else if ($key == "crushIndex")
                return $this->crushIndex;
            else if ($key == "ChipSize")
                return $this->ChipSize;           
            else
                throw new Exception('Undefined Property['.$key."]");
        }
        // 魔物をランダムに得る
        public function GetDevil()
        {
            $idx = array_rand($this->Devils);
            return $this->Devils[$idx];
        }
        // RPG 地図ランダム生成
        //  0:地べた
        //  1:粉砕後(ここでは設定しない)
        //  2:魔物
        //  3:粉砕対象(3以上)
        // $rows = マップの行数
        // $cols = マップの列数
        // $num = 宝箱の種類数
        public function CreateMap($rows, $cols, $num)
        {
            // マップの中央
            $cpx = floor($cols / 2);
            $cpy = floor($rows / 2);
            // マップ配列
            $map = array();
            // 障害物、宝箱、魔物等の地べた以外の配列
            $mst = array();
            // 行ループ
            for ($row = 0; $row < $rows; $row++) {
                $map[] = array();
                // 列ループ
                for ($col = 0; $col < $cols; $col++) {
                    // マップの中央は必ず地べたにする
                    if ($row == $cpy && $col == $cpx)
                        $map[$row][$col] = 0;
                    else {
                        $flg = mt_rand(0, 1);
                        // 地べたと置物分岐
                        if ($flg == 0) {
                            $map[$row][$col] = $flg;
                            $mst[] = array('r' => $row, 'c' => $col);
                        }
                        else {
                            // 粉砕対象がでたら10個に1個の割合で宝箱にする
                            if (mt_rand(1, 10) == 10) {
                                $box = mt_rand(1, $num);
                                $map[$row][$col] = $this->crushIndex + $box;
                            }
                            else
                                $map[$row][$col] = $this->crushIndex;
                        }
                    }
                }
            }
            // 魔物を配置する(マップに1匹)
            $idx = array_rand($mst);
            $map[$mst[$idx]['r']][$mst[$idx]['c']] = $this->Monster;
            // 結果を返す
            return $map;
        }
        // 経路上のノード生成
        private function NewNode($parent, $row, $col)
        {
            $key = substr('0000'.$row, -4).substr('0000'.$col, -4);
            $new = array('key' => $key, 'row' => $row, 'col' => $col, 'cost' => 0, 'parent' => $parent);
            return $new;
        }
        // ノードを登録する
        private function putNode($node, $flgOpen)
        {
            if ($flgOpen)
                $this->oHash[$node['key']] = $node;
            else
                $this->cHash[$node['key']] = $node;
        }
        // 推定コスト計算 ヒューリスティック関数
        // 二つの指定ノードの推定コストを計算する
        // この関数が最短経路を選択する肝になる
        private function getHeuristicCost($node, $next)
        {
            // 二つのノードの行列の差を得る
            $a = $node['row'] - $next['row'];
            $b = $node['col'] - $next['col'];
            // 二つのノードのコストを計算する
            $c = sqrt(($a * $a) + ($b * $b));
            // 結果を返す
            return $c;
        }
        // 最小コストのノードを得る
        private function getMinCostNode()
        {
            $mNode = null;
            // Openリストがあるなら...
            if (count($this->oHash) > 0) {
                // ダミーノードを生成する
                $mNode = $this->NewNode(null, 0, 0);
                $mNode['cost'] = PHP_INT_MAX;
                // コストの最小値を探索する
                foreach($this->oHash as $node) {
                    if ($node['cost'] < $mNode['cost'])
                        $mNode = $node;
                }
                // ハッシュを削除
                unset($this->oHash[$mNode['key']]);
            }
            // 結果を返す
            return $mNode;
        }
        // 最短経路の取得
        public function GetShortcutRoute($StRow, $StCol, $EdRow, $EdCol, $map)
        {
            // 隣接ノード間の最長距離コスト(障害物)
            $ObstacleCost = $this->ChipSize * $this->ChipSize;
            // 1.初期化 出発点ノードとゴールノードを作成する
            $sNode = $this->NewNode(null, $StRow, $StCol);
            $gNode = $this->NewNode($sNode, $EdRow, $EdCol);
            // 2.出発点ノードをOpenリストに追加する、このとき g*(S) = 0 であり f*(S) = h*(S) となる
            $sNode['cost'] = $this->getHeuristicCost($sNode, $gNode);
            $this->putNode($sNode, true);
            // 3.Openリストが空になるまでループ
            while (count($this->oHash) > 0) {
                // Openリストに格納されているノードの内、最小の距離コストを持つノード n を取り出す。
                $node = $this->getMinCostNode();
                // ゴールであるなら探索を終了する
                if ($node['row'] == $EdRow && $node['col'] == $EdCol) {
                    $gNode = $node;
                    break;
                }
                // ゴール以外の場合は n を Close リストに移す。
                $this->putNode($node, false);
                // n に隣接している全てのノード(時計回り8方向の隣接ノードを m とおく)に対して以下の操作を行う 
                for ($v = 0; $v < 8; $v++) {
                    // 着目ノードの座標を得る
                    $r = $node['row'];
                    $c = $node['col'];
                    // 北、北東、北西
                    if ($v == 0 || $v == 1 || $v == 7)
                        $r--;
                    // 南東、南、南西
                    if ($v == 3 || $v == 4 || $v == 5)
                        $r++;
                    // 北東、東、南東
                    if ($v == 1 || $v == 2 || $v == 3)
                        $c++;
                    // 南西、西、北西
                    if ($v == 5 || $v == 6 || $v == 7)
                        $c--;
                    // マップ範囲内にあるならば...
                    if (isset($map[$r]) && isset($map[$r][$c])) {
                        $m = $this->NewNode($node, $r, $c);
                        // $mCost = 累積距離コスト + COST(n,m) を計算する
                        // 累積距離コスト=現在着目しているノードのコスト=$node['cost']
                        // $aCost = COST(n,m) = ノード n から m へ移動するときのコスト
                        $aCost = $this->getHeuristicCost($node, $m);
                        $mCost = $node['cost'] + $aCost;
                        // m がゴールでなく障害物ならコストを大きくする
                        if (($r != $EdRow || $c != $EdCol) && $map[$r][$c] >= $this->Monster)
                            $mCost += $ObstacleCost;
                        // m の状態に応じて以下の操作を行う
                        if (!isset($this->oHash[$m['key']]) && !isset($this->cHash[$m['key']])) {
                            // m が Openリストにも Closeリストにも含まれていない場合 f*(m) = f'(m)
                            $m['cost'] = $mCost;
                            // m を 登録する
                            $this->putNode($m, true);
                        }
                        else if (isset($this->oHash[$m['key']])) {
                            // m が Openリストにある場合登録済み m を得る
                            $m = $this->oHash[$m['key']];
                            // f'(m) < f*(m) であるなら
                            if ($mCost < $m['cost']) {
                                //  f*(m) = f'(m) に置き換える
                                $m['cost'] = $mCost;
                                // m の親を n にする
                                $m['parent'] = $node;
                                // m を 置き換える
                                $this->putNode($m, true);
                            }
                        }
                        else if (isset($this->cHash[$m['key']])) {
                            // m が Closeリストにある場合登録済み m を得る
                            $m = $this->cHash[$m['key']];
                            // f'(m) < f*(m) であるなら
                            if ($mCost < $m['cost']) {
                                // m を Closeリストから削除
                                unset($this->cHash[$m['key']]);
                                // f*(m) = f'(m) とする
                                $m['cost'] = $mCost;
                                // m の親を n にする
                                $m['parent'] = $node;
                                // m を Openリストに追加する
                                $this->putNode($m, true);
                            }
                        }
                    }
                }
            }
            // 経路結果変数
            $route = array();
            // 4.探索終了後、親を順次たどっていくと G から S までの最短経路が得られる。
            while (isset($gNode['parent'])) {
                $route[] = array('row' => $gNode['row'], 'col' => $gNode['col']);
                $gNode = $gNode['parent'];
            }
            // 結果を返す
            return $route;
        }
    }
?>