challenge エレベータの制御(基本編)

エレベータを制御して、5階建てのビルの各階にいる人たちを、
「効率よく」1階のエントランスまで運んでください。

作成時の条件は次の通りです。
  1. 各階において、人が残っていることはわかるが、
     あと何人残っているかまではわからないものとする。
     # 人が残っているところは常に呼び出しのボタンが押された状態を
     # 仮定して問題ありません。
  2. 稼働しているエレベータは1機のみとする
  3. 降車するたびに、変化がわかるような出力をしてください。
  4. すべての人を運搬終わったら、最後に次の情報を出力してください。
     - 運搬を始めてからの経過時間(ラウンド数)
     - 一番長く放置されていた階の待ち時間(ラウンド数)
     - エレベータの移動距離合計数

エレベータの機能は次の通りです。
  - 搭載人数は最大3人までとする。
  - 移動には、1つの階につき「2」ラウンドかかる。
  - 人の乗降には、1回につき「5」ラウンドかかる。

※ 「ラウンド」は包括された時間だと思ってください。
   単純に「秒」と読み替えてもよいです


各階の人数は次の通りです。
5階  7人
4階 11人
3階  3人
2階  7人
1階  0人

冒頭では、「効率よく」なんて曖昧な表現をしようしましたが、
何について効率よくしたのか、設計についての見解を
コメントしていただけるとうれしいです。

たとえば、
下記のサンプル出力では、各階の待ち時間を最小とすることで
効率よいとしました。(利用者の視点)
ぱっと思いつくところでは、ほかにも2-3種類あるとおもいます。

