レポート課題

Java 6 を使って作りなさい。

レポートには表紙をつけてください。

変更履歴

2010/11/4
課題1初出、プログラムの訂正
2010/11/11
課題完成
2010/11/11
Game をデフォルトパッケージにするために、各クラスにpublicが付く大幅な変更
2010/11/13
問1-4 にテストクラスを付加(夕方に変更しました)
2010/11/13
テストプログラムを添付
2010/11/14
HimawariTest.java を訂正
2010/11/15
ParametricConditionTest.java と HimawariTest.java を訂正
2010/11/16
ParametricConditionTest.java の日本語を一文字削除
2010/11/17
ParametricConditionTest.java の test2 を削除、 test3 を追加
2010/11/22
おまけの GameTest.java を差し替え、KajuConditionTest.java を訂正
2010/11/28
レポートの書き方を追加
2010/11/30
レポートの書き方を追加
2010/12/2
課題2
2010/12/2
TDUListIterator5Testを変更
2010/12/8
NodeTest訂正、TDUListIterator3Test訂正
2010/12/8
重要TDUListIterator4Test訂正、TDUListIterator5Test訂正、TDUListIteratorTest訂正

課題2

提出先: レポートボックス

レポート締切日:
4年生
2010年12月20日20:00
2,3年生
2011年1月12日20:00

4年生は冬休み中もやりとり可能なメールアドレスをレポートに記入すること(hotmail は不可です)。 また、PDF によるレポートのやりとりを行えるようにしておくこと。 冬休み中に電子メールで PDF によるレポートのやりとりができないと、合格できない場合が生じるので注意すること。

データをいくつでも入れられるリストクラス TDUList を作ります。 パッケージは tdu とし、外部クラスからでも使用できるようにしなさい。 なお、各メソッドの細かい仕様はこちらが特に指定する以外は、Java6 の API マニュアルに準拠します。

各設問に付されているテストに関しては結果をレポートに添付すること。

問2-1

どんなオブジェクトでも一つ入れられるノードクラス Node<E> を作成します。 線形リストに使用するため、内部に Node<E> 型の変数 next を protected で持たせます。 作成すべきメソッドは次の通りです。

  1. 引数なしのコンストラクタ(オブジェクトも next も null が入る)
  2. オブジェクトを引数とするコンストラクタ(next には null が入る)
  3. E get() オブジェクトを取り出す
  4. void set(E arg) オブジェクトの上書き
  5. String toString() オブジェクトの文字列化

テスト(12/8 更新しました)を使用して下さい。

問2-2

TDUList は Node オブジェクトの連続を内部に格納し、様々な操作を行うよう に作成することを目標とします。 下記のクラス tdu.TDUList1 はもっとも基本的な雛形です。 この、node メンバ変数は Node オブジェクトの連続を格納するためのメンバ 変数です。 但し、常に連続の最後のオブジェクトは空の Node オブジェクトを持つことと します。 この TDUList1 を継承し、Node オブジェクトの連続の数を数える size メソッ ドを実装したクラス tdu.TDUList2 を作成しなさい。 但し、空の Node オブジェクトだけの時は 0 を返し、値の入った Node オブ ジェクトが k 個連続したのちに空の Node オブジェクトがつながっている場 合は k を出力するようにしなさい。 また、これもテストを活用しなさい。

なお、アルゴリズムの説明をする際は、データ例を図示し、何を数えているか と終了条件に印を付けなさい。

TDUList1


package tdu;
import java.util.AbstractSequentialList;
import java.util.ListIterator;
public class TDUList1 extends AbstractSequentialList<String> {
	public TDUList1(){
		super();
		node=new Node<String>();
	}
	protected Node<String> node;
	@Override
	public ListIterator<String> listIterator(int arg0) {
		return null;
	}
	@Override
	public int size() {
		return 0;
	}
}

問2-3

