14 集合データ構造とアルゴリズム

14.1 学習目標

!!重要!! 新しいライブラリ

今回は、「入れ物タートル」「ボタンタートル」「入力タートル」という新しい機能が入ったライブラリを使います。

まず、皆さんが使っている論プロエディタの「lib」というフォルダにある、blib101.jarというファイルを削除してください。 これは、今まで使っていた古いライブラリです。

論プロエディタのダウンロードページ から新しいライブラリ(blib104.jar)をダウンロードし、皆さんが使っている論プロエディタの「lib」というフォルダに入れてください。

入れ替えができたら、新しいライブラリの動作確認をしてみましょう。タートルテンプレートを選び、startメソッド内に以下のプログラムを入力して、コンパイル・実行してください。

				
	HolderTurtle holder = new HolderTurtle();
	holder.最後に追加する(new CardTurtle(99));
	update();
				
			

以下のような画面が表示されれば成功です。

図 83 はじめての入れ物タートル

14.2 入れ物を使ったプログラム

Squeak編で理解した知識が生かせるように、Squeak編のときに利用したものと同じ入れ物をJavaで使えるようにしました(メソッド名も日本語にしてみました)。 利用法はほぼ一緒ですが、若干異なる部分もありますので、ここでは、Java版の入れ物の使い方を説明します。

14.2.1 カードを出し入れするプログラム

このプログラムは、10枚のカードを入れ物1に入れ、1枚ずつ取り出して入れ物2に移すプログラムです。

リスト 14.2.1.1 MoveCards.java
  1: /**
  2:  * プログラム名:カードを入れ物1から入れ物2に移動するプログラム
  3:  * 作成者: MegumiAraki 
  4:  * 作成日: Wed Dec 05 13:24:46 JST 2007
  5:  */
  6: public class MoveCards extends Turtle {
  7: 
  8: 	// 起動処理
  9: 	public static void main(String[] args) {
 10: 		Turtle.startTurtle(new MoveCards());
 11: 	}
 12: 
 13: 	// 入れ物
 14: 	HolderTurtle holder1;
 15: 	HolderTurtle holder2;
 16: 
 17: 	// タートルを動かす処理
 18: 	public void start() {
 19: 
 20: 		初期化する();
 21: 		print("アニメーションループを開始します");
 22: 
 23: 		// アニメションループ
 24: 		while (true) {
 25: 
 26: 			// 待つ
 27: 			sleep(0.5);
 28: 
 29: 			// 処理を行う
 30: 			if (holder1.入っているものの個数() != 0) {
 31: 				holder2.最後に追加する(holder1.カーソル位置にあるもの());// 入れ物1から入れ物2にカードを移動する
 32: 			} else if (holder1.入っているものの個数() == 0) {
 33: 				print("カード移動を終了します");
 34: 				break;// アニメーションループを抜ける
 35: 			} else {
 36: 				print("エラー");
 37: 			}
 38: 
 39: 			// 再描画する
 40: 			update();
 41: 
 42: 		}
 43: 		print("アニメーションループを終了しました");
 44: 	}
 45: 
 46: 	void 初期化する() {
 47: 		Turtle.window.size(550, 300);// ウインドウサイズを調節する
 48: 		hide();
 49: 
 50: 		// 入れ物を作る
 51: 		holder1 = new HolderTurtle();
 52: 		holder2 = new HolderTurtle();
 53: 
 54: 		// 入れ物を見やすい位置に置く
 55: 		holder1.warp(50, 50);
 56: 		holder2.warp(50, 100);
 57: 
 58: 		// 入れ物に10枚のカードを入れる
 59: 		for (int i = 0; i < 10; i++) {
 60: 			holder1.最後に追加する(new CardTurtle(i * 10));
 61: 		}
 62: 
 63: 		update();
 64: 	}
 65: 
 66: }

下のボタンを押すと、このプログラムが実行できます。 ここをクリックすると、プログラムをダウンロードできます。

14.2.1.1 グローバル変数

このプログラムでは、はじめに、クラスブロック内で変数を宣言しています。 このように、クラスブロック内で宣言された変数をグローバル変数 (5) といいます。指定されたブロック内(たとえば、あるメソッド内)でしか有効でない変数をローカル変数といいます。 グローバル変数の有効範囲は、クラス全体です。そのクラスのどのメソッドからも使うことができます。

						
 13: 	// 入れ物
 14: 	HolderTurtle holder1;
 15: 	HolderTurtle holder2;


					

このプログラムでは、holder1とholder2をグローバル変数として宣言し、 startメソッドと初期化するメソッドの2つのメソッドで、これらの変数を使っています。

グローバル変数は、クラス内のどのメソッドからも値を変更できるため、プログラムが意図しない動作をしたとき、どのメソッドで値が変更されたかを読み解くことが困難になります。 このようにプログラムの保守性が下がるため、グローバル変数の使用は、プログラミングの作法としてはあまりよくないものだと言われています。

しかし、ある変数が多くのメソッドで使われる場合、グローバル変数を使わなければ、毎回変数を引数として渡さなければならず、面倒です。 そのため、ある変数が多くのメソッドで使われる場合、グローバル変数として宣言することがあります。

このプログラムでは、startメソッドと初期化するメソッドの両方で、holder1とholder2という変数を使っているため、 この2つをグローバル変数として宣言しています。

  1. Javaでは、このような変数を正式にはインスタンス変数と言います。ここでは、クラスのメソッドに対してグローバルな変数である、という意味で、ローカル変数と対比する概念として、グローバル変数という表現を用いています。

14.2.1.2 break文

このプログラムでは、アニメーションループを抜け出すためにbreak文を使用しています。 break文が繰り返し文(while文、for文、do/while文)の中で実行されると、 プログラムの処理の流れはただちに繰り返し構造から抜け出し、 制御が繰り返し構造の直後にある命令に移ります。

						
 23: 		// アニメションループ
 24: 		while (true) {
 25:
 26: 			// 処理を行う
 27: 			if (holder1.入っているものの個数() != 0) {
 28: 				holder2.最後に追加する(holder1.カーソル位置にあるもの());// 入れ物1から入れ物2にカードを移動する
 29: 			} else if (holder1.入っているものの個数() == 0) {
 30: 				print("カード移動を終了します");
 31: 				break;// アニメーションループを抜ける
 32: 			} else {
 33: 				print("エラー");
 34: 			}
 35:
 36: 			// 再描画する
 37: 			update();
 38:
 39: 			// 待つ
 40: 			sleep(1);
 41: 		}
 42:
 43: 		print("アニメーションループを終了しました");
 44: 	}


					

このプログラムでは、holder1に入っているものの個数が0になると、 24行目から41行目までのアニメーションループを脱出し、制御が43行目に移ります。

break文は、構造化プログラミング(入り口ひとつ、出口ひとつの処理構造)を破壊するものとして、 プログラミングの作法としてはあまりよくないものだと言われています。 break文を使わなくても、同じ処理の流れを定義することは可能なので、 プログラミングの作法を重んじるプログラマは、break文の代わりに変数を用いて繰り返し構造を制御し、 break文を使わないプログラムを記述します。

ここでは、「繰り返しを抜ける」ということを変数を使わず表現し、分かりやすくするため、break文を使っています。

14.2.2 入れ物に関する新しい命令

この章では、「入れ物タートル」を使ったプログラミングを行います。 以下に、入れ物タートルに関する命令の一覧を示します。

14.2.2.1 入れ物を作る命令

HolderTurtle [変数名];
入れ物タートル型の変数を宣言します。
[(入れ物タートル型として宣言済みの)変数名] = new HolderTurtle()
[変数名]という名前の新しい入れ物タートルを作ります。

14.2.2.2 追加と削除

最後に追加する([追加するもの])
入れ物の最後にタートル型(6)のものを追加します。
先頭に追加する([追加するもの])
入れ物の先頭にタートル型(注釈参照)のものを追加します。
カーソル位置に追加する([追加するもの])
入れ物のカーソル位置に(注釈参照)のものを追加します。
カーソル位置のものを削除する()
カーソル位置にあるものを削除します
入っているものを全て捨てる()
入れ物に入っているものを全て捨てます。
  1. 画像タートル・テキストタートル・カードタートルのいずれか。自作のHouse、Starなどは今のところ対応していません。