さて、あなたならどう書く?(笑
// 自分で作ったやつは250L位になってしまいましたorz

INIT --------------------
 [5]th Floor: [ 7] / last_round:[   0]
 [4]th Floor: [11] / last_round:[   0]
 [3]th Floor: [ 3] / last_round:[   0]
 [2]th Floor: [ 7] / last_round:[   0]
 [1]th Floor: [ 0] / last_round:[   0] 

IN(5) [7] → [4] OUT
IN(4) [11] → [8] OUT
IN(3) [3] → [0] OUT
IN(2) [7] → [4] OUT
IN(5) [4] → [1] OUT
IN(4) [8] → [5] OUT
IN(2) [4] → [1] OUT
IN(5) [1] → [0] IN(4) [5] → [3] OUT
IN(2) [1] → [0] OUT
IN(4) [3] → [0] OUT

END --------------------
 [5]th Floor: [ 0] / last_round:[ 174]
 [4]th Floor: [ 0] / last_round:[ 229]
 [3]th Floor: [ 0] / last_round:[  58]
 [2]th Floor: [ 0] / last_round:[ 213]
 [1]th Floor: [ 0] / last_round:[   0] 
       経過時間:[257]
   最大待ち時間:[100]
 移動距離合計数:[52]
長いからとサンプルコードはしょってしまったのでいろいろと不都合がでてしまいました。

last_round は僕のデバックの都合上のものなので出力に関しては気にしないでください。
ごめんなさい。
お題を間違えてCのまま投稿してしまったので
言語設定せずに投稿します。

gcc -Wall -std=c99 doukaku225.c

# ところで、これ投稿したの一昨日くらいなのですが、
  公開のカウントって下書きした段階ではじまってる?
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
#include <stdio.h>
#include <stdbool.h>
#include <assert.h>

#define CARRYING_LIMIT      (3)
#define CARRYING_MOVE_COST  (5)
#define ELEVATOR_MOVE_COST  (2)

typedef struct tagFloor
{
    bool called;            /*  */
    int  floor_Nth;         /*  */
    int  carry_remain;      /*  */
    long last_round;        /*  */
    struct tagFloor *down;  /*  */
    struct tagFloor *up;    /*  */
} FLOOR;

typedef struct tagElevatorBox
{
    int     carrying;       /*  */
    int     cool_time;      /*  */
    FLOOR * now_floor;      /*  */
    FLOOR * target_floor;   /*  */
} ELEVATOR;

static long round          = 0;
static long round_wait_max = 0;
static long move_total     = 0;

/* エレベータ内が搭載可能人数を返す */
int elevator_getCarryAvailed( const ELEVATOR *elevator )
{
    return (CARRYING_LIMIT - elevator->carrying);
}

/* 目的の階に到着していれば真 */
bool elevator_isTargetFloor( const ELEVATOR *elevator)
{
    if( elevator->now_floor == elevator->target_floor )
    {
        return true;
    }
    return false;
}

/* エレベータに乗車させる */
int elevator_carrying_in( ELEVATOR *elevator )
{
    int avail = 0;
    const int oldremain = elevator->now_floor->carry_remain;
    avail = elevator_getCarryAvailed(elevator);
    if(  avail > 0 )
    {
        if( elevator->now_floor->carry_remain > avail )
        {
            elevator->now_floor->carry_remain -= avail;
            elevator->carrying += avail;
        }
        else
        {
            elevator->carrying += elevator->now_floor->carry_remain;
            elevator->now_floor->called = false;
            elevator->now_floor->carry_remain = 0;
        }
        elevator->cool_time = CARRYING_MOVE_COST;
        printf("IN(%d) [%d] → [%d] "
                ,elevator->now_floor->floor_Nth,oldremain, elevator->now_floor->carry_remain);
    }
    return 0;
}

/* エレベータから降車させる */
int elevator_carrying_out( ELEVATOR *elevator )
{
    if( elevator->carrying > 0 )
    {
        elevator->carrying = 0;
        elevator->cool_time = CARRYING_MOVE_COST;
        printf("OUT ");
    }
    return 0;
}

/* エレベータを移動する */
int elevator_update(ELEVATOR *elevator)
{
    if( elevator->cool_time > 0 )
    {
        elevator->cool_time --;
        return 1;
    }
    if( elevator_isTargetFloor(elevator) == true )
    {
        return 0;
    }
    else
    {
        /* エレベータの移動 */
        move_total ++;
        assert( elevator->now_floor->floor_Nth != elevator->target_floor->floor_Nth );
        if( elevator->now_floor->floor_Nth < elevator->target_floor->floor_Nth )
        {
            elevator->now_floor = elevator->now_floor->up;
         }
        else
        {
            elevator->now_floor = elevator->now_floor->down;
        }
        elevator->cool_time = ELEVATOR_MOVE_COST;
    }
    return 0;
}

/* 次に停止するべき階を選択する */
int floor_select( FLOOR **next, const FLOOR *floor, const long round )
{
    long wait_max;
    FLOOR *cursor;

    *next = NULL; /* 最上階 */
    wait_max = -1;
    cursor = (FLOOR *)floor;
    while( true )
    {
        if( cursor->called == true && (round - cursor->last_round) > wait_max )
        {
            *next = cursor;
            wait_max = (round - cursor->last_round);
            if( (round - cursor->last_round) > round_wait_max )
            {
                round_wait_max = (round - cursor->last_round);
            }
        }
        if( cursor == cursor->down )
        {
            break;
        }
        cursor = cursor->down;
    }

    if( *next == NULL )
    {
        /* 1階ならばすべて運び終わっている */
        *next = cursor;
        return 1;
    }
    (*next)->last_round = round;
    return 0;
}

/*  */
int floor_print(const ELEVATOR* elevator, const FLOOR *floor)
{
    printf("--------------------\n");
    while( true )
    {
        printf(" [%d]th Floor: [%2d] / last_round:[%4ld] %c %c\n"
            , floor->floor_Nth, floor->carry_remain,floor->last_round
            , (floor==elevator->target_floor)?'=':' '
            , (floor==elevator->now_floor)?'*':' ');
        if( floor == floor->down )
        {
            break;
        }
        floor = floor->down;
    }
    return 0;
}

/*  */
int main(int argc, char *argv[])
{
    static FLOOR floor[] = 
            {
                {false, 1,  0, 0, &floor[0], &floor[1]}
                ,{true, 2,  7, 0, &floor[0], &floor[2]}
                ,{true, 3,  3, 0, &floor[1], &floor[3]}
                ,{true, 4, 11, 0, &floor[2], &floor[4]}
                ,{true, 5,  7, 0, &floor[3], &floor[4]}
            };
    static FLOOR *top_floor = &floor[4];
    static ELEVATOR schindler = { 0, 0, &floor[0], &floor[0] };

    FLOOR *next = NULL;

    /* 初期状態の出力*/
    printf("INIT ");
    floor_print(&schindler, top_floor);

    /* 運搬開始 */
    round = 0;
    round_wait_max = 0;
    move_total = 0;
    while( true )
    {
        round ++;
        elevator_update(&schindler);
        if( schindler.cool_time > 0 )
        {
            continue;
        }
        if( elevator_isTargetFloor(&schindler) == true )
        {
            /* 目的の階に到着 */
            if( schindler.now_floor->floor_Nth == 1 )
            {
                elevator_carrying_out(&schindler);
                /* 次の停止回を最上階から検索する */
                floor_select( &next, top_floor, round );
                if( next->floor_Nth == 1 )
                {
                    /* もうない */
                    break;
                }
                //floor_print(&schindler, top_floor);
                printf("\n");
             }
            else
            {
                elevator_carrying_in(&schindler);
                if( elevator_getCarryAvailed( &schindler ) > 0 )
                {
                    /* まだ搭載できるので移動のついでに追加搭載する */
                    floor_select( &next, schindler.now_floor, round );
                }
                else
                {
                    /* もう限界なので1階を目的地にする */
                    next = &floor[0];
                }
                //floor_print(&schindler, top_floor);
            } /* end of if(1階か) */
            /* 次の停止階を設定する */
            schindler.target_floor = next;
        } /* end of if(到着しているか) */
    } /* end of while( 残っているか )  */

    printf("\n\nEND ");
    floor_print(&schindler, top_floor);
    printf("%15s:[%ld]\n", "経過時間", round);
    printf("%15s:[%ld]\n", "最大待ち時間", round_wait_max);
    printf("%15s:[%ld]\n", "移動距離合計数", move_total);

    return 0;
}
/* EOF */

Posted feedbacks - Haskell

Haskellでやったんですよー言語タグをつけるの忘れました…

1
2
3
module Main where

main = putStrLn "see my previous post"

Index

Feed

Other

Link

Pathtraq

loading...