04 月 26 日(火)3-4h

KTurtle(2)

タートルグラフィックス「KTurtle」を利用して, コードを効率良く(複雑な処理を短く) 記述するための考え方を身に着けよう.

また,以下の実習が終わったら, vimtutor のレッスン6に取り組もう. (レッスン5は現段階では理解が難しいのでスキップする. また,レッスン7は上級者専用.)


変数と数式

前回学んだ通り,多角形を描くには, 一定距離の前進(forward)と 一定角度の旋回(turnleft または turnright)とを 繰り返せばよかった. たとえば,12角形の場合のコードは:

reset
repeat 12 {
	forward 10
	turnleft 30
}

これを元にして,螺旋(らせん)を描くように改造してみよう. 前進の距離を少しずつ変化させるようにすればよい: (効率的なソースコードの例)

reset
$len = 1			# 距離の変数 $len に定数 1 を代入
repeat 100 {
	forward $len		# 距離 $len だけ前進
	turnleft 30
	$len = $len + 1		# 距離を 1 だけ増やす
		# $len の値は repeat するたびに,1 から 2 へ,2 から 3 へ,... と変化
}
距離ではなく,角度を変化させてもよい. 余裕があれば,実際にやってみよう.

このように,変数と数式とをうまく利用すれば, 複雑な図形を短いコードで表わせるようになる.

もし,変数を使わずに螺旋を描こうとすると, repeat も使えず,とても長たらしいコードを書かなければならない: (非効率的な例.真似してはいけません.)

reset
forward 1
turnleft 30
forward 2
turnleft 30
forward 3
turnleft 30
.
.
.
forward 100
turnleft 30

なお,変数は自由に作れるが,次の命名規則を守ること:

適格な変数名の例:$angle$v123$p2x,...

不適格な変数名の例:angle$123v$-px,...

ちなみに,C言語では,変数に「$」は付けない.

サブルーチン

独自のコマンドを作り,プログラムを短く分けて,分かりやすく組み立てよう. 多角形を描くコマンド polygon の定義例・使用例:

learn polygon $n, $len {	# polygonコマンドの定義
	repeat $n {
		forward $len
		turnleft 360/$n
	}
}

reset
repeat 4 {
	polygon 4, 100		# 大きさ10 の四角形
	turnright 90
	forward 100
}

このプログラムを実行すると,

部品化の考え方は,POV-Ray のオブジェクトの #declare とか, Scheme の関数の define とかと同じだ.

乱数

乱数を利用すると,不規則な図形を描ける. もっとも単純な例:(ランダムウォーク)

reset
repeat 100 {
	$len = random 10,30		# 10以上,30以下の乱数
	$ang = random -90, 90		# -90以上,+90以下の乱数
	turnleft $ang
	forward $len
}

何度も実行してみよう. 実行する度に,異なる結果になるハズだ. 画面外にハミ出てしまう場合もあるが...


条件分岐

ランダムウォークを元に,ハミ出ても戻って来るようにしてみた:

reset
canvassize 200, 400		# 画面サイズを横200×縦400に
center				# タートルを中央へ
repeat 100 {
	$x = getx		# タートルの現在のx座標
	$y = gety		# タートルの現在のy座標

	if ($x < 0) { gox 200 }	# x方向にハミ出たら逆から戻る
	if (200 < $x) { gox 0 }

	if ($y < 0) { goy 400 }	# y方向に   〃
	if (400 < $y) { goy 0 }

	$len = random 10,30
	$ang = random -90, 90
	turnleft $ang
	forward $len
}

新しいコマンドがたくさん出てきたが, ここで一番重要なものは if だ. 一般形は次の通り:

if ( 条件式 ) {
	条件が成立した場合の処理
} else {
	成立しなかった場合の処理
}

なお,else 以降は省略してもよい.

また,条件式では, 不等号「<」,「>」の他, 等号「==」,否定等号「!=」も利用できる.

数学の世界では,等号と否定等号は「=」と「≠」だが, プログラミングの世界では,「==」と「!=」を使うことが多い. なお,プログラミングの世界では, 「=」は比較「等しいかどうか?調べろ!」ではなく, 代入「変数の値を書き換えろ!」であることが多い.

ユーザインタフェース

KTurtle では,ダイアログウィンドウを通じて, ユーザとタートル(プログラム)との間の通信も簡単に実現できる. 試しに,タートルをリモコンロボットにしてみた:

reset
canvassize 300, 400 
go 150, 300			# 座標(150, 300) に移動
while (true) {			# 永久に繰り返す
        $f = ask "どーする? (s/r/l/end)"
					# ダイアログから指示を入力
					# Straight/Right/Left/...
        if ($f == "l") {
		turnleft 90
	} else if ($f == "r") {
		turnright 90
	}
        else if ($f == "end") {
		break		# 繰り返しを途中終了
	}
        forward 30
}
message "おしまい"		# ダイアログにメッセージを出力

なお,この例では,変数に数値ではなく,文字列を代入したりしている. だけど,数値の場合とほとんど同じなので,説明不要だよね?

KTurtle の場合,数値も文字列もほとんど同様に扱える. 一方,C言語の場合,数値と文字列とを区別して扱う必要がある.

練習問題

  1. 階段を描け. (ただし,turnleft を一回だけ使って... ヒント:+90 → ー90 → +90 → ー90 → ... 回転角度を変数にして,−1 倍を繰り返す.)
  2. 星空を描け. (ランダムな大きさの星形をランダムな位置に...)
  3. リモコンタートルを改造し,終了確認機能を追加せよ. (「本当にやめるの?(yes/no)」みたいな...)
  4. [上級者用問題]画面の端を壁に見立てて,タートルを壁で跳ね返せ. (「ブロックくずし」のように... ヒント:方向については,現在の値を調べることはできないので, タートル任せではなく,プログラマ側で管理する. つまり,turn* ではなく, direction で方向を指定.)

KTurtle のプログラムが止まらなくなってしまった場合, 強制終了するには,端末で次のコマンド:

$  killall kturtle
保存していないソースコードは消えてしまいます.

それと,練習問題の他,vimtutor も忘れずに...


本日の課題

今回学習した技(変数,数式,if,learn,等)を駆使して, ある程度複雑な図形を自由に作成せよ。 

レポート提出

(c) 2016, yanagawa@kushiro-ct.ac.jp