Java 7 または Java 6 を使って作りなさい。
レポートには表紙をつけてください。
提出先: レポートボックス
データをいくつでも入れられるリストクラス TDUList を作ります。 なお、各メソッドの細かい仕様はこちらが特に指定する以外は、Java7 または Java 6 の API マニュアルに準拠します。
各設問に付されているテストに関しては結果をレポートに添付すること。
なお、テストクラスを用意したので、各設問 において、指示のあるテストクラスを用いてテストを行い、正常であった旨を 報告しなさい。
なお、この課題も 課題ファイル集(9月20日版) を用意した。 インストール方法は課題1と同様である。
どんなオブジェクトでも一つ入れられるノードクラス kotae.Node<E> を作成しなさい。 線形リストに使用するため、内部に Node<E> 型の変数 next を public で持たせます。 作成すべきメソッドは次の通りです。
なお、test.NodeTest を使用して、正常であるかどうかを確かめること。
TDUList は Node オブジェクトの線形リストを内部に格納し、様々な操作を行 えるようにすることを目標とします。 以下の課題ではまず、文字列を入れられる線形リストのライブラリを作成し、 最終的に Generics を使用してどのようなオブジェクトも入れられるように改 良します。
さて、下記のクラス kadai.TDUList1 と kadai.TDUListIterator1はもっとも 基本的な雛形です。 TDUList1 において node メンバ変数は Node オブジェクトの線形リストの先 頭のオブジェクトを参照するためのメンバ変数です。 なお、常に線形リストの最後のオブジェクトは空の Node オブジェクトを持つ こととします。 この TDUList1 を継承し、Node オブジェクトの線形リストの要素数を数える size メソッドを実装したクラス kotae.TDUList2 を作成しなさい。 但し、空の Node オブジェクトだけの時は 0 を返し、値の入った Node オブ ジェクトが k 個連続したのちに空の Node オブジェクトがつながっている場 合は k を出力するようにしなさい。
なお、アルゴリズムの説明をする際は、データ例を図示し、数えている対象と 終了条件がわかるように印を付けなさい。 なお、 test.TDUList2Test を利用し、テスト結果も示すこと。
package kadai;
import java.util.AbstractSequentialList;
import java.util.ListIterator;
import kotae.Node;
public class TDUList1 extends AbstractSequentialList<String> {
public Node<String> node;
public TDUList1(){
super();
node = new Node<String>();
}
@Override
public ListIterator<String> listIterator(int arg) {
return new TDUListIterator1(node,arg);
}
@Override
public int size() {
return 0;
}
}
package kadai;
import java.util.ListIterator;
import java.util.NoSuchElementException;
import kotae.Node;
public class TDUListIterator1 implements ListIterator<String> {
public TDUListIterator1(Node<String> node, int arg) {
}
@Override
public void add(String e) {
throw new UnsupportedOperationException();
}
@Override
public boolean hasNext() {
return false;
}
@Override
public boolean hasPrevious() {
return false;
}
@Override
public String next() {
throw new NoSuchElementException();
}
@Override
public int nextIndex() {
return 0;
}
@Override
public String previous() {
throw new NoSuchElementException();
}
@Override
public int previousIndex() {
return -1;
}
@Override
public void remove() {
throw new UnsupportedOperationException();
}
@Override
public void set(String e) {
throw new UnsupportedOperationException();
}
}
kadai.TDUList3 を下記のようにします。 このクラスが機能するように kadai.TDUListIterator1 クラスを継承した kotae.TDUListIterator3 クラスを作成し、kotae.Node<String> と int の値 を引数に持つコンストラクタと String オブジェクトを引数にする add メソッ ドを実装しなさい。 但し、このコンストラクタの int の値の意味は、java.util.ListIterator の APIマニュアルの通りで、与えられた int の値にカーソルをセットします。 そして、 add メソッドでカーソルの位置に要素を追加しなさい。 これに対して test.TDUList3Testとtest.TDUListIterator3Test を活用しなさい。
この add メソッドはどのようにデータが加わっていくかを図示してください。 また、 TDUListIterator3 の add メソッドと、 TDUList3 の add メソッドの 関わりについて考察しなさい。
package kadai;
import java.util.ListIterator;
import kotae.TDUList2;
import kotae.TDUListIterator3;
public class TDUList3 extends TDUList2 {
public TDUList3(){
super();
}
public ListIterator<String> listIterator(int arg0){
return new TDUListIterator3(node,arg0);
}
}
kadai.TDUList4 を下記のようにします。 この時、kotae.TDUListIterator3 を継承し、 public String next() と public boolean hasNext() メソッドを 実装したクラス kotae.TDUListIterator4 を作成しなさい。 これに対しては、 test.TDUList4Testと test.TDUListIterator4Test を 活用しなさい。
package kadai;
import java.util.ListIterator;
import kotae.TDUListIterator4;
public class TDUList4 extends TDUList3 {
public TDUList4() {
super();
}
@Override
public ListIterator<String> listIterator(int arg){
return new TDUListIterator4(node,arg);
}
}
kadai.TDUList5 を下記のようにします。 このとき、 kotae.TDUListItrator4 を継承し、set メソッドを実装したクラス kotae.TDUListIterator5 を作成しなさい。 これに対しては、 test.TDUList5Testとtest.TDUListIterator5Testを活用し なさい。 なお、親メソッドと同等のことをやろうとする場合において、プログラムのコ ピーを避けてください。
package kadai;
import java.util.ListIterator;
import kotae.TDUListIterator5;
public class TDUList5 extends TDUList4 {
public TDUList5() {
super();
}
@Override
public ListIterator<String>> listIterator(int arg){
return new TDUListIterator5(node,arg);
}
}
package kadai;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
class Keisoku {
public static void main(String[] args) {
switch((int) (Math.random()*3)){
case 0: test(new kotae.TDUList<Integer>());
break;
case 1: test(new LinkedList<Integer>());
break;
case 2: test(new ArrayList<Integer>());
break;
}
}
private static void test( List<Integer> list) {
int max=10000;
StopWatch sw = new StopWatch();
for(int i=0;i<max;i++){
list.add(new Integer((int) (Math.random()*1000)));
}
System.out.println(sw);
for(int i=0;i<100;i++){
list.set((int) (Math.random()*max),new Integer((int) (Math.random()*1000)));
}
System.out.println(sw);
double average=0;
for(Integer i : list){
average+=i;
}
average/=max;
System.out.println(sw);
System.out.println(average);
System.out.println(list.getClass().getName());
}
}
package kadai;
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);
}
}
提出先: 2号館レポートボックス
じゃんけんを行うことを考えます。 プレイヤー二人が対戦をするのですが、それぞれが戦略を考えて手を出します。
以下の設問において kotae パッケージを作り、 その中に指定されたクラスを作成しなさい。
なお、テストクラスを用意したので、各設問 において、指示のあるテストクラスを用いてテストを行い、正常であった旨を 報告しなさい。
始めに、「手」を表現するクラスを作ります。 interface Hand を下記のように定義します。
package kadai;
public interface Hand {
int wins(Hand hand);
int getNum();
}
作成する kotae/MyHand クラスは、 コンストラクタにint型の値を入れると、getNum() でその値が取り出せるとします。 手は「Yasumi」「Gu」「Choki」「Pa」の4種類とし、この順に 0,1,2,3 と対 応するとします。 また、 toString() をオーバライドし、上記の Yasumi, Gu, Choki, Pa を文 字列として取り出せるとします。 さらに、 equals(Object) は同じ手ではtrue となるようにオーバライドし、 hashCode() は同じ手で同じ値が出るようにオーバライドします。
wins メソッドは引数の手に対して、勝ちなら 1, あいこなら 0, 負けなら -1 を返すように実装します。 Yasumi の時は、相手が Yasumi 以外なら負けで、 Yasumi ならあいことしま す。
Yasumi | Gu | Choki | Pa | |
---|---|---|---|---|
Yasumi | 0 | -1 | -1 | -1 |
Gu | 1 | 0 | 1 | -1 |
Choki | 1 | -1 | 0 | 1 |
Pa | 1 | 1 | -1 | 0 |
なおテストには test/MyHandTest.java を使用してください。
作成した MyHand クラスに対して、手を出すことを抽象化します。 kadai.HandBuilder は getHand に0から 3 を指定すると、対応するHand のオブジェク トを返すためのインタフェースです。 これを素朴に実装したのが kadai.HandBuilder1 で、これは単純に毎回 MyHand オブジェクトをコンストラクタを使用して生成します。
package kadai;
public interface HandBuilder {
Hand getHand(int type);
}
package kadai;
import kotae.MyHand;
public class HandBuilder1 implements HandBuilder {
public HandBuilder1(){}
@Override
public Hand getHand(int type) {
return new MyHand(type);
}
}
さて、毎回コンストラクタを使用せず、getHand で同じ手では同じオブジェク トを返す kotae.HandBuilder2 を作りなさい。
なお、これらをテストするクラス test.HandBuilder2Test を使用しなさい。
次に、手を出す戦略のクラスを作ります。 kadai/Tactics インタフェースは getHand メソッドがありますが、引数はあ りません。 getHand では戦略にしたがった手が得られます。 ただし、コンストラクタは HandBuilder を得て、手はこの HandBuilder 経由 で出します。
package kadai;
public interface Tactics {
Hand getHand();
}
さて、このような前提で、次の戦略を実現する kotae.Tactics1, kotae.Tactics2 クラスを作りなさい。
なお、これらをテストするクラス test.Tactics1, test.Tactics2 を使用しな さい。
なお、計算がオーバフローする可能性のあるプログラムは不可とする。
kadai.Janken は、二つの Player オブジェクトを与えて、 pon メソッ ドでじゃんけんをさせるクラスである。 この Player クラスは、コンストラクタで名前を受け取り、さらに setTactics メソッドで Tactics を一つ持つことができる。 さて、Janken 中の pon メソッドでは、Player オブジェクトに対して getHand メソッドで手を出させ、勝敗を判定し、Player オブジェクトに対し て win, loose, draw メソッドで勝負の結果を与える。
Player オブジェクトはさらに toString メソッドをオーバライドしていて、 次のフォーマットで勝敗を文字列として出力する。
名前":\t"勝数" wins, "負け数" looses and "引分数" draws."
次の kadai.Janken を上記のように動作させるように kotae.Player クラス を作成しなさい。
package kadai;
import kotae.Player;
public class Janken {
private Player[] players;
public Janken(Player player0, Player player1){
players = new Player[2];
players[0] = player0;
players[1] = player1;
}
public Hand[] pon(){
Hand[] hands = new Hand[2];
for(int i=0; i<2; i++){
hands[i] = players[i].getHand();
}
switch(hands[0].wins(hands[1])){
case 0:
players[0].draw();
players[1].draw();
break;
case 1:
players[0].win();
players[1].loose();
break;
case -1:
players[0].loose();
players[1].win();
break;
}
return hands;
}
}
omake.Nichiyou を実行すると、ランダムで HandBuilder1 と HandBuilder2 から一つを選んで二人の Player を100万回勝負をさせ、 その実行結果と実行時間を表示する。 これを HandBuilder1 と HandBuilder2 で 10 回ずつ計測し、平均値を比較し なさい。 さらに、この実行時間が異なる理由を説明しなさい。
package omake;
import java.util.ArrayList;
import kadai.Hand;
import kadai.HandBuilder;
import kadai.HandBuilder1;
import kadai.Janken;
import kotae.HandBuilder2;
import kotae.Player;
import kotae.Tactics1;
import kotae.Tactics2;
public class Nichiyou {
public static void main(String[] args) {
HandBuilder[] hb = {new HandBuilder1(), new HandBuilder2()};
taisen(hb[(int) (Math.random()*hb.length)]);
}
private static void taisen(HandBuilder hb) {
StopWatch sw = new StopWatch();
Player curepiece = new Player("CurePiece");
curepiece.setTactics(new Tactics1(hb));
Player sazae = new Player("Sazae");
sazae.setTactics(new Tactics2(hb));
Janken nichiyou = new Janken(curepiece, sazae);
ArrayList<Hand[]> kekka = new ArrayList<Hand[]>();
for(int i=0; i<1000000; i++){
kekka.add(nichiyou.pon());
}
System.out.println(sw);
System.out.println(hb.getClass().getName());
System.out.println(curepiece);
System.out.println(sazae);
}
}
課題1-5の計測が完了するまでに実行する回数の平均値を理論的に求めなさい。
Eclipse のセッティングの方法
なお、問題訂正などでプログラムが変更になった場合、上記の最新のファイル 集をダウンロードした後で、作業中のプロジェクトでもう一度importして下さ い。 上書きするファイルが検出されるとダイアログが表示されますが、 Yes ALL で問題だけ最新の状態になるはずです。
なお、写したと思われるほど酷似したレポートが複数提出された場合、原著が どれかの調査を行わず、抽選で一通のレポートのみを評価 の対象とし、他は提出済みの不合格レポートとして再提出は課しません。 自分で意図せずに他人にコピーされてしまった場合も同様ですので、レポート の取り扱いについては十分に注意して下さい。