14.2.2.3 カーソルに関する命令

カーソル位置()
現在のカーソル位置を取得します。
カーソル位置を変える([カーソル番号])
カーソル位置を、指定したカーソル番号に変えます
カーソルを進める()
カーソルを1進めます
カーソルを戻す()
カーソルを1戻します
カーソル位置にあるもの()
カーソル位置にあるものを取得します。
カーソル位置にあるものの数値()
カーソル位置にあるカードの数値を取得します。カーソル位置にあるものが数字の書かれたカードでない場合は、-1を返します。
カーソル位置にあるものの内容()
カーソル位置にあるカードの内容を文字列型で取得します。内容が取得できない場合はNULLという文字列を返します。

14.2.2.4 その他の命令

かきまぜる()
入れ物の中身をかきまぜます。
入っているものの個数()
入っているものの個数を取得します

14.2.3 カードに関する新しい命令

以下に、カードに関する新しい命令の一覧を示します

14.2.3.1 カードを作る命令

CardTurtle [変数名];
カードタートル型の変数を宣言します。
[(カードタートル型として宣言済みの)変数名] = new CardTurtle([カードの内容])
[変数名]という名前の新しいカードタートルを作ります。カードの内容には、文字列、小数、整数を入れることができます。

14.2.3.2 その他の命令

text()
カードの内容を文字列型で取得します
text([カードの内容])
カードの内容を、指定したカードの内容に変えます
fontsize()
カードの内容のフォントサイズを取得します
fontsize([フォントサイズの指定])
カードの内容のフォントサイズを指定します
カードを作り、入れ物に入れる命令の省略形

新しいカードを作り、入れ物に入れるときには、以下のように命令を書きます。

							
CardTurtle card;
card = new CardTurtle(10);
holder.最後に追加する(card);

						

この3文は、以下のように省略して書くことができます。

							
holder.最後に追加する(new CardTurtle(10));

						
やってみよう!

ランダムな数が書かれたカードが10枚入った入れ物を作ろう。

やってみよう!

0から9までの数が書かれたカードが10枚入った入れ物を作り、1秒に1回かきまぜて、 かきまぜるたびに「先頭にある数は○○です」と表示するプログラムを作ろう。

やってみよう!

ユーザに「何番目のカードを選びますか?」と表示し、ユーザからカーソル位置の入力を受けつけ、 10枚のカードが入った入れ物から、ユーザが入力した位置にあるカードの数字を取得し、 「あなたの選んだカードに書かれている数は○○ですね」と表示するプログラムを作ろう。

14.3 ソートアルゴリズム

14.3.1 ソートアルゴリズムとは

Squeak編で学んだように、ソートアルゴリズムとは、ばらばらに並んでいるものを決まったならびに並び替える手順のことです。

本節では、Squeak編で学習した最小値選択法を、Squeakで行った方法と全く同じ方法で(1重ループ)で実現したもの(Squeakと同じ)をまず作成します。

次に、Squeakではできなかった2重ループで実現したものを作ってみます。

14.3.2 1重ループの最小値選択法(Squeakと同じ)

それでは、1重ループのプログラムを見ていきましょう。

14.3.2.1 1重ループの最小値選択法(Squeakと同じ)のフローチャート

このフローチャートでは、全体が1つのループの中に入っています。

図 14.3.2.1.1 最小値検索法1重(Squeakと同じ)ループフローチャート

14.3.2.2 最小値選択法(1重ループ(Squeakと同じ))

このプログラムは1重ループの最小値選択法の例です。

リスト 14.3.2.2.1 SelectionSort1.java
  1: /**
  2:  * プログラム名:最小値選択法(Squeakと同じ)
  3:  * 作成者: MegumiAraki 
  4:  * 作成日: Wed Dec 05 21:36:23 JST 2007
  5:  */
  6: public class SelectionSort1 extends Turtle {
  7: 
  8: 	// 起動処理
  9: 	public static void main(String[] args) {
 10: 		Turtle.startTurtle(new SelectionSort1());
 11: 	}
 12: 
 13: 	// カードの束
 14: 	HolderTurtle 未処理束;
 15: 	HolderTurtle 最小値候補;
 16: 	HolderTurtle ソート済束;
 17: 	HolderTurtle 検索済束;
 18: 
 19: 	// タートルを動かす処理
 20: 	public void start() {
 21: 
 22: 		初期化する();
 23: 
 24: 		// カードを並び替える(並び替えの様子をアニメーションで表示する)
 25: 		while (true) {
 26: 			if (未処理束.入っているものの個数() != 0) {
 27: 				if (未処理束.カーソル位置にあるものの数値() < 最小値候補.カーソル位置にあるものの数値()) {
 28: 					検索済束.最後に追加する(最小値候補.カーソル位置にあるもの());
 29: 					最小値候補.最後に追加する(未処理束.カーソル位置にあるもの());
 30: 				} else {
 31: 					検索済束.最後に追加する(未処理束.カーソル位置にあるもの());
 32: 				}
 33: 				if (未処理束.入っているものの個数() != 0) {
 34: 				} else {
 35: 					ソート済束.最後に追加する(最小値候補.カーソル位置にあるもの());
 36: 					検索済束.入っている全てのものを以下の入れ物に移動する(未処理束);
 37: 					最小値候補.最後に追加する(未処理束.カーソル位置にあるもの());
 38: 				}
 39: 			} else {
 40: 				ソート済束.最後に追加する(最小値候補.カーソル位置にあるもの());
 41: 				描画する();
 42: 				break;
 43: 			}
 44: 			描画する();
 45: 		}
 46: 	}
 47: 
 48: 	void 初期化する() {
 49: 		hide();
 50: 		Turtle.window.size(550, 400);// ウインドウサイズを調節する
 51: 
 52: 		// カードの束を作る
 53: 		未処理束 = new HolderTurtle();
 54: 		未処理束.warp(50, 120);
 55: 		TextTurtle 未処理束タグ = new TextTurtle("未処理束");
 56: 		未処理束タグ.fontsize(12);
 57: 		未処理束タグ.warp(50, 100);
 58: 
 59: 		最小値候補 = new HolderTurtle();
 60: 		最小値候補.warp(50, 50);
 61: 		TextTurtle 最小値候補タグ = new TextTurtle("最小値候補");
 62: 		最小値候補タグ.fontsize(12);
 63: 		最小値候補タグ.warp(50, 30);
 64: 
 65: 		ソート済束 = new HolderTurtle();
 66: 		ソート済束.warp(50, 260);
 67: 		TextTurtle ソート済束タグ = new TextTurtle("ソート済束");
 68: 		ソート済束タグ.warp(50, 240);
 69: 		ソート済束タグ.fontsize(12);
 70: 
 71: 		検索済束 = new HolderTurtle();
 72: 		検索済束.warp(50, 190);
 73: 		TextTurtle 検索済束タグ = new TextTurtle("検索済束");
 74: 		検索済束タグ.fontsize(12);
 75: 		検索済束タグ.warp(50, 170);
 76: 
 77: 		// カードを8枚作り、未処理束に入れる
 78: 		for (int i = 0; i < 8; i++) {
 79: 			未処理束.最後に追加する(new CardTurtle(random(100)));
 80: 		}
 81: 
 82: 		// 未処理束の先頭からカードを1枚取り出し、最小値候補に置く
 83: 		最小値候補.最後に追加する(未処理束.カーソル位置にあるもの());
 84: 
 85: 		update();
 86: 	}
 87: 
 88: 	// 描画する
 89: 	void 描画する() {
 90: 		update();
 91: 		sleep(0.1);
 92: 	}
 93: 
 94: }

下のボタンを押すと、このプログラムが実行できます。 ここをクリックすると、プログラムをダウンロードできます。

