phpでRoomba Simulator作ったメモ

ルンバをぼーっと眺めていてどんなアルゴリズム書けば効率よく掃除できるのか気になったので、簡単なシミュレータを作った。

ぶつかったときの動きと、ぶつからずに一定の距離を進んだときの動きを書いて読み込ませると何回の行動で綺麗にできたか結果を出力する。

## 使い方

composerでインストールして使う。

```
{
    "require" : {
        "sat8bit/roombasim" : "dev-master",
        "symfony/console" : "3.0.*@dev"
    },
    "repositories": [
        {
            "type":"vcs",
            "url": "git://github.com/sat8bit/roombasim.git" 
        }

    ]
}
```

で、コマンド実行。残念な感じでRoombaの動きを表示する。

```
$ vendor/bin/roombasim roombasim 'sat8bit\RoombaSim\Roomba\RoombaAISample' --disp
R(7), C(5.3900627682607, 3.8575910007494), D(240)
|                                        |
| . . . . . . . . . . .           .   . .|
| . . . .() . . . . . .   . . . .     . .|
| . . . .   . . . . .   . . . . . . . . .|
| . . . . .   . . . .   . . . . . . . . .|
| . . . . .   . . .   . . . . . . . . . .|
| . . . . . .   . .   . . . . . . . . . .|
| . . . . . .   .   . . . . . . . . . . .|
| . . . . . . .     . . . . . . . . . . .|
| . . . . . . . . . . . . . . . . . . . .|
| . . . . . . . . . . . . . . . . . . . .|
| . . . . . . . . . . . . . . . . . . . .|
| . . . . . . . . . . . . . . . . . . . .|
| . . . . . . . . . . . . . . . . . . . .|
| . . . . . . . . . . . . . . . . . . . .|
| . . . . . . . . . . . . . . . . . . . .|
| . . . . . . . . . . . . . . . . . . . .|
| . . . . . . . . . . . . . . . . . . . .|
| . . . . . . . . . . . . . . . . . . . .|
| . . . . . . . . . . . . . . . . . . . .|
```

### Arguments

コマンド名。入れなくてよくしたい。

```
roombasim
```

AIクラス。作り方は後述。

```
'sat8bit\RoombaSim\Roomba\RoombaAISample'
```

### Options

部屋を変更する。デフォルトは15x15の部屋(RectangleRoom15x15)。

```
--room "RectangleDirtyRoom15x15"
```

最大行動回数を変更する。

```
--step 20
```

途中経過を可視化する。

```
--disp
```

## Roombaの作り方

### 前提条件

- Roombaは、左上のマスを右向きでスタートする。
- Roombaは、最初は壁に当たるまで走り続ける。

### 実装

#### RoombaAIInterface

下記のinterfaceを実装したクラスを作成する。

```
<?php

namespace sat8bit\RoombaSim\Roomba;

interface RoombaAIInterface
{
    /**
     * when hit.
     * hitメソッドは壁や障害物に当たったときの動きを返す。
     *
     * @param int $distance
     * @return Motion
     */
    public function hit($distance);

    /**
     * when ran.
     * ranメソッドは壁や障害物に当たるより先に指定の距離を走ったときの動きを返す。
     *
     * @param int $distance
     * @return Motion
     */
    public function ran($distance);
}
```

`Motion`クラスは回転角度（時計回り）と走行距離を引数に作成する。

#### Sample

```
<?php

class RoombaAISample implements RoombaAIInterface
{
    /**
     * when hit.
     *
     * @param int $distance
     * @return Motion
     */
    public function hit($distance)
    {
        // 壁にあたったらランダム(0~360度)で回転し、1000進む
        return new Motion(mt_rand(0, 360), 1000);
    }
    /**
     * when ran.
     *
     * @param int $distance
     * @return Motion
     */
    public function ran($distance)
    {
        // 回転せずに1000進む。つまり壁に当たるまでまっすぐ走り続ける
        return new Motion(0, 1000);
    }
}
```

### 実行

autoloadできる場所において引数で渡す。

```
vendor/bin/roombasim roombasim 'RoombaAISample' --disp
```

## デフォルトで用意されているRoom一覧

変更する場合はroomオプションでクラス名を指定します。自分で部屋を作ることもできます。

クラス名|説明
---|---
RectangleRoom15x15|長方形の部屋
RectangleDirtyRoom15x15|RectangleRoom15x15より汚れが激しい長方形の部屋
LivingRoom20x15|（想像を働かせて）L字型のソファとローテーブル、テレビ台が障害物となっている部屋

## その他

- https://github.com/sat8bit/roombasim
- https://github.com/sat8bit/roombasim-example