10月9日 この日、私とこうしろうは『こうしろうのMindStroms日記』について、あるメールマガジンの発行者から取材を受けた。こうしろう一家は、この取材に向けて部屋を片付け電球を取り替え、朝からそわそわしていた。まだ、発行前なのでどういう内容になるのか私にもわからないのであるが、私とこうしろうはMindStormsの面白さについて(多少、緊張しながら)熱く語ったつもりである。メールマガジンの発行後に、その内容をこの日記でも紹介したいと思っている。

 そんな刺激も手伝ってか、この日の晩もNQCのお勉強となった。やる気に溢れるこうしろうにサブルーチン、インライン関数、マクロと一気にまくしたてた。

 まずは、サブルーチンである。「えーっと、こうしろう。サブルーチンちゃ、同じことを何回も書かなくてもいいように複数の命令を1つの命令としてまとめておくことながいちゃ。それでタスクからそのサブルーチンを必要に応じて呼び出すわけや。とりあえずプログラミングしてみて。サブルーチンはsubで始まるんだよ。」

sub turn_around()
{
 OnRev(OUT_C); Wait(340);
 OnFwd(OUT_A + OUT_C);
}
task main()
{
 OnFwd(OUT_A+OUT_C); Wait(100);
 turn_around(); Wait(200);
 turn_around(); Wait(100);
 turn_around();
 Off(OUT_A+OUT_C);
}

モーターCを反転させ曲がった後、前方に進みだす処理をサブルーチン化し、メインタスクから呼び出している。「RIS標準のプログラムで言うたら、MyCommandみたいもんやちゃ。」というと、こうしろうは「ふーん。」と納得したようである。サブルーチンの欠点は9つまでしか定義できないことと、同時に複数のタスクから呼び出すと障害が発生する可能性のあることだ。

 次にインライン関数についてこうしろうに説明した。インライン関数はサブルーチンと同じ機能を実現するが、コンパイル時にインライン関数に記述したコードが呼び出し元タスクに展開されるので個数制限や同時呼び出しの障害を回避できる。「コンパイル時に展開される…」をこうしろうに理解させるのが困難であった。

void turn_around()
{
 OnRev(OUT_C); Wait(340);
 OnFwd(OUT_A + OUT_C);
}
task main()
{
 OnFwd(OUT_A+OUT_C); Wait(100);
 turn_around(); Wait(200);
 turn_around(); Wait(100);
 turn_around();
 Off(OUT_A+OUT_C);
}

インライン関数はキーワードVoidで指定する。

 次にインライン関数のもうひとつ便利な点、引数を受け取れることを説明した。「intって何やったけ?」と尋ねるこうしろうに「この野郎、もう忘れたんかい」と内心思いながら「intつまりインテジャー(Integer)は引数の型、簡単に言うと大きさを指定しているんだよ。NQCの場合、変数は全部intやから気にしなくていいよ。」と答えた。

void turn_around(int turntime)
{
 OnRev(OUT_C); Wait(turntime);
 OnFwd(OUT_A + OUT_C);
}
task main()
{
 OnFwd(OUT_A+OUT_C); Wait(100);
 turn_around(200); Wait(200);
 turn_around(50); Wait(100);
 turn_around(300);
 Off(OUT_A+OUT_C);
}

turn_aroundの後の( )の中に200や300と引数を指定している。

 最後にマクロの説明をした。「#defineって前に使ったね。」とこうしろう。「おー!覚えてくれてたか」とうれしくなって説明に力が入った。「前は定数を定義するのに、#defineを使ったね。マクロの定義も#defineでするんだよ。複数の命令を1つのマクロとして定義するわけだ。」

#define turn_around OnRev(OUT_C); Wait(340);OnFwd(OUT_A + OUT_C);
task main()
{
 OnFwd(OUT_A+OUT_C);
 Wait(100);
 turn_around;
 Wait(200);
 turn_around;
 Wait(100);
 turn_around;
 Off(OUT_A+OUT_C);
}

下記のプログラムはマクロも引数を取れるという例である。

#define turn_right(s,t)
SetPower(OUT_A+OUT_C,s);OnFwd(OUT_A);OnRev(OUT_C);Wait(t);
#define turn_left(s,t)
SetPower(OUT_A+OUT_C,s);OnRev(OUT_A);OnFwd(OUT_C);Wait(t);
#define forwards(s,t)
SetPower(OUT_A+OUT_C,s);OnFwd(OUT_A+OUT_C);Wait(t);
#define backwards(s,t)  
SetPower (OUT_A+OUT_C,s);OnRev(OUT_A+OUT_C);Wait(t);
task main()
{
 forwards(3,200);
 turn_left(7,85);
 forwards(7,100);
 backwards(7,200);
 forwards(7,100);
 turn_right(7,85);
 forwards(3,200);
 Off(OUT_A+OUT_C);
}

「さー、こうちゃん、これで、NQCの基礎の勉強は終わりだ。単純な命令の組み合わせにはマクロを使って、複雑な処理はインライン関数やサブルーチンで作成していけばいいんだよ。」