14.3.3 2重ループの最小値選択法

次に、2重ループのプログラムを見ていきましょう。

14.3.3.1 2重ループの最小値選択法のフローチャート

このフローチャートでは、ループの中にループが入っています。

図 14.3.3.1.1 最小値選択法2重ループフローチャート

while文とdo-while文

while文とdo-while文は、両方とも繰り返しを表す文ですが、 条件判断の位置が違います。 while文は、最初に繰り返しを続けるかどうか調べて、続けるならば処理を行い、 続けないならば処理を抜ける、という構造をしています。 do-while文は、はじめに処理を行い、処理を行ったあとで、 繰り返しを続けるかどうか調べて、続けるならば2回目の処理を行い、続けないならば処理を抜ける、 という構造をしています。

14.3.3.2 最小値選択法(2重ループ)

このプログラムは2重ループの最小値選択法の例です。

リスト 14.3.3.2.1 SelectionSort2.java
  1: /**
  2:  * プログラム名:最小値選択法(2重ループ) 
  3:  * 作成者: MegumiAraki 
  4:  * 作成日: Wed Dec 05 21:36:23 JST 2007
  5:  */
  6: public class SelectionSort2 extends Turtle {
  7: 
  8: 	// 起動処理
  9: 	public static void main(String[] args) {
 10: 		Turtle.startTurtle(new SelectionSort2());
 11: 	}
 12: 
 13: 	// カードの束
 14: 	HolderTurtle 未処理束;
 15: 	HolderTurtle 最小値候補;
 16: 	HolderTurtle ソート済束;
 17: 	HolderTurtle 検索済束;
 18: 
 19: 	// タートルを動かす処理
 20: 	public void start() {
 21: 		初期化する();
 22: 
 23: 		while (true) {
 24: 			最小値候補.最後に追加する(未処理束.カーソル位置にあるもの());
 25: 			描画する();
 26: 
 27: 			do {
 28: 				// めくる
 29: 				if (未処理束.カーソル位置にあるものの数値() < 最小値候補.カーソル位置にあるものの数値()) {// (小さくなければ)
 30: 					検索済束.最後に追加する(最小値候補.カーソル位置にあるもの());
 31: 					描画する();
 32: 					最小値候補.最後に追加する(未処理束.カーソル位置にあるもの());
 33: 					描画する();
 34: 				} else {
 35: 					検索済束.最後に追加する(未処理束.カーソル位置にあるもの());
 36: 					描画する();
 37: 				}
 38: 			} while (未処理束.入っているものの個数() != 0);
 39: 			ソート済束.最後に追加する(最小値候補.カーソル位置にあるもの());
 40: 			描画する();
 41: 			if (検索済束.入っているものの個数() == 1) {
 42: 				break;
 43: 			}
 44: 			検索済束.入っている全てのものを以下の入れ物に移動する(未処理束);
 45: 			描画する();
 46: 		}
 47: 
 48: 		ソート済束.最後に追加する(検索済束.カーソル位置にあるもの());// 最小値候補をソート済み束に置く
 49: 		描画する();
 50: 	}
 51: 
 52: 	void 初期化する() {
 53: 		hide();
 54: 		Turtle.window.size(550, 400);// ウインドウサイズを調節する
 55: 
 56: 		// カードの束を作る
 57: 		未処理束 = new HolderTurtle();
 58: 		未処理束.warp(50, 120);
 59: 		TextTurtle 未処理束タグ = new TextTurtle("未処理束");
 60: 		未処理束タグ.fontsize(12);
 61: 		未処理束タグ.warp(50, 100);
 62: 
 63: 		最小値候補 = new HolderTurtle();
 64: 		最小値候補.warp(50, 50);
 65: 		TextTurtle 最小値候補タグ = new TextTurtle("最小値候補");
 66: 		最小値候補タグ.fontsize(12);
 67: 		最小値候補タグ.warp(50, 30);
 68: 
 69: 		ソート済束 = new HolderTurtle();
 70: 		ソート済束.warp(50, 260);
 71: 		TextTurtle ソート済み束タグ = new TextTurtle("ソート済束");
 72: 		ソート済み束タグ.fontsize(12);
 73: 		ソート済み束タグ.warp(50, 240);
 74: 
 75: 		検索済束 = new HolderTurtle();
 76: 		検索済束.warp(50, 190);
 77: 		TextTurtle 検索済み束タグ = new TextTurtle("検索済束");
 78: 		検索済み束タグ.fontsize(12);
 79: 		検索済み束タグ.warp(50, 170);
 80: 
 81: 		// カードを8枚作り、未処理束に入れる
 82: 		for (int i = 0; i < 8; i++) {
 83: 			未処理束.最後に追加する(new CardTurtle(random(100)));
 84: 		}
 85: 
 86: 		update();
 87: 	}
 88: 
 89: 	void 描画する() {
 90: 		update();
 91: 		sleep(0.1);
 92: 	}
 93: 
 94: }

下のボタンを押すと、このプログラムが実行できます。 ここをクリックすると、プログラムをダウンロードできます。

このプログラムでは、命令が実行されるたびに再描画しています。 これは、カードの動く様子を目に見えるようにするためです。 再描画命令を書かなければ、カードの動く様子は描画されず、処理前と処理後の様子のみが描画されます。 1重ループの最小値選択法では、ループの最後のみに際描画命令を書いていましたが、 2重ループのプログラムで、外側のループの最後のみに再描画命令を書くと、 内側のループを処理している間、カードの移動が一度も描かれません。

考えてみよう!

1重ループ・2重ループのフローチャートとプログラムを比較して、どちらが分かりやすいか考えてみましょう。 また、どちらがプログラムとして書きやすいか考えてみましょう。

14.4 ボタンを使ったプログラム

Java版ソートプログラムを実行してみるときに、リセットしたり、ストップしたりするボタンがないのが不便ですね。 ここでは、タートルライブラリのボタンタートルの使い方を説明し、Java版ソートプログラムに組み込む例を提示します。 次に、ボタンを使うと、1ステップごとに処理を止めているように見せるプログラム(ステップ実行)のプログラムも比較的簡単に作れることを示します。

ボタンを使ったプログラムをアプレットで実行する際には、 必ず、ボタンが表示されている画面を一度クリックしてください。 ボタンが表示されている画面をクリックしないと、ボタンへの入力が受け付けられません。

14.4.1 どのボタンが押されたか表示するプログラム

このプログラムは、どのボタンが押されたかをコンソールに表示するプログラムです。

リスト 14.4.1.1 ButtonSample.java
  1: /**
  2:  * プログラム名:どのボタンが押されたか表示するプログラム 
  3:  * 作成者: MegumiAraki 
  4:  * 作成日: Wed Dec 05 13:24:46 JST
  5:  * 2007
  6:  */
  7: public class ButtonSample extends Turtle {
  8: 
  9: 	// 起動処理
 10: 	public static void main(String[] args) {
 11: 		Turtle.startTurtle(new ButtonSample());
 12: 	}
 13: 
 14: 	// ボタン
 15: 	ButtonTurtle helloButton;
 16: 	ButtonTurtle byeButton;
 17: 
 18: 	// タートルを動かす処理
 19: 	public void start() {
 20: 
 21: 		初期化する();
 22: 
 23: 		// アニメションループ
 24: 		while (true) {
 25: 
 26: 			// 待つ
 27: 			sleep(0.25);
 28: 
 29: 			// 処理を行う
 30: 			if (helloButton.isClicked()) {// helloButtonがクリックされたら
 31: 				print(helloButton.text());
 32: 			} else if (byeButton.isClicked()) {// byeButtonがクリックされたら
 33: 				print(byeButton.text());
 34: 			} else {//何もクリックされていなかったら
 35: 				//何もしない
 36: 			}
 37: 
 38: 			// 再描画する
 39: 			update();
 40: 
 41: 		}
 42: 	}
 43: 
 44: 	void 初期化する() {
 45: 		hide();
 46: 
 47: 		// ボタンを作る
 48: 		helloButton = new ButtonTurtle("こんにちは");
 49: 		byeButton = new ButtonTurtle("さようなら");
 50: 
 51: 		// ボタンを見やすい位置に置く
 52: 		helloButton.warp(100, 50);
 53: 		byeButton.warp(100, 100);
 54: 
 55: 		// 再描画する
 56: 		update();
 57: 	}
 58: 
 59: }

