Elevator Saga 1 はじめてみる -> 意外と難しいまでの話

はじめに
===

https://play.elevatorsaga.com/
をはじめました。

対象読者: すでに何らかのプログラミング経験がある人

## コーディングの仕方
https://play.elevatorsaga.com/documentation.html#docs
に従ってコーディングすればよい。

はじめる前に
===

プログラミング経験のある人は
https://edutainment-fun.com/hidemaru/it/%E3%82%A8%E3%83%AC%E3%83%99%E3%83%BC%E3%82%BF%E3%83%BC%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9F%E3%83%B3%E3%82%B0%E3%82%B2%E3%83%BC%E3%83%A0%E3%81%A7%E6%A5%BD%E3%81%97%E3%81%8F%E5%AD%A6%E3%81%B6_3792.html
の「注意点」は読んでおきましょう。

# Lv1: とにかく触ってみる
初期状態のコードを実行すると0階と1階を往復するだけです。2階にも人がいるので2Fに停めたいですね。そこで以下のように書き換えます。

- code1-1

```JavaScript
{
    init: function(elevators, floors) {
        var elevator = elevators[0]; // Let's use the first elevator
        elevator.on("idle", function() {
            elevator.goToFloor(0);
            elevator.goToFloor(1);
            elevator.goToFloor(2);
        });
    },
    update: function(dt, elevators, floors) {}
}
```
これだと、0->1->2->0->1->2と移動します。「各停」にするにはどうすればいいでしょうか。

- code1-2

```JavaScript
{
    init: function(elevators, floors) {
        var elevator = elevators[0]; // Let's use the first elevator
        elevator.on("idle", function() {
            elevator.goToFloor(0);
            elevator.goToFloor(1);
            elevator.goToFloor(2);
            elevator.goToFloor(1);
        });
    },
    update: function(dt, elevators, floors) {}
}
```

とすると、0->1->2->1->0->1->2というように各停になります。
どちらの例でもLv1はクリアできるはずです。

## 動作説明
各elevatorはdestinationQueueという行先の階のキューを保持しています。elevator.goToFloorはこのキューにinsert_rightで行先の階を追加します。

elevatorのidleイベントはこのキューが空の時に発火します。つまり、上記のcode1-2では、最初及び1階に着くたびに"0->1->2->1に行け"というキューをpushしています。

# Lv2: フロアのイベントを利用する
流石にフロアが5階あるので、各階に停まるのは非効率的に思うでしょう。
まず、思い浮かぶのは「フロアのボタンが押された階に行ってみる」ことです。

```JavaScript
{
    init: function(elevators, floors) {
        var elevator = elevators[0]; // Let's use the first elevator
        elevator.on("idle", function() { });
        floors.forEach(function(f) {
            f.on("up_button_pressed down_button_pressed", function() {
                elevator.goToFloor(f.floorNum());
            });
        });

    },
    update: function(dt, elevators, floors) {}
}
```

しかし、これでは「乗った人が行きたい階に行っていない」ので人がおりてくれません。
なので、「エレベータ内のボタンが押されたらまずそのフロアに行く」ことにします。
フロアのボタンが押されたことはフロアオブジェクトからのイベント発火でハンドリングできます。

```JavaScript
{
    init: function(elevators, floors) {
        var elevator = elevators[0]; // Let's use the first elevator
        elevator.on("idle", function() { });
        elevator.on("floor_button_pressed", function(floorNum) {
            elevator.goToFloor(floorNum, true);
        });
        floors.forEach(function(f) {
            f.on("up_button_pressed down_button_pressed", function() {
                elevator.goToFloor(f.floorNum());
            });
        });
    },
    update: function(dt, elevators, floors) {}
}
```

# Lv4: 複数のエレベータ
フロアが増えたのに加えてエレベータが増えるのでそれに対応します。
各エレベータについて、押された階に順番に停まるようにするには、以下で実現できます。

```Javascript
        elevators.forEach(function(elevator) {
            elevator.on("floor_button_pressed", function(floorNum) {
                elevator.goToFloor(floorNum);
            });
        });
```

ただ、フロアのボタンが押された際に両方のエレベータを動かす必要はないので、どちらのエレベータを移動させるか考える必要があります。
例えば、それぞれのエレベータ交互に割り当てる、負荷率の低いエレベータに割り当てる、その階に近いエレベータに割り当てる。などが考えられます。
今回は「近いエレベータに割り当てる」を実装します。

```JavaScript
{
    init: function(elevators, floors) {
        elevators.forEach(function(elevator) {
            elevator.on("floor_button_pressed", function(floorNum) {
                elevator.goToFloor(floorNum);
            });
        });
        floors.forEach(function(f) {
            f.on("up_button_pressed down_button_pressed", function() {
                function sort_func(a, b){
                    if( Math.abs(a.currentFloor() - f.floorNum()) < Math.abs(b.currentFloor() - f.floorNum())){
                        return -1;
                    } else {
                        return 1;
                    }
                }
                elevators.sort(sort_func);
                elevators[0].goToFloor(f.floorNum());
            });
        });
    },
    update: function(dt, elevators, floors) {}
}
```

これで、Lv4くらいまではクリアできるようになるはずです。
このあたりから、しっかりと全体像を掴んでプログラミングしないとならない、と思い始めるはずです。