tdu.TDUList3 を下記のようにします。 このクラスが機能するように tdu.TDUListIterator3 クラスを作成し、 Node<String> と int の値を引数に持つコンストラクタと String オブ ジェクトを引数にする add メソッドを実装しなさい。 但し、このコンストラクタの int の値の意味は、java.util.ListIterator の APIマニュアルの通りで、与えられた int の値にカーソルをセットします。 そして、 add メソッドでカーソルの位置に要素を追加しなさい。 これに対しては、 TDUList3Testと TDUListIterator3Test(12/8 更新しました) を活用しなさい。

なお、java.util.ListIterator には多くのメソッドが登録されてますが、add メソッド以外は、(1) Java の API のマニュアルで UnsupportedOperationException を throw するように指定されているものは そのように、(2)その他は無条件でなにもしないようにしてください。 値を返すメソッドに対しては、必要に応じて 0, false, null のいずれかを返 すようにしてください。

この add メソッドはどのようにデータが加わっていくかを図示してください。 また、 TDUListIterator3 の add メソッドと、 TDUList3 の add メソッドの 関わりについて考察しなさい。

TDUList3


package tdu;
import java.util.ListIterator;
public class TDUList3 extends TDUList2 {
        public TDUList3(){
                super();
        }
	public ListIterator<String> listIterator(int arg0){
		return new TDUListIterator3(node,arg0);
	}
}

問2-4

tdu.TDUList4 を下記のようにします。 この時、TDUListIterator3 を継承し、 public String next() と public boolean hasNext() メソッドを 実装したクラス TDUListIterator4 を作成しなさい。 これに対しては、 TDUList4Test(12/8 更新しました) を 活用しなさい。

TDUList4


package tdu;
import java.util.ListIterator;
public class TDUList4 extends TDUList3 {
	public TDUList4() {
		super();
	}
	@Override
	public ListIterator<String> listIterator(int arg){
		return new TDUListIterator4(node,arg);
	}
}

問2-5

TDUList5 を下記のようにします。 このとき、 TDUListItrator4 を継承し、set メソッドを実装したクラス TDUListIterator5 を作成しなさい。 これに対しては、 TDUList5TestとTDUListIterator5Test(12/8 更新しました) を 活用しなさい。 なお、親メソッドと同等のことをやろうとする場合において、プログラムのコピーを避 けてください。

TDUList5


package tdu;
import java.util.ListIterator;
public class TDUList5 extends TDUList4 {
	public TDUList5() {
		super();
	}
	@Override
	public ListIterator<String> listIterator(int arg){
		return new TDUListIterator5(node,arg);
	}
}

問2-6

  1. 以上をまとめ、Generics を使用し、任意のオブジェクトを格納できるリスト クラス TDUList<E> と TDUListIterator<E> を作成しなさい。 なお、テストとしてTDUListTest と TDUListIteratorTest(12/8 変更しました)を活用しなさい。
  2. 次に、次の Main プログラムを様々な引数で10回ずつ程度動作させ、両対数グ ラフで tdu.TDUList と java.util.LinkedList のそれぞれの各部分の実行時間の比較をしなさい。 但し、一回の実行時間が5分を越えるような計測は避けてください。
  3. 作成したメソッドがどのように呼び出されるかを分析し、アルゴリズムのどこ に問題があるのかを指摘しなさい。 さらに、改善方法のアイディアを述べなさい。

Main


import java.util.*;
class Main {
	@SuppressWarnings("unchecked")
	public static void main(String[] args) {	
		List<Integer>[] list = (List<Integer>[]) new List[]{ new tdu.TDUList<Integer>(),
				new LinkedList<Integer>()};
		int index = Integer.parseInt(args[0]);
		int max=Integer.parseInt(args[1]);
		StopWatch sw = new StopWatch();	
		for(int i=0;i<max;i++){
			list[index].add(new Integer((int) (Math.random()*1000)));
		}
		System.out.println(sw);
		for(int i=0;i<100;i++){
			list[index].set((int) (Math.random()*max),new Integer((int) (Math.random()*1000)));
		}
		System.out.println(sw);
		double average=0;
		for(Integer i : list[index]){
			average+=i;
		}
		average/=max;
		System.out.println(average);
		System.out.println(sw);
	}
}