下のボタンを押すと、このプログラムが実行できます。 ここをクリックすると、プログラムをダウンロードできます。

ボタンが押されたら、ボタンの内容をコンソールに出力します。

14.4.2 ボタンに関する新しい命令

以下に、ボタンに関する命令の一覧を示します

14.4.2.1 ボタンを作る命令

ButtonTurtle [変数名];
ボタンタートル型の変数を宣言します。
[(ボタンタートル型として宣言済みの)変数名] = new ButtonTurtle([ボタンのラベル])
[変数名]という名前の新しいボタンタートルを作ります。

14.4.2.2 ボタンから入力を受け付ける命令

isClicked()
ボタンがクリックされたか調べます

14.4.2.3 その他の命令

text()
ボタンのラベルを文字列型で取得します
text([ボタンのラベル])
ボタンのラベルを、指定したボタンのラベルに変えます
fontsize()
ボタンのラベルのフォントサイズを取得します
fontsize([フォントサイズの指定])
ボタンのラベルのフォントサイズを指定します
やってみよう!

10枚のカードが入った入れ物と、「カーソルを1進める」というボタンを用意し、 ボタンを押すとカーソルを1進めるプログラムを作ってみよう。

14.4.3 押されたボタンによって状態を切り替えるプログラム

「どのボタンを押したか表示するプログラム」は、ボタンを押したら命令を1回だけ実行するプログラムでした。 ボタンを使って「命令を1回実行する」のではなく、 「スタートボタンが押されてから、ストップボタンが押されるまで、このプログラムを実行したい」というように、 プログラムの状態を切り替えたい時があります。

このプログラムは、ボタンによって状態を切り替え、表示する内容を変えるプログラムです。

リスト 14.4.3.1 ButtonSwitchSample.java
  1: /**
  2:  * プログラム名:どのボタンが押されたか表示するプログラム 作成者: MegumiAraki 作成日: Wed Dec 05 13:24:46 JST
  3:  * 2007
  4:  */
  5: public class ButtonSwitchSample extends Turtle {
  6: 
  7: 	// 起動処理
  8: 	public static void main(String[] args) {
  9: 		Turtle.startTurtle(new ButtonSwitchSample());
 10: 	}
 11: 
 12: 	// ボタン
 13: 	ButtonTurtle helloButton;
 14: 	ButtonTurtle byeButton;
 15: 
 16: 	// タートルを動かす処理
 17: 	public void start() {
 18: 
 19: 		初期化する();
 20: 
 21: 		// アニメションループ
 22: 		String text = "表示用テキスト";
 23: 		while (true) {
 24: 			// 待つ
 25: 			sleep(0.25);
 26: 
 27: 			// 処理を行う
 28: 			// ボタンの入力を受け付ける
 29: 			if (helloButton.isClicked()) {// helloButtonがクリックされたら
 30: 				text = helloButton.text();
 31: 			}
 32: 			if (byeButton.isClicked()) {// byeButtonがクリックされたら
 33: 				text = byeButton.text();
 34: 			} else {
 35: 				//何もしない
 36: 			}
 37: 			print(text);//テキストを出力する
 38: 
 39: 			// 再描画する
 40: 			update();
 41: 		}
 42: 	}
 43: 
 44: 	void 初期化する() {
 45: 		hide();
 46: 
 47: 		// ボタンを作る
 48: 		helloButton = new ButtonTurtle("こんにちは");
 49: 		byeButton = new ButtonTurtle("さようなら");
 50: 
 51: 		// ボタンを見やすい位置に置く
 52: 		helloButton.warp(100, 50);
 53: 		byeButton.warp(100, 100);
 54: 
 55: 		// 再描画する
 56: 		update();
 57: 	}
 58: 
 59: }

下のボタンを押すと、このプログラムが実行できます。 ここをクリックすると、プログラムをダウンロードできます。

このプログラムでは、0.25秒に1回、textという変数に保存された文字をコンソールに出力しています。 ボタンが押されたら、textという変数の値が書き換わり、出力される文字が変わります。

14.4.4 ソートアルゴリズム(ボタンの実用例)

以下のプログラムは、ボタンを使ってソートアルゴリズムの処理の流れを制御している例です。

ボタンを使って、途中で最小値選択法の処理を一時停止したり、 ステップ実行(命令を1行ごとに実行すること)できるようにして、 ソートアルゴリズムを観察できるようにしています。

14.4.4.1 最小値選択法(1重ループ・ボタンあり)

このプログラムは1重ループの最小値選択法に改良を加え、 ボタンからの入力を受付け、スタート・ストップ・リセットをできるようにしたものです。

リスト 14.4.4.1.1 SelectionSort1WithButton.java
  1: /**
  2:  * プログラム名:最小値選択法
  3:  * 作成者:MegumiAraki 
  4:  * バージョン: 1.0 (日付)2007/12/8
  5:  */
  6: public class SelectionSort1WithButton extends Turtle {
  7: 
  8: 	// 起動処理
  9: 	public static void main(String[] args) {
 10: 		Turtle.startTurtle(new SelectionSort1WithButton());
 11: 	}
 12: 
 13: 	// カードの束
 14: 	HolderTurtle 未処理束;
 15: 	HolderTurtle 最小値候補;
 16: 	HolderTurtle ソート済束;
 17: 	HolderTurtle 検索済束;
 18: 
 19: 	// ボタン
 20: 	ButtonTurtle startButton;
 21: 	ButtonTurtle resetButton;
 22: 	ButtonTurtle stopButton;
 23: 
 24: 	// プログラムの状態
 25: 	boolean チクタク = false;
 26: 
 27: 	// タートルを動かす処理
 28: 	public void start() {
 29: 		初期化する();
 30: 
 31: 		// アニメーションループ
 32: 		int counter = 0;
 33: 		while (true) {
 34: 			sleep(0.025);
 35: 
 36: 			// ボタンの入力を受け付ける
 37: 			if (startButton.isClicked()) {
 38: 				チクタク = true;
 39: 			}
 40: 			if (resetButton.isClicked()) {
 41: 				リセットする();
 42: 			}
 43: 			if (stopButton.isClicked()) {
 44: 				チクタク = false;
 45: 			}
 46: 
 47: 			// 最小値選択法の1ステップの処理をする
 48: 			counter = (counter + 1) % 8;//8コマごとに実行する
 49: 			if (チクタク && counter == 0) {
 50: 				最小値選択法();
 51: 			}
 52: 
 53: 			update();
 54: 		}
 55: 	}
 56: 
 57: 	void 初期化する() {
 58: 		hide();
 59: 		Turtle.window.size(550, 400);// ウインドウサイズを調節する
 60: 
 61: 		// ボタンを作る
 62: 		startButton = new ButtonTurtle("スタート");
 63: 		resetButton = new ButtonTurtle("リセット");
 64: 		stopButton = new ButtonTurtle("ストップ");
 65: 
 66: 		startButton.warp(450, 20);
 67: 		resetButton.warp(450, 50);
 68: 		stopButton.warp(450, 80);
 69: 
 70: 		// カードの束を作る
 71: 		未処理束 = new HolderTurtle();
 72: 		未処理束.warp(50, 120);
 73: 		TextTurtle 未処理束タグ = new TextTurtle("未処理束");
 74: 		未処理束タグ.fontsize(12);
 75: 		未処理束タグ.warp(50, 100);
 76: 
 77: 		最小値候補 = new HolderTurtle();
 78: 		最小値候補.warp(50, 50);
 79: 		TextTurtle 最小値候補タグ = new TextTurtle("最小値候補");
 80: 		最小値候補タグ.fontsize(12);
 81: 		最小値候補タグ.warp(50, 30);
 82: 
 83: 		ソート済束 = new HolderTurtle();
 84: 		ソート済束.warp(50, 260);
 85: 		TextTurtle ソート済束タグ = new TextTurtle("ソート済束");
 86: 		ソート済束タグ.warp(50, 240);
 87: 		ソート済束タグ.fontsize(12);
 88: 
 89: 		検索済束 = new HolderTurtle();
 90: 		検索済束.warp(50, 190);
 91: 		TextTurtle 検索済束タグ = new TextTurtle("検索済束");
 92: 		検索済束タグ.fontsize(12);
 93: 		検索済束タグ.warp(50, 170);
 94: 
 95: 		// カードを8枚作り、未処理束に入れる
 96: 		for (int i = 0; i < 8; i++) {
 97: 			未処理束.最後に追加する(new CardTurtle(random(100)));
 98: 		}
 99: 
100: 		// 未処理束の先頭からカードを1枚取り出し、最小値候補に置く
101: 		最小値候補.最後に追加する(未処理束.カーソル位置にあるもの());
102: 
103: 		update();
104: 	}
105: 
106: 	void リセットする() {
107: 		最小値候補.入っている全てのものを以下の入れ物に移動する(未処理束);
108: 		検索済束.入っている全てのものを以下の入れ物に移動する(未処理束);
109: 		ソート済束.入っている全てのものを以下の入れ物に移動する(未処理束);
110: 
111: 		未処理束.かきまぜる();
112: 
113: 		最小値候補.最後に追加する(未処理束.カーソル位置にあるもの());
114: 
115: 		update();
116: 	}
117: 
118: 	void 最小値選択法() {
119: 		if (未処理束.入っているものの個数() != 0) {
120: 			if (未処理束.カーソル位置にあるものの数値() < 最小値候補.カーソル位置にあるものの数値()) {
121: 				検索済束.最後に追加する(最小値候補.カーソル位置にあるもの());
122: 				最小値候補.最後に追加する(未処理束.カーソル位置にあるもの());
123: 			} else {
124: 				検索済束.最後に追加する(未処理束.カーソル位置にあるもの());
125: 			}
126: 			if (未処理束.入っているものの個数() != 0) {
127: 			} else {
128: 				ソート済束.最後に追加する(最小値候補.カーソル位置にあるもの());
129: 				検索済束.入っている全てのものを以下の入れ物に移動する(未処理束);
130: 				最小値候補.最後に追加する(未処理束.カーソル位置にあるもの());
131: 			}
132: 		} else {
133: 			ソート済束.最後に追加する(最小値候補.カーソル位置にあるもの());
134: 			チクタク = false;
135: 		}
136: 	}
137: 
138: }

