while 1ここではエレベータがそれぞれの階に到着するごとに「降りる人はいないか」「乗る人はいないか」を判定
getOff() /* 人を降ろす
getOn() /* 人を乗せる
moveElevator() /* エレベータを動かす
endwhile
floor(3,7)=1のようにして表現するのです。7階に向かう人が2人いるなら、
floor(3,7)=2となります。この方法は簡単ですのでこれまでの知識で十分皆さんにもプログラムできるはずです。
floor(3)=[7]と表すことにします。ここに6階に向かう人がやってきました。この人はエレベータ待ちに加わります。
floor(3)=[6 7]となりました。次に2階に向かう人と1階に向かう人がやってきます。
floor(3)=[1 2 6 7]です。ちょうど上に向かうエレベータがやってきたので3階から上に行く人はエレベータに乗り込み、エレベータを待つ人は、
floor(3)=[1 2]になりました。続いて下に向かうエレベータが到着し、3階で待つ人は、
floor(3)=[]となる、このようにデータを好きなように追加・削除できるデータの表現方法を使ってみることにしましょう。
int xとすればOKです。
x=EMPTY
addData(要素,リスト)リストに要素をつけ加えてできた新しいリストを返します。要素は整数です。xという変数に[1]をセットするなら、
int x x = EMPTY /* x=[ ]あるいは、
x = addData(1,x) /* x=[1]
int xとします。addDataはリストの「前に」要素をつけ加えますので、
x=addData(1,EMPTY)
int x,iとした結果は、
x=EMPTY
for i=1 to 3
x=addData(i,x)
next
[3 2 1]と、逆順になります。
concat(リスト1,リスト2)リスト1の後ろにリスト2をつないだリストを返します。これはリスト1とリスト2をつないだ新しいリストを作るものではなく、
int zとすると、zに[1 2 3 4 5]がセットされるだけでなく、xも[1 2 3 4 5]に変わってしまいます。
z=concat(x,y)
int x x=[1 2 3]などということはできません。注意してください。
head(リスト)リストの先頭要素を返します。xが[2 3 5]のとき、
print head(x)を実行すると「2」が表示されます。
tail(リスト)リストの先頭要素を除いた残りのリストを返します。xが[1 2 3]のとき、
tail(x)を実行すると、[2 3]が返されることになります。
delData(削除位置,リスト)リストの削除位置にある要素を取り除いたリストを返します。削除位置の指定方法はちょっと変わっていて、
x=delData(tail(tail(x)),x)となります。tail(tail(x))は[3 4]ですから、先頭要素である3が削除されるというわけです。
printList(リスト)リストはprint命令では表示できません。そこで、リストを目に見える形で表示するための関数です。
printList(head(x))などとすると、変なものが表示されたりエラーになったりします。必ずリストが入っている変数かtail関数の値を、
x=tail(x)でも目的を達することはできます。しかし、摩訶不思議なメカニズムによってゴミが発生してしまうのです。
x=delData(x,x)となります。
renumを実行すれば、いつもの見慣れた10行から始まるプログラムになります。
int xとしてリストを入れる変数を宣言しておきます。
x=EMPTYでxに空のリストをセットしたら、
printList(x)としてみましょう。[]が表示されましたね。
x=addData(1,x)で空のリストに1という要素を加えてみます。
printList(x)で[1]と表示されましたか?続いて、
for i=2 to 5:x:addData(i,x):nextではどうでしょう。これはまずxに2をつけ加え、次に3,次に4,5とつけ加えていきます。
z=append(x,y)を実行してみてください。本当につながったかどうか確かめてみましょう。
printList(z)で[1 2 3 4 5 6]というリストが表示されましたか?続いてxとyも調べてみましょう。xは[1 2 3]のまま、
for i=1 to 10:print rnd():nextどうですか、デタラメな数が10個表示されたでしょう。このrnd関数を使って、ランダムに各階に到着
for i=1 to 10ランダムな1~7の数が表示されましたね。これで乗客が現れる階をデタラメに決めることができるようになりました。
print int(rnd()*7)+1
next
まず到着階を決め、到着階と異なる目的階が出るまでrepeat~untilでループするわけです。
int ff /* floor from
int ft /* floor to
ff=int(md()*7)+1
repeat
ft=int(md()*7)+1
until ff<>ft
int floor(7)として各階の乗客を入れるためのリストを作り、空リストで初期化しておきます。次に上の方法で乗客を発生させ、
int i
for i=1 to 7
floor(i)=EMPTY
next
floor(ff)=addData(ff,floor(ff))とすればOKです。では方針が固まったところで、プログラムリスト3を見てください。
floor(n,0)にはn階から下に向かう人を、 floor(n,1) には上に向かう人を入れることにします。こうしておけば、上に向かうエレベータがn階に到着したとき、
print chr$(5)というのはコントロールキーを押しながらEを押すのと同じ働きをします。これで表示行をクリアして
arrival()とダイレクトモードで入力してみましょう。画面表示が変わりましたか?だめなら何度かトライしてみてください。
int iとダイレクトモードで実行してみましょう。各階の様子が次々と変わり、乗客がどんどんやってきます。
for i=1 to 100:arrival():next
int pass=EMPTYと書きたいところなのですが、ここは涙を飲んで-1で初期化してあります。そしてvector変数はエレベータの移動の向きを表します。
floor(elevator,0) /* 下に降りる人を調べればわかります。これがEMPTYでなければ乗客がいるということです。エレベータが上に動いているなら、
floor(elevator,1) /* 上に昇る人
pas=concat(floor(elevatoer,1),pass)として、上に向かう人をっ乗客に加えればOkですね。
floor(elevator,1)=EMPTYでエレベーター待ちの人を空リストにしておきます。
[2 3 2 7 4 7]となっているとしましょう。各階のエレベータ待ちのリストと同じように、エレベータの乗客は目的階
[3 7 4 7]とならなければなりません。このような処理はどうすれば実現できるでしょうか。ちょっと考えてみると、
int chk chk=passとして、降ろす乗客かどうかを判断するためのチェック用リストをまず用意します。チェック用リスト
pass=delData(chk,pass)としてpassからその要素を取り除きます。headが降ろす乗客でなければ、
chk=tail(chk)でchkのtail部分を取り出し、再びそのheadが降ろす乗客かどうかを調べるわけです。ここでtailをとった結果を
pass=delData(chk,pass)で降ろしていますので安心してください。
for i=0 to 50:arrival():nextとして、乗客を発生させます。次にエレベータの方向を決めます。
locate 0,21
vector=1です。これでエレベータは上向きに動きます。
test()と入力してみましょう。1階で待っている人がエレベータに乗り込みましたか?カーソルが数行上に
elevator=2:test()を実行してみてください。2階で降りる人が(もしいれば)降り、2階で待っていた人が乗り込んで来ましたか。
vector=-1でエレベータを下に動かすことにします。
test()で乗客を乗せ、先程と同じ要領で、
elevator=6:test()などとしながら、1階まで降りてきてみましょう。シミュレーションはうまくいっているようですね。
while 1という形で実現されることになります。
arrival() /* 乗客の到着
direction() /* 方向の決定
getOff() /* 乗客が降りる
getOn() /* 乗客が乗る
moveElevator() /* エレベーターを動かす
endwhile
print time$を実行すると、現在の時刻を表示させることもできます。これをtmという文字型の変数に代入しておき、
int elevator /* エレベータのいる階という4つの変数で表現されていました。これを複数台分用意すればいいだけです。配列で表現することにしましょう。
int vector /* 動いている方向
int pass /* 乗客
int wait /* 乗り降り時の待ち
int Elevator(1) /* エレベータのいる階これで終わりです。あとは、プログラム中で4つの変数を使っているところを適宜書き換えていけば
int Vector(1) /* 動いている方向
int Pass(1) /* 乗客
int Wait(1) /* 乗り降り時の待ち
3150 direction(i)を、
3150 direction1(i)に変更してください。
timer=300とすると、リストxの先頭要素に現在の時刻300がセットされます。これは1階に向かう人が時刻300にやってきたことを意味します。
x=addData(1,-1) /* xに[1]をセット
setTime(x)
timer= 35なら2階に向かう人に時刻350がセットされます。確かめてみましょう。
x=addData(2,x) /* x = [2 1]
setTime(x)
print getTime(x) /* 2階に行く人なら350が表示されますし、
print getTime(tail(x)) /* 1階に行く人なら300が表示されます。
リストにおけるデータ削除 [1 2 3]というリストから2を削除する場合、 data(i,1) = i+2とすればよい。本文の図1を見ながら考えてみていただきたい。注意しなければならないのは、 このときdata(i+1,n) は誰からもつながらない宙ぶらりんデータとなってしまうことだ。 先月摩訶不思議な作用でゴミが発生するといったが、これがゴミの正体である。 このような方法でデータ削除を続けると宙ぶらりんデータが次第に増えていき、 最後にはdata配列すべてがゴミになってしまうことになる。 これを避けるため本プログラムでは次のような方法を採用している。initList関数は プログラム起動時にdata配列をひとつの長いリストにする関数である。この長いリス トを自由リストといい、その先頭は変数dataBaseに保持されている。addData関数に よって新しいリストを作る必要が生じた場合、 addData関数はnewData関数を呼び出し て自由リストの先頭からデータを入れる箱をひとつ切り出してもらう。結果自由リストは ひとつ減ることになり、 dataBaseの値も更新される。 逆にリストから要素を削除する場合には、delData関数はgc関数を呼び出して削除した 箱を自由リストに戻すという作業を行う。この結果自由リストはひとつ増えることになる。 要素の削除には必ずdelData関数を使うように先月指示したのは、このゴミ回収 作業を行うためである。 newData、gcの2つの関数の働きにより、シミュレーション実行中に1000人を超える 人がエレベータに殺到しない限り、自由リストが枯渇することはない。 |