StopWatch


import java.util.Date;
public class StopWatch {
	private Date now;
	public StopWatch() {
		now = new Date();
	}
	@Override
	public String toString() {
		final Date next = new Date();
		double result = (double)( next.getTime()-now.getTime())/1000;
		now = next;
		return String.valueOf(result);
	}
	
}

指導可能時間

12/19現在の指導可能な時間を示します。 なるべく電子メールで予約して来てほしいですが、一応、来訪時に余裕があったら指導します。 また、下記はあくまでも予定ですので、突然予定が変ることもあります。 常に最新の情報を参考にしてください。 なお、本講義の副手は3人ともネットワークシステム研究室に所属しています。 レポート返却後は担当副手が決まりますので、担当副手に指導を受けて下さい。 なお、坂本と副手への一括連絡用のメールアドレス algo1@net.c.dendai.ac.jp を用意しましたので御活用下さい。

なお、漢字と同じ幅のローマ数字や丸数字は電子メールで使用できません。 この講義名をメールで書く際は漢字と同じ幅の文字を使用せずに、必ず英字に 切り替えて「データ構造とアルゴリズムI」と表記してください。

12/10
17:00〜20:30
13
×
14
4年レポート返却日
15
17:00頃から21:00
16
×
17
×
20
×
21
13:10〜14:40
22
14:00〜16:00
24
×
1/6
×
7
17:10〜19:00
10
×
11
13:10〜21:00
12
17:00〜20:00

課題1

レポート締切日: 2010年12月1日20:00

提出先: レポートボックス

作物を畑で育成すゲーム(ソースコード)を 考えます。 3 つの畑に作物を植えて、成長させます。

操作はコマンドラインから行います。

list
種のリストを表示します
put 位置 種
指定の畑に種を蒔きます
age
成長させます

なお、この課題は既ににちゃんねるに質問され、解答が提示されています。 同じ問題を何度も質問することは掲示板のマナー違反になりますので、御控え下さい。

問1-1

種の名前 orange で「オレンジ」を栽培できるようにしなさい。 但し、こちらで提供したプログラムは一切変更してはいけません。 その代わり、新たなクラス Main1 を定義して下さい。

Main1.java


import garden.*;
import java.util.*;
class Main1 {
    public static void main(String[] arg){
	final Game g = new Game1(3,new Scanner(System.in));
	g.run();
    }
}

ヒント

Orange クラスは Kaju を継承して作成します。 上記にあるように Game1 は Game を継承したサブクラスとして作成します。 他にも必要に応じて他のクラスも継承します。

プロトタイプデザインパターンを使っています。

実行例
0: null, 1: null, 2: null
list
[orange, apple]
0: null, 1: null, 2: null
put 0 orange
0: オレンジは種, 1: null, 2: null
age
0: オレンジは育ってます, 1: null, 2: null
age
0: オレンジは花が咲きました, 1: null, 2: null
age
0: オレンジは実がなりました, 1: null, 2: null
age
0: オレンジは葉が散りました, 1: null, 2: null
age
0: オレンジは葉が繁りました, 1: null, 2: null
age
0: オレンジは花が咲きました, 1: null, 2: null
age
0: オレンジは実がなりました, 1: null, 2: null
age
0: オレンジは枯れました, 1: null, 2: null
age
0: null, 1: null, 2: null
end

問1-2

畑の数を増やす extend 命令を追加したクラス Game2 を作って下さい。 但し、そのために Hatake クラスに extend メソッドを追加して下さい (他の部分を変更してはいけません)。

Main2.java


import garden.*;
import java.util.*;
class Main2 {
    public static void main(String[] arg){
	final Game g = new Game2(3,new Scanner(System.in));
	g.run();
    }
}
ヒント