下のボタンを押すと、このプログラムが実行できます。 ここをクリックすると、プログラムをダウンロードできます。

ボタンの入力を受け付ける命令は、0.025秒に1回実行し、スムーズに入力を受け付けられるようにし、 最小値選択法は、動きが目で観察できるように、カウンタ (7) を使って0.2秒に1回実行するようにしています。

  1. このプログラムのカウンタは、0.025秒ごとに1,2,3,4,5,6,7,0,1,2,3,4...と変化していきます。このプログラムでは、カウンタの値が0のときに最小値選択法の1ステップの処理をするので、最小値選択法は、0.2秒に1回、実行されることになります。

14.4.4.2 最小値選択法(1重ループ・ステップ実行)

このプログラムは、最小値選択法を1ステップごとに停止させ、 最小値選択法が実行される様子を観察できるようにしたものです。

リスト 14.4.4.2.1 SelectionSort1ByStep.java
  1: /**
  2:  * プログラム名:最小値選択法(Squeakと同じ) 
  3:  * 作成者: MegumiAraki 
  4:  * 作成日: Wed Dec 05 21:36:23 JST 2007
  5:  */
  6: public class SelectionSort1ByStep extends Turtle {
  7: 
  8: 	// 起動処理
  9: 	public static void main(String[] args) {
 10: 		Turtle.startTurtle(new SelectionSort1ByStep());
 11: 	}
 12: 
 13: 	// カードの束
 14: 	HolderTurtle 未処理束;
 15: 	HolderTurtle 最小値候補;
 16: 	HolderTurtle ソート済束;
 17: 	HolderTurtle 検索済束;
 18: 
 19: 	// ボタン
 20: 	ButtonTurtle stepButton;
 21: 
 22: 	// タートルを動かす処理
 23: 	public void start() {
 24: 
 25: 		初期化する();
 26: 		ボタンが押されるまで待つ();
 27: 
 28: 		// カードを並び替える(並び替えの様子をアニメーションで表示する)
 29: 		while (true) {
 30: 			if (未処理束.入っているものの個数() != 0) {
 31: 				if (未処理束.カーソル位置にあるものの数値() < 最小値候補.カーソル位置にあるものの数値()) {
 32: 					検索済束.最後に追加する(最小値候補.カーソル位置にあるもの());
 33: 					ボタンが押されるまで待つ();
 34: 					最小値候補.最後に追加する(未処理束.カーソル位置にあるもの());
 35: 					ボタンが押されるまで待つ();
 36: 				} else {
 37: 					検索済束.最後に追加する(未処理束.カーソル位置にあるもの());
 38: 					ボタンが押されるまで待つ();
 39: 				}
 40: 				if (未処理束.入っているものの個数() != 0) {
 41: 				} else {
 42: 					ソート済束.最後に追加する(最小値候補.カーソル位置にあるもの());
 43: 					ボタンが押されるまで待つ();
 44: 					検索済束.入っている全てのものを以下の入れ物に移動する(未処理束);
 45: 					ボタンが押されるまで待つ();
 46: 					最小値候補.最後に追加する(未処理束.カーソル位置にあるもの());
 47: 					ボタンが押されるまで待つ();
 48: 				}
 49: 			} else {
 50: 				ソート済束.最後に追加する(最小値候補.カーソル位置にあるもの());
 51: 				ボタンが押されるまで待つ();
 52: 				break;
 53: 			}
 54: 		}
 55: 	}
 56: 
 57: 	void 初期化する() {
 58: 		hide();
 59: 		Turtle.window.size(550, 400);// ウインドウサイズを調節する
 60: 
 61: 		// ボタンを作る
 62: 		stepButton = new ButtonTurtle("ステップ");
 63: 		stepButton.warp(450, 20);
 64: 
 65: 		// カードの束を作る
 66: 		未処理束 = new HolderTurtle();
 67: 		未処理束.warp(50, 120);
 68: 		TextTurtle 未処理束タグ = new TextTurtle("未処理束");
 69: 		未処理束タグ.fontsize(12);
 70: 		未処理束タグ.warp(50, 100);
 71: 
 72: 		最小値候補 = new HolderTurtle();
 73: 		最小値候補.warp(50, 50);
 74: 		TextTurtle 最小値候補タグ = new TextTurtle("最小値候補");
 75: 		最小値候補タグ.fontsize(12);
 76: 		最小値候補タグ.warp(50, 30);
 77: 
 78: 		ソート済束 = new HolderTurtle();
 79: 		ソート済束.warp(50, 260);
 80: 		TextTurtle ソート済束タグ = new TextTurtle("ソート済束");
 81: 		ソート済束タグ.fontsize(12);
 82: 		ソート済束タグ.warp(50, 240);
 83: 
 84: 		検索済束 = new HolderTurtle();
 85: 		検索済束.warp(50, 190);
 86: 		TextTurtle 検索済束タグ = new TextTurtle("検索済束");
 87: 		検索済束タグ.fontsize(12);
 88: 		検索済束タグ.warp(50, 170);
 89: 
 90: 		// カードを8枚作り、未処理束に入れる
 91: 		for (int i = 0; i < 8; i++) {
 92: 			未処理束.最後に追加する(new CardTurtle(random(100)));
 93: 		}
 94: 
 95: 		// 未処理束の先頭からカードを1枚取り出し、最小値候補に置く
 96: 		最小値候補.最後に追加する(未処理束.カーソル位置にあるもの());
 97: 
 98: 		update();
 99: 	}
100: 
101: 	// 描画する
102: 	void ボタンが押されるまで待つ() {
103: 		do {// ステップボタンが押されるまで待つ
104: 			update();
105: 			sleep(0.025);
106: 		} while (!(stepButton.isClicked()));
107: 	}
108: 
109: }

