実際に、いくつかプログラムを作って、NXC の制御文や変数の使い
方をまとめてみる。
また、スクリーンへの文字列の表示も行う。
なお、前回と同じように★は、推測で記している箇所なので、注意
されたい。ご存知の方は、よろしければご教授ください。
「Lego Mindstomes NXT - NXC プログラミング (1)」に記したが、
制御文のところだけ再掲する。
■ 制御文
□ if 文
if (条件式) 条件式の結果が true のとき実行するボディ
if (条件式) 条件式の結果が true のとき実行するボディ else そ
うでないときに実行するボディ
□ switch 文
switch (式) ボディ
case 定数式 :
default :
□ while 文
while (条件式) ボディ
□ do while 文
do ボディ while (条件式)
□ for 文
for (初期値化式 ; 条件式 ; 更新式) ボディ
□ repeat 文
repeat (式) ボディ
C 言語にはない制御文です。式の結果の回数分だけ繰り返します。
なお、式の結果が 0 以下の場合、ボディを実行することはありま
せん。
例
---
repeat (10) {
// 繰り返すコード
}
---
□ until マクロ
つぎのように定義されています。センサーを使うときによく使いま
す。
#define until(c) while(!(c))
したがって、while キーワードの代わりに、
until (条件式) ボディ
do ボディ until (条件式)
と書くことができます。このとき、条件式の意味は、「~まで」と
いうことになるので、「条件式が true になったらループ終了」と
いうことです。
■ くり返し制御文のサンプル
それでは、TrunRight01 プログラムをくり返しの制御文を使ってそ
れぞれ作ってみましょう。繰り返す回数は 3 回です。
----------- -----------
プログラム 使用制御文
----------- -----------
TrunRight02 repeat
TrunRight03 for
TrunRight04 while
TrunRight05 do - until
----------- -----------
---
---
---
方をまとめてみる。
また、スクリーンへの文字列の表示も行う。
なお、前回と同じように★は、推測で記している箇所なので、注意
されたい。ご存知の方は、よろしければご教授ください。
「Lego Mindstomes NXT - NXC プログラミング (1)」に記したが、
制御文のところだけ再掲する。
■ 制御文
□ if 文
if (条件式) 条件式の結果が true のとき実行するボディ
if (条件式) 条件式の結果が true のとき実行するボディ else そ
うでないときに実行するボディ
□ switch 文
switch (式) ボディ
case 定数式 :
default :
□ while 文
while (条件式) ボディ
□ do while 文
do ボディ while (条件式)
□ for 文
for (初期値化式 ; 条件式 ; 更新式) ボディ
□ repeat 文
repeat (式) ボディ
C 言語にはない制御文です。式の結果の回数分だけ繰り返します。
なお、式の結果が 0 以下の場合、ボディを実行することはありま
せん。
例
---
repeat (10) {
// 繰り返すコード
}
---
□ until マクロ
つぎのように定義されています。センサーを使うときによく使いま
す。
#define until(c) while(!(c))
したがって、while キーワードの代わりに、
until (条件式) ボディ
do ボディ until (条件式)
と書くことができます。このとき、条件式の意味は、「~まで」と
いうことになるので、「条件式が true になったらループ終了」と
いうことです。
■ くり返し制御文のサンプル
それでは、TrunRight01 プログラムをくり返しの制御文を使ってそ
れぞれ作ってみましょう。繰り返す回数は 3 回です。
----------- -----------
プログラム 使用制御文
----------- -----------
TrunRight02 repeat
TrunRight03 for
TrunRight04 while
TrunRight05 do - until
----------- -----------
---
/** * TrunRight02.nxc * 「トライボット」使用 * 500ミリ秒間前進し、その後右に180度曲がる。これを3回繰り返 す。 * @author maruno * @version 1.0, 2008-01-05 * @since 1.0 */ #include "NXCDefs.h" #define MOVE_TIME 500 #define TURN_TIME 360 task main() { repeat (3) { OnFwd(OUT_BC, 75); Wait(MOVE_TIME); OnRev(OUT_C, 75); Wait(TURN_TIME); } Off(OUT_BC); }
---
---
/** * TrunRight03.nxc * 「トライボット」使用 * 500ミリ秒間前進し、その後右に180度曲がる。これを3回繰り返 す。 * @author maruno * @version 1.0, 2008-01-05 * @since 1.0 */ #include "NXCDefs.h" #define MOVE_TIME 500 #define TURN_TIME 360 task main() { for (int i = 0; i <3; i++) {
---
for 文を使っています。C 言語と違い、初期値化式でローカル変数
を宣言することもできます。
---
/** * TrunRight04.nxc * 「トライボット」使用 * 500ミリ秒間前進し、その後右に180度曲がる。これを3回繰り返 す。 * @author maruno * @version 1.0, 2008-01-05 * @since 1.0 */ #include "NXCDefs.h" #define MOVE_TIME 500 #define TURN_TIME 360 task main() { int i = 0; while (i <3) {
---
---
/** * TrunRight05.nxc * 「トライボット」使用 * 500ミリ秒間前進し、その後右に180度曲がる。これを3回繰り返 す。 * @author maruno * @version 1.0, 2008-01-05 * @since 1.0 */ #include "NXCDefs.h" #define MOVE_TIME 500 #define TURN_TIME 360 task main() { int i = 0; do { OnFwd(OUT_BC, 75); Wait(MOVE_TIME); OnRev(OUT_C, 75); Wait(TURN_TIME); i++; } until (i >= 3); Off(OUT_BC); }
---
until マクロを使っています。マクロ展開後は、
do {
...
} while (!(i >= 3));
になります。
■ 分岐制御文を使ったサンプル
ランダムにトライボットが 10 秒間動きます。
ランダムな時間値やパワー値の取得は、Random 関数を使っていま
す。
---
/** * Random01.nxc * 「トライボット」使用 * ランダムに10秒間動く。 * @author maruno * @version 1.0, 2008-01-05 * @since 1.0 */ #include "NXCDefs.h" #define MOVE_LIMIT_TIME 1000 * 10 #define TURN_TIME 180 task main() { int move_total_time = 0; do { int outputs; switch (Random(3)) { // (1) case 0: outputs = OUT_B; break; case 1: outputs = OUT_C; break; default: outputs = OUT_BC; break; } int move_time = Random(500); OnFwd(outputs, Random(201) - 100); // (2) Wait(move_time); move_total_time += move_time; Off(OUT_BC); // (3) } while (move_total_time <MOVE_LIMIT_TIME);
---
□ switch (Random(3)) { // (1)
モーター B、C、BC を動かすので、どのモーターを動かすかを乱数
(0, 1, 2)を使って決めます。
□ Random 関数
Random 関数は、オーバーロードされています。上限を引数で渡し
て、「0 以上 上限未満」の値を返す上の関数の方が使い勝手はい
いでしょう。
---
Random(n) Value
16 ビットの符号なしの乱数値(0 以上 n 未満)を返します。
例:
x = Random(10); // return a value of 0..9
---
---
Random() Value
16 ビットの符号つきの乱数値を返します。
例:
x = Random();
---
□ OnFwd(outputs, Random(201) - 100); // (2)
乱数で決まったモーターを、また、乱数値で指定されたパワーで動
かします。
OnFwd 関数のパワーは、-100 ~ 100 です。負数の場合は、後退す
る OnRev 関数と同じ意味になります。
□ Off(OUT_BC); // (3)
今回はループの中に入れています。一度、モーターを停止させない
と、停止させられるまで動き続けるからです。すなわち、モーター
B を動かしてからつぎに モーター C を動かす場合、モーター B
も停止しないと、つぎのモーター C では、モーター BC が動くこ
とになります。(これはこれでおもしろい動きになるかもしれませ
んが)
■ 情報をスクリーンに表示する
C 言語や C++ 言語の最初に学習するのは、標準出力に "Hello Wor
ld!" を表示する、というものでしょう。CUI のアプリケーション
では、何かしらの形で表示しないと動きがわかりません。でも、ロ
ボットを使ったプログラムでは、モーターなど、標準出力に表示し
なくても動きがわかったりします。
ただ、センサーから入力した値などは、表示しないとわかりません。
ここでは、スクリーンに文字列を表示してみましょう。
描画や画像を表示することもできますが、これは別の機会に。
□ "Hello World!" の表示
まずは、定番の "Hello World!" を表示してみます。
---
/** * HelloWorld01.nxc * 「トライボット」使用 * スクリーンに "Hello World!" を示する。 * @author maruno * @version 1.0, 2008-01-05 * @since 1.0 */ #include "NXCDefs.h" task main(){ TextOut(0, LCD_LINE3, "Hello World!"); // (1) TextOut(0, LCD_LINE6, "12345678901234567890"); // (2) Wait(5000); }
---
このプログラムで、スクリーンの 3 行目に "Hello World!" が、
また、6 行目に "1234567890123456" が 5 秒間表示されたと思い
ます。
文字列の表示には、TextOut 関数を使います。
□ TextOut
---
TextOut(x, y, msg, clear = false) Function
文字列をスクリーンの座標 (x ,y) から書きます。y にはつぎの値
を指定します。
LCD_LINE1、LCD_LINE2、...、LCD_LINE8
引数 clear は、この文字列を表示する前にスクリーンをクリアす
るかどうかを指定します。指定がなければ、クリアしません(デフ
ォルト値が false です)
例:
TextOut(0, LCD_LINE3, "Hello World!");
---
なお、引数の最後に「clear = false」とあるのは、この引数は省
略してもいいし、省略しなくてもいい。省略した場合は、デフォル
ト値として、「false」を指定したのと同じことになる、というこ
とです。これも、C++ ではおなじみの「デフォルト引数」というも
のですね。
□ TextOut(0, LCD_LINE3, "Hello World!"); // (1)
TextOut 関数によって、指定された文字列を 3 行目に表示します。
□ TextOut(0, LCD_LINE6, "12345678901234567890"); // (2)
20 文字分指定されていますが、実際に表示されるのは最初の 16
文字だけです。
スクリーンは、一行 16 文字分だけ表示されます。
■ 文字列を編集して表示する
プログラム Random01 は、10 秒間ランダムに動きます。どのよう
に動くかは、実際に動かしてみないとわかりません。このときの動
く値を、スクリーンに表示してみましょう。
---
/** * Random02.nxc * 「トライボット」使用 * ランダムに10秒間動く。そのときの情報をスクリーンに表示す る。 * @author maruno * @version 1.0, 2008-01-05 * @since 1.0 */ #include "NXCDefs.h" #define MOVE_LIMIT_TIME 1000 * 10 #define TURN_TIME 180 task main() { int move_total_time = 0; do { int outputs; string moter; switch (Random(3)) { case 0: outputs = OUT_B; moter = "B"; break; case 1: outputs = OUT_C; moter = "C"; break; default: outputs = OUT_BC; moter = "BC"; break; } int power = Random(201) - 100; int move_time = Random(100) * 10; OnFwd(outputs, power); string msg; string num; msg = StrCat("moter = ", moter); // (1) TextOut(0, LCD_LINE3, msg); num = NumToStr(power); // (2) msg = StrCat("power = ", num); TextOut(0, LCD_LINE4, msg); num = NumToStr(move_time); msg = StrCat("time = ", num); // TextOut(0, LCD_LINE5, StrCat("time = ", NumToStr(m ove_time))); // (3) TextOut(0, LCD_LINE5, msg); Wait(move_time); move_total_time += move_time; Off(OUT_BC); } while (move_total_time <MOVE_LIMIT_TIME);
---
□ msg = StrCat("moter = ", moter); // (1)
StrCat 関数は、文字列を連結し、その結果を返す関数です。
□ StrCat 関数
---
StrCat(str1, str2, ..., strN) Value
引数で指定された複数の文字列を連結して返します。
例:
msg = StrCat("test", "please"); // returns "testplease"
---
□ num = NumToStr(power); // (2)
NumToStr 関数は、数値を文字列に変換する関数です。
□ NumToStr 関数
---
NumToStr(value) Value
指定された数値 num を文字列に変換して返します。
例:
msg = NumToStr(-2); // returns "-2" in a string
---
□ TextOut(0, LCD_LINE5, StrCat("time = ", NumToStr(move_tim
e)));
なお、このように指定したいところですが、コンパイルエラーにな
ります。
どうやら、NXC は、関数のネストができないようです。★
以上