ストラテジデザインパターンを使っています

実行例

0: null, 1: null, 2: null
help
使い方: コマンド [引数]
put: 位置 作物名 : 作物を指定の位置に植える
extend: 畑を拡張する
age: 一日経過させる
list: 作物一覧
end : 終了
0: null, 1: null, 2: null
list
[orange, apple]
0: null, 1: null, 2: null
extend
0: null, 1: null, 2: null, 3: null
put 3 orange
0: null, 1: null, 2: null, 3: オレンジは種
put 4 apple
java.lang.ArrayIndexOutOfBoundsException: 4
0: null, 1: null, 2: null, 3: オレンジは種
extend
0: null, 1: null, 2: null, 3: オレンジは種, 4: null
put 4 apple
0: null, 1: null, 2: null, 3: オレンジは種, 4: りんごは種
age
0: null, 1: null, 2: null, 3: オレンジは育ってます, 4: りんごは育ってます
end

問1-3

新たな作物として、種の名前 strawberry で 「いちご」を栽培できるように したクラス Game3 を作成しなさい。 但し、生育パターンは"種","育ってます","花が咲きました","実がなりました","枯れました" になるようにしなさい。 既存のクラスを変更してはいけません。また、新たに作成したクラスは全て報 告して下さい。

Main3.java


import garden.*;
import java.util.*;
class Main3 {
    public static void main(String[] arg){
	final Game g = new Game3(3,new Scanner(System.in));
	g.run();
    }
}
ヒント

テンプレートメソッドデザインパターンを使用しています。

実行例

0: null, 1: null, 2: null
list
[orange, apple, strawberry]
0: null, 1: null, 2: null
put 0 strawberry
0: いちごは種, 1: null, 2: null
put 1 orange
0: いちごは種, 1: オレンジは種, 2: null
put 2 apple
0: いちごは種, 1: オレンジは種, 2: りんごは種
age
0: いちごは育ってます, 1: オレンジは育ってます, 2: りんごは育ってます
age
0: いちごは花が咲きました, 1: オレンジは花が咲きました, 2: りんごは花が咲きました
age
0: いちごは実がなりました, 1: オレンジは実がなりました, 2: りんごは実がなりました
age
0: いちごは枯れました, 1: オレンジは葉が散りました, 2: りんごは葉が散りました
age
0: null, 1: オレンジは葉が繁りました, 2: りんごは葉が繁りました
age
0: null, 1: オレンジは花が咲きました, 2: りんごは花が咲きました
age
0: null, 1: オレンジは実がなりました, 2: りんごは実がなりました
age
0: null, 1: オレンジは枯れました, 2: りんごは枯れました
age
0: null, 1: null, 2: null
end

問1-4

育つ期間、花の咲いている期間、実のなっている期間をそれぞれ int の配列として コンストラクタの引数に与えられる ParametricCondition クラスを作りなさい。 そして、このクラスを使用して、次の作物を植えられるようにしなさい。

作物育つ期間花の期間実がなる期間
トマト114
あさがお241
ひまわり312

(花の時期などは実物とは無関係です)

Main4.java


import garden.*;
import java.util.*;
class Main4 {
    public static void main(String[] arg){
	final Game g = new Game4(3,new Scanner(System.in));
	g.run();
    }
}

実行例