下のボタンを押すと、このプログラムが実行できます。 ここをクリックすると、プログラムをダウンロードできます。

14.4.4.3 最小値選択法(2重ループ・ボタンあり)

このプログラムは2重ループの最小値選択法に改良を加え、 ボタンからの入力を受付け、スタート・ストップ・リセットをできるようにしたものです。

リスト 14.4.4.3.1 SelectionSort2WithButton.java
  1: /**
  2:  * プログラム名:最小値選択法(二重ループ) 
  3:  * 作成者: MegumiAraki 
  4:  * 作成日: Wed Dec 05 21:36:23 JST 2007
  5:  */
  6: public class SelectionSort2WithButton extends Turtle {
  7: 
  8: 	// 起動処理
  9: 	public static void main(String[] args) {
 10: 		Turtle.startTurtle(new SelectionSort2WithButton());
 11: 	}
 12: 
 13: 	// カードの束
 14: 	HolderTurtle 未処理束;
 15: 	HolderTurtle 最小値候補;
 16: 	HolderTurtle ソート済束;
 17: 	HolderTurtle 検索済束;
 18: 
 19: 	// ボタン
 20: 	ButtonTurtle startButton;
 21: 	ButtonTurtle resetButton;
 22: 	ButtonTurtle stopButton;
 23: 
 24: 	// プログラムの状態
 25: 	boolean チクタク = false;
 26: 
 27: 	// タートルを動かす処理
 28: 	public void start() {
 29: 		初期化する();
 30: 
 31: 		// アニメーションループ
 32: 		while (true) {
 33: 			ボタン入力の処理をする();
 34: 			最小値選択法();
 35: 			チクタク = false;
 36: 		}
 37: 	}
 38: 
 39: 	// カードを並び替える(並び替えの様子をアニメーションで表示する)
 40: 	void 最小値選択法() {
 41: 		while (true) {
 42: 			最小値候補.最後に追加する(未処理束.カーソル位置にあるもの());
 43: 			ボタン入力の処理をする();
 44: 
 45: 			do {
 46: 				if (未処理束.カーソル位置にあるものの数値() < 最小値候補.カーソル位置にあるものの数値()) {
 47: 					検索済束.最後に追加する(最小値候補.カーソル位置にあるもの());
 48: 					ボタン入力の処理をする();
 49: 					最小値候補.最後に追加する(未処理束.カーソル位置にあるもの());
 50: 					ボタン入力の処理をする();
 51: 				} else {
 52: 					検索済束.最後に追加する(未処理束.カーソル位置にあるもの());
 53: 					ボタン入力の処理をする();
 54: 				}
 55: 
 56: 			} while (未処理束.入っているものの個数() != 0);
 57: 
 58: 			ソート済束.最後に追加する(最小値候補.カーソル位置にあるもの());
 59: 			ボタン入力の処理をする();
 60: 
 61: 			if (検索済束.入っているものの個数() == 1) {
 62: 				ソート済束.最後に追加する(検索済束.カーソル位置にあるもの());
 63: 				ボタン入力の処理をする();
 64: 				break;
 65: 			} else {
 66: 				検索済束.入っている全てのものを以下の入れ物に移動する(未処理束);
 67: 				ボタン入力の処理をする();
 68: 			}
 69: 		}
 70: 
 71: 	}
 72: 
 73: 	void リセットする() {
 74: 		最小値候補.入っている全てのものを以下の入れ物に移動する(未処理束);
 75: 		検索済束.入っている全てのものを以下の入れ物に移動する(未処理束);
 76: 		ソート済束.入っている全てのものを以下の入れ物に移動する(未処理束);
 77: 
 78: 		未処理束.かきまぜる();
 79: 	}
 80: 
 81: 	void 初期化する() {
 82: 		hide();
 83: 		Turtle.window.size(550, 400);// ウインドウサイズを調節する
 84: 
 85: 		// ボタンを作る
 86: 		startButton = new ButtonTurtle("スタート");
 87: 		startButton.warp(450, 20);
 88: 
 89: 		resetButton = new ButtonTurtle("リセット");
 90: 		resetButton.warp(450, 50);
 91: 
 92: 		stopButton = new ButtonTurtle("ストップ");
 93: 		stopButton.warp(450, 80);
 94: 
 95: 		// カードの束を作る
 96: 		未処理束 = new HolderTurtle();
 97: 		未処理束.warp(50, 120);
 98: 		TextTurtle 未処理束タグ = new TextTurtle("未処理束");
 99: 		未処理束タグ.fontsize(12);
100: 		未処理束タグ.warp(50, 100);
101: 
102: 		最小値候補 = new HolderTurtle();
103: 		最小値候補.warp(50, 50);
104: 		TextTurtle 最小値候補タグ = new TextTurtle("最小値候補");
105: 		最小値候補タグ.fontsize(12);
106: 		最小値候補タグ.warp(50, 30);
107: 
108: 		ソート済束 = new HolderTurtle();
109: 		ソート済束.warp(50, 260);
110: 		TextTurtle ソート済束タグ = new TextTurtle("ソート済束");
111: 		ソート済束タグ.warp(50, 240);
112: 		ソート済束タグ.fontsize(12);
113: 
114: 		検索済束 = new HolderTurtle();
115: 		検索済束.warp(50, 190);
116: 		TextTurtle 検索済束タグ = new TextTurtle("検索済束");
117: 		検索済束タグ.fontsize(12);
118: 		検索済束タグ.warp(50, 170);
119: 
120: 		// カードを20枚作り、未処理束に入れる
121: 		for (int i = 0; i < 8; i++) {
122: 			未処理束.最後に追加する(new CardTurtle(random(100)));
123: 		}
124: 
125: 		update();
126: 	}
127: 
128: 	void ボタン入力の処理をする() {
129: 		do {
130: 			sleep(0.1);
131: 
132: 			// ボタンの入力を受け付ける
133: 			if (stopButton.isClicked()) {
134: 				チクタク = false;
135: 			}
136: 			if (resetButton.isClicked()) {
137: 				リセットする();
138: 			}
139: 			if (startButton.isClicked()) {
140: 				チクタク = true;
141: 			}
142: 
143: 			update();
144: 
145: 		} while (!チクタク);
146: 	}
147: 
148: }

下のボタンを押すと、このプログラムが実行できます。 ここをクリックすると、プログラムをダウンロードできます。

14.4.4.4 最小値選択法(2重ループ・ステップ実行)

このプログラムは、最小値選択法を1ステップごとに停止させ、 最小値選択法が実行される様子を観察できるようにしたものです。

リスト 14.4.4.4.1 SelectionSort2ByStep.java
  1: /**
  2:  * プログラム名:最小値選択法(2重ループ) 
  3:  * 作成者: MegumiAraki 
  4:  * 作成日: Wed Dec 05 21:36:23 JST 2007
  5:  */
  6: public class SelectionSort2ByStep extends Turtle {
  7: 
  8: 	// 起動処理
  9: 	public static void main(String[] args) {
 10: 		Turtle.startTurtle(new SelectionSort2ByStep());
 11: 	}
 12: 
 13: 	// カードの束
 14: 	HolderTurtle 未処理束;
 15: 	HolderTurtle 最小値候補;
 16: 	HolderTurtle ソート済束;
 17: 	HolderTurtle 検索済束;
 18: 
 19: 	// ボタン
 20: 	ButtonTurtle stepButton;
 21: 
 22: 	// タートルを動かす処理
 23: 	public void start() {
 24: 		初期化する();
 25: 		ボタンが押されるまで待つ();
 26: 
 27: 		while (true) {
 28: 			最小値候補.最後に追加する(未処理束.カーソル位置にあるもの());
 29: 			ボタンが押されるまで待つ();
 30: 
 31: 			do {
 32: 				if (未処理束.カーソル位置にあるものの数値() < 最小値候補.カーソル位置にあるものの数値()) {// (小さくなければ)
 33: 					検索済束.最後に追加する(最小値候補.カーソル位置にあるもの());
 34: 					ボタンが押されるまで待つ();
 35: 					最小値候補.最後に追加する(未処理束.カーソル位置にあるもの());
 36: 					ボタンが押されるまで待つ();
 37: 				} else {
 38: 					検索済束.最後に追加する(未処理束.カーソル位置にあるもの());
 39: 					ボタンが押されるまで待つ();
 40: 				}
 41: 			} while (未処理束.入っているものの個数() != 0);
 42: 			ソート済束.最後に追加する(最小値候補.カーソル位置にあるもの());
 43: 			ボタンが押されるまで待つ();
 44: 			if (検索済束.入っているものの個数() == 1) {
 45: 				break;
 46: 			}
 47: 			検索済束.入っている全てのものを以下の入れ物に移動する(未処理束);
 48: 			ボタンが押されるまで待つ();
 49: 		}
 50: 
 51: 		ソート済束.最後に追加する(検索済束.カーソル位置にあるもの());// 最小値候補をソート済み束に置く
 52: 		ボタンが押されるまで待つ();
 53: 	}
 54: 
 55: 	void 初期化する() {
 56: 		hide();
 57: 		Turtle.window.size(550, 400);// ウインドウサイズを調節する
 58: 
 59: 		// ボタンを作る
 60: 		stepButton = new ButtonTurtle("ステップ");
 61: 		stepButton.warp(450, 20);
 62: 
 63: 		// カードの束を作る
 64: 		未処理束 = new HolderTurtle();
 65: 		未処理束.warp(50, 120);
 66: 		TextTurtle 未処理束タグ = new TextTurtle("未処理束");
 67: 		未処理束タグ.fontsize(12);
 68: 		未処理束タグ.warp(50, 100);
 69: 
 70: 		最小値候補 = new HolderTurtle();
 71: 		最小値候補.warp(50, 50);
 72: 		TextTurtle 最小値候補タグ = new TextTurtle("最小値候補");
 73: 		最小値候補タグ.fontsize(12);
 74: 		最小値候補タグ.warp(50, 30);
 75: 
 76: 		ソート済束 = new HolderTurtle();
 77: 		ソート済束.warp(50, 260);
 78: 		TextTurtle ソート済束タグ = new TextTurtle("ソート済束");
 79: 		ソート済束タグ.fontsize(12);
 80: 		ソート済束タグ.warp(50, 240);
 81: 
 82: 		検索済束 = new HolderTurtle();
 83: 		検索済束.warp(50, 190);
 84: 		TextTurtle 検索済束タグ = new TextTurtle("検索済束");
 85: 		検索済束タグ.fontsize(12);
 86: 		検索済束タグ.warp(50, 170);
 87: 
 88: 		// カードを8枚作り、未処理束に入れる
 89: 		for (int i = 0; i < 8; i++) {
 90: 			未処理束.最後に追加する(new CardTurtle(random(100)));
 91: 		}
 92: 
 93: 		update();
 94: 	}
 95: 
 96: 	// 1ステップごとに描画する
 97: 	void ボタンが押されるまで待つ() {
 98: 		do {// ステップボタンが押されるまで待つ
 99: 			update();
100: 			sleep(0.025);
101: 		} while (!(stepButton.isClicked()));
102: 	}
103: 
104: }

下のボタンを押すと、このプログラムが実行できます。 ここをクリックすると、プログラムをダウンロードできます。

!(論理否定演算子)

!を論理否定演算子といい、真偽値を逆にする演算子です。!(true)=false、!(false)=trueとなります。 このプログラムに使われている!(StepButton.isClicked())は、 ステップボタンが押されていたら、falseを返し、押されていなかったら、trueを返します。

14.5 辞書の作成

Squeak編と同様の辞書を作ってみましょう。

14.5.1 入力タートル

辞書を作るには、タートル画面から入力を受け付ける部品が必要です。入力を受け付けるには入力タートルを使います(あわてて作ったので、ひらがなしか入力できません、すみません)。

14.5.1.1 おうむ返しプログラム(入力タートルバージョン)

このプログラムは、入力された文字をそのまま表示するプログラムです。

リスト 14.5.1.1.1 RepeatWord.java
  1: /**
  2:  * プログラム名:おうむ返しプログラム(入力タートルバージョン) 
  3:  * 作成者:MegumiAraki 
  4:  * バージョン: 1.0 (20071215)
  5:  */
  6: public class RepeatWord extends Turtle {
  7: 
  8: 	// 起動処理
  9: 	public static void main(String[] args) {
 10: 		Turtle.startTurtle(new RepeatWord());
 11: 	}
 12: 
 13: 	// タートルを動かす処理
 14: 	public void start() {
 15: 
 16: 		hide();
 17: 		// 入力ボックス
 18: 		InputTurtle input = new InputTurtle();
 19: 		input.warp(30, 30);
 20: 		// 表示用テキスト
 21: 		TextTurtle text = new TextTurtle("ここに文字が表示されます");
 22: 		text.fontsize(14);
 23: 
 24: 		while (true) {
 25: 			sleep(0.025);// 待つ
 26: 
 27: 			// エンターキーが押されたら
 28: 			if (key() == 10) {
 29: 				text.text(input.text());// 表示用テキストの内容を入力ボックスの内容に変える
 30: 				input.clearText();// 表示用テキストの内容をリセットする
 31: 			}
 32: 
 33: 			update();// 再描画する
 34: 		}
 35: 	}
 36: }

下のボタンを押すと、このプログラムが実行できます。 ここをクリックすると、プログラムをダウンロードできます。

キー入力を受けつけ、エンターキーが押されたら、おうむ返しをして、入力ボックスをリセットしています。

14.5.1.2 2つの入力タートルの制御

上記プログラムでは、入力タートルを2つ以上作った場合に、両方のタートルに文字が入力されてしまいます。 これを解決する方法を次のプログラムに示します。このプログラムは、入力タートルを2つを作り、 キー操作によってどちらの入力ボックスを使うか切り替えるプログラムです。

リスト 14.5.1.2.1 TwoInputBoxes.java
  1: /**
  2:  * プログラム名:2つの入力ボックスを切り替えるプログラム 
  3:  * 作成者:MegumiAraki 
  4:  * バージョン: 1.0 (20071215)
  5:  */
  6: public class TwoInputBoxes extends Turtle {
  7: 
  8: 	// 起動処理
  9: 	public static void main(String[] args) {
 10: 		Turtle.startTurtle(new TwoInputBoxes());
 11: 	}
 12: 
 13: 	// タートルを動かす処理
 14: 	public void start() {
 15: 
 16: 		hide();
 17: 
 18: 		// 入力ボックス1
 19: 		InputTurtle input1 = new InputTurtle();
 20: 		input1.warp(30, 30);
 21: 
 22: 		// 入力ボックス2
 23: 		InputTurtle input2 = new InputTurtle();
 24: 		input2.warp(30, 60);
 25: 		input2.setActive(false);
 26: 
 27: 		// 表示用テキスト
 28: 		TextTurtle text = new TextTurtle("ここに文字が表示されます");
 29: 		text.fontsize(10);
 30: 
 31: 		while (true) {
 32: 
 33: 			sleep(0.025);// 待つ
 34: 
 35: 			// エンターキーが押されたら
 36: 			if (key() == 10) {
 37: 				if (input1.isActive()) {
 38: 					text.text(input1.text());
 39: 					input1.clearText();
 40: 				} else if (input2.isActive()) {
 41: 					text.text(input2.text());
 42: 					input2.clearText();
 43: 				}
 44: 			}
 45: 
 46: 			// スペースキーが押されたら
 47: 			if (key() == 32) {
 48: 				if (input1.isActive()) {
 49: 					input1.setActive(false);
 50: 					input2.setActive(true);
 51: 				} else if (input2.isActive()) {
 52: 					input1.setActive(true);
 53: 					input2.setActive(false);
 54: 				}
 55: 			}
 56: 
 57: 			update();// 再描画する
 58: 		}
 59: 	}
 60: }