0: null, 1: null, 2: null
list
[orange, himawari, tomato, asagao, apple, strawberry]
0: null, 1: null, 2: null
put 0 himawari
0: ひまわりは種, 1: null, 2: null
put 1 asagao
0: ひまわりは種, 1: あさがおは種, 2: null
put 2 tomato
0: ひまわりは種, 1: あさがおは種, 2: トマトは種
age
0: ひまわりは育ってます, 1: あさがおは育ってます, 2: トマトは育ってます
age
0: ひまわりは育ってます, 1: あさがおは育ってます, 2: トマトは花が咲きました
age
0: ひまわりは育ってます, 1: あさがおは花が咲きました, 2: トマトは実がなりました
age
0: ひまわりは花が咲きました, 1: あさがおは花が咲きました, 2: トマトは実がなりました
age
0: ひまわりは実がなりました, 1: あさがおは花が咲きました, 2: トマトは実がなりました
age
0: ひまわりは実がなりました,  1: あさがおは花が咲きました, 2: トマトは実がなりました
age
0: ひまわりは枯れました, 1: あさがおは実がなりました, 2: トマトは枯れました
age
0: null, 1: あさがおは枯れました, 2: null
age
0: null, 1: null, 2: null
end

garden/ParametricConditionTest.java

以下は、 garden パッケージアイコンを右クリックして、「new」→「J Unit Test Case」を選択してください。 そして、「New JUnit 4 Case」を選択し、Name に ParametricConditionTest を入れてください。 そして、「Perform the following action: Add JUnit4 library to the build path」の表示が出たら Ok を選択してください。 その後で、エディタの内容を以下に取り替えてください。


package garden;
import static org.junit.Assert.*;
import org.junit.Test;
public class ParametricConditionTest {
	@Test
	public void test1() {
		Condition condition = new ParametricCondition(new int[]{1,1,1});
		assertEquals("種",condition.get(0));
		assertFalse(condition.isOverage(0));
		assertEquals("育ってます",condition.get(1)); //11/16 訂正
		assertFalse(condition.isOverage(1));
		assertEquals("花が咲きました",condition.get(2));
		assertFalse(condition.isOverage(2));
		assertEquals("実がなりました",condition.get(3));
		assertFalse(condition.isOverage(3));
		assertEquals("枯れました",condition.get(4));		
		assertFalse(condition.isOverage(4));
		assertTrue(condition.isOverage(5));
	}
	@Test
	public void test2() {
		Condition condition = new ParametricCondition(new int[]{2,1,3});
		assertEquals("種",condition.get(0));
		assertFalse(condition.isOverage(0));
		assertEquals("育ってます",condition.get(1)); //11/16 訂正
		assertFalse(condition.isOverage(1));
		assertEquals("育ってます",condition.get(2)); //11/16 訂正
		assertFalse(condition.isOverage(2));
		assertEquals("花が咲きました",condition.get(3));
		assertFalse(condition.isOverage(3));
		assertEquals("実がなりました",condition.get(4));
		assertFalse(condition.isOverage(4));
		assertEquals("実がなりました",condition.get(5));
		assertFalse(condition.isOverage(5));
		assertEquals("実がなりました",condition.get(6));
		assertFalse(condition.isOverage(6));
		assertEquals("枯れました",condition.get(7));		
		assertFalse(condition.isOverage(7));
		assertTrue(condition.isOverage(8));
	}
	@Test
	public void test3() {
		Condition condition = new ParametricCondition(new int[]{2,3,4});
		assertEquals("種",condition.get(0));
		assertFalse(condition.isOverage(0));
		assertEquals("育ってます",condition.get(1));
		assertFalse(condition.isOverage(1));
		assertEquals("育ってます",condition.get(2));
		assertFalse(condition.isOverage(2));
		assertEquals("花が咲きました",condition.get(3));
		assertFalse(condition.isOverage(3));
		assertEquals("花が咲きました",condition.get(4));
		assertFalse(condition.isOverage(4));
		assertEquals("花が咲きました",condition.get(5));
		assertFalse(condition.isOverage(5));
		assertEquals("実がなりました",condition.get(6));
		assertFalse(condition.isOverage(6));
		assertEquals("実がなりました",condition.get(7));
		assertFalse(condition.isOverage(7));
		assertEquals("実がなりました",condition.get(8));
		assertFalse(condition.isOverage(8));
		assertEquals("実がなりました",condition.get(9));
		assertFalse(condition.isOverage(9));
		assertEquals("枯れました",condition.get(10));
		assertFalse(condition.isOverage(10));
		assertTrue(condition.isOverage(11));
	}
}