下のボタンを押すと、このプログラムが実行できます。 ここをクリックすると、プログラムをダウンロードできます。

スペースキーが押されたら、フォーカスを切り替えています。

14.5.1.3 入力タートルに関する新しい命令

以下に、入力タートルに関する命令の一覧を示します

入力タートルを作る命令

InputTurtle [変数名];
入力タートル型の変数を宣言します。
[(入力タートル型として宣言済みの)変数名] = new InputTurtle()
[変数名]という名前の新しい入力タートルを作ります。

入力タートルから入力を受け付ける命令

text()
入力タートルの内容を取得します
setActive([真偽値(true or false)])
入力受付状態を設定します
isActive()
入力受付状態を調べます

その他の命令

clearText()
入力タートルの内容を消去します
toJapaneseMode()
日本語入力モードにします。入力できるのはかなのみです。
toEnglishMode()
英語入力モードにします。入力できるのは小文字のみです。
fontsize()
フォントサイズを取得します
fontsize([フォントサイズの指定])
フォントサイズを指定します
やってみよう!

入力タートルを1つ用意し、スペースキーで入力モード(日本語、英語)を切り替えるプログラムを作ってみよう。

14.5.2 辞書プログラム

14.5.2.1 辞書プログラム

このプログラムは、2つの入れ物を使った辞書プログラムです。

1つの入れ物に、索引となるキーを入れ、もうひとつの入れ物にはデータを入れています。 ユーザが入力した語が、キーの入れ物にあるかどうか調べて、 あれば、キーの入れ物のカーソル位置と同じカーソル位置にあるデータを返します。

リスト 14.5.2.1.1 Dictionary.java
  1: /**
  2:  * プログラム名:辞書アプリケーション 
  3:  * 作成者:MegumiAraki
  4:  * バージョン: 1.0 (20071215)
  5:  */
  6: public class Dictionary extends Turtle {
  7: 
  8: 	// 起動処理
  9: 	public static void main(String[] args) {
 10: 		Turtle.startTurtle(new Dictionary());
 11: 	}
 12: 
 13: 	InputTurtle input;// 入力ボックス
 14: 	TextTurtle result;// 検索結果表示用テキスト
 15: 
 16: 	// 入れ物
 17: 	HolderTurtle keys;
 18: 	HolderTurtle values;
 19: 
 20: 	// タートルを動かす処理
 21: 	public void start() {
 22: 
 23: 		初期化する();
 24: 
 25: 		while (true) {
 26: 			sleep(0.025);// 待つ
 27: 
 28: 			// エンターキーが押されたら、
 29: 			if (key() == 10) {
 30: 				//検索を行い,結果を表示する
 31: 				String key = input.text();
 32: 				String value = 検索する(key);
 33: 				result.text(value);
 34: 				input.clearText();
 35: 			}
 36: 
 37: 			update();// 再描画する
 38: 		}
 39: 	}
 40: 
 41: 	// 検索する
 42: 	String 検索する(String searchKey) {
 43: 
 44: 		for (int i = 1; i <= keys.入っているものの個数(); i++) {// 1つずつ調べる
 45: 			keys.カーソル位置を変える(i);
 46: 			if (keys.カーソル位置にあるものの内容().equals(searchKey)) {// 見つかったら
 47: 				values.カーソル位置を変える(i);
 48: 				return values.カーソル位置にあるものの内容();// 検索結果を返す
 49: 			}
 50: 		}
 51: 
 52: 		// 見つからなかったら
 53: 		return "見つかりませんでした";
 54: 	}
 55: 
 56: 	void 初期化する() {
 57: 
 58: 		hide();
 59: 
 60: 		// 入力ボックス
 61: 		input = new InputTurtle();
 62: 		input.warp(30, 30);
 63: 
 64: 		// 検索結果
 65: 		result = new TextTurtle("ここに文章が表示されます");
 66: 		result.fontsize(14);
 67: 
 68: 		// 辞書の読みを入れておく入れ物
 69: 		keys = new HolderTurtle();
 70: 		keys.warp(50, 200);
 71: 		keys.最後に追加する(new CardTurtle("りんご"));
 72: 		keys.最後に追加する(new CardTurtle("いちご"));
 73: 		keys.最後に追加する(new CardTurtle("めろん"));
 74: 		keys.最後に追加する(new CardTurtle("ばなな"));
 75: 
 76: 		// 辞書の内容を入れておく入れ物
 77: 		values = new HolderTurtle();
 78: 		values.warp(50, 250);
 79: 		values.最後に追加する(new CardTurtle("apple"));
 80: 		values.最後に追加する(new CardTurtle("strawberry"));
 81: 		values.最後に追加する(new CardTurtle("melon"));
 82: 		values.最後に追加する(new CardTurtle("banana"));
 83: 
 84: 		input.toJapaneseMode();// 入力を日本語モードにする
 85: 
 86: 		update();// 再描画する
 87: 	}
 88: 
 89: }

下のボタンを押すと、このプログラムが実行できます。 ここをクリックすると、プログラムをダウンロードできます。

文字列の内容が一致しているか調べる命令

このプログラムでは文字列の内容が一致しているかどうか調べるために、equals命令を使っています。

							 46: if (key.カーソル位置にあるものの内容().equals(searchKey))
						

数値の同値性を調べるためにこれまで利用してきた==命令は、文字列の同値性を調べるためには使えません(正確には、使えます(コンパイルは通る)が、内容ではなくオブジェクトが同じかどうか比較してしまうので、誤った結果になる場合があります)。

文字列の内容が一致しているかどうか調べたいときは、A.equals(B)のように、equals命令を使う必要があります(A,Bはそれぞれ文字列型の変数)。

14.6 練習問題

14.6.1 問題1:挿入法のソートプログラムを作ろう

下の実行例を参考に、挿入法の並べ替えプログラムを作りましょう。

スタート・ストップ・リセット・ステップなどのボタンはつけなくてかまいません。

14.6.2 問題2:入れ物を使ったアプリケーションを作ろう

下の実行例を参考に、入れ物を使ったアプリケーションを作りましょう。 2つのうちのどれか1つを選んで、実装してください。

14.6.2.1 問題2-1:作文さん

このプログラムは、入れ物に名詞と動詞を保存して、作文するプログラムです。

(入れ物は、ウインドウの下のほうに隠れています。ウインドウを広げてみてください)

実装のヒント

このプログラムでは、入力ボックスをコピーし、コピーしたものを入れ物に入れています。

以下のプログラムでは、inputという入力タートルの内容をテキストタートルにコピーし、 そのテキストタートルをnounsという入れ物に入れています。

							
nouns.最後に追加する(new TextTurtle(input.text()));
							
						

このプログラムを参考に、作文さんプログラムを実装してください。

14.6.2.2 問題2-2:タイピングゲーム

このプログラムは、入れ物に絵と単語を保存して、タイピングゲームをするプログラムです。 (入れ物は、ウインドウの下のほうに隠れています。ウインドウを広げてみてください)

実装のヒント

このプログラムでは、時間を扱います。以下のプログラムは、開始時間をミリ秒で取得するプログラムです。

long型は、int型よりも桁数の大きな数字を扱える型です。

long startTime = System.currentTimeMillis();
						

以下のように、開始時間と終了時間の差(ミリ秒単位)を求め、 それを分単位に変換し、タイピング文字数をかかった時間(分)で割ることで、 タイピング速度を求めることができます。

							
long endTime = System.currentTimeMillis();
long miliTime = endTime - startTime;//かかった時間(ミリ秒)
double time = (double) miliTime / (double) 1000 / (double) 60;//かかった時間(分)
int speed = (int) (inputCharacterCount / time);
result.text("あなたのタイピング速度は" + speed + "文字/分です.");