garden/HimawariTest.java

以下は、 garden パッケージアイコンを右クリックして、「new」→「JUnit Test Case」を選択してください。 そして、「New JUnit 4 Case」を選択し、Name に HimawariTest を入れてください。 そして、「Perform the following action: Add JUnit4 library to the build path」の表示が出たら Ok を選択してください。 その後で、エディタの内容を以下に取り替えてください。


package garden;
import static org.junit.Assert.*;
import org.junit.Before;
import org.junit.Test;
public class HimawariTest {
  private Sakumotsu himawari;
  @Before
  public void setUp() throws Exception {
    himawari = new Himawari();
  }
  @Test
  public void testGetCondition() {
    assertEquals("garden.ParametricCondition",himawari.getCondition().getClass().getName());
  }
  @Test
  public void testToString() {
    assertEquals("ひまわりは種",himawari.toString());
  }
}

おまけ

課題1のテストコード

課題1のレポートの書き方

採点基準

  1. 問題をちゃんと理解すること。 特に解答が楽になるようにとか、「わかりやすく」とか「しっかり」など、非 科学的な理由で勝手に問題を作り替えてはいけません。
  2. プログラムが正常に動作すること。 指定した出力を正確に出すこと。 また、指定していない表示を行わないこと。 さらに、多少の動作条件の変化に対して、正常に対応できること。 特に、テストに対しては正常に動作しても、考えうる他の正常な入力に対して暴走するようなプログラムは不可です。
  3. 実行例を付けること。 実行可能なプログラムに関して、正しく実行された実行例を必ずつけること。 なお、問題の趣旨を理解しており、膨大な出力のうち、全ての出力が必ずしも 必要ないと判断される場合は、出力の一部を省略しても良い。
  4. 説明が適切であること。 プログラムの内容を正しく説明していなければなりません。 また、テストの内容を理解し、テスト結果からプログラムが正常であることを 理由を付けて判定すること。

レポート作成上の注意点

  1. 表紙をつけてください。 また、再提出時は前回の表紙をつけてください。
  2. プログラミングのレポートでは必ずプログラムの説明をすること。 その時に、一行一行を日本語に直訳するのではなく、データの読み込みとか、 出力とかの部分に分割し、機能毎に使用した手法を説明すること。 プログラム中にコメントを入れてもプログラムの説明とはみなさないので注意 する事。 プログラムの説明ではつぎのように説明をしてください。
    1. プログラム全体の構成
    2. 各部分の機能
    3. それぞれの機能を実現するために行ったプログラミング上の工夫
  3. 「問題を解きなさい」という問に対して「解きました。合ってました」で は正解ではないことはわかるはず。 「テストしなさい」という問に対しては、テストの方法の説明、実際のテスト の実施方法、テスト結果、検証などを説明して下さい。
  4. レポートは手書きでもワープロでも構いません。但し、実行結果はコン ピュータの出力を添付すること。 また、なるべく白黒で作成すること。実行結果などでどうしても色が付いてしまうような場合はそのままで構いません。 実行結果が無いレポートは不合格です。
  5. 考察は必ず書いて下さい。
  6. 不必要なことはなるべく書かない事。 長過ぎるレポートは減点します。またなるべく両面印刷にしてください。 但し、文字は必要以上に小さくしない事。レポート本文の文字は 10 ポイント 以上のものを使う事。

なお、写したと思われるほど酷似したレポートが複数提出された場合、原著が どれかの調査を行わず、抽選で一通のレポートのみを評価 の対象とし、他は提出済みの不合格レポートとして再提出は課しません。 自分で意図せずに他人にコピーされてしまった場合も同様ですので、レポート の取り扱いについては十分に注意して下さい。


坂本直志 <sakamoto@c.dendai.ac.jp>
東京電機大学工学部情報通信工学科