課題1801
直角柱を表すクラス Prism をパッケージ j2.lesson05 に作成しなさい。
直角柱とは三角柱や直方体などの多角形を底面に持ち (底面と平行で合同である面をもう一つ持つ)、全ての側面が長方形で構成されているような立体である。
このクラスに次のようなインスタンスフィールドを用意すること。また、private, final として指定すること。
- 底面を表す Polygon base
- 高さを表す double height
また、次のようなコンストラクタを用意すること。これは public として指定すること。
- public Prism(Polygon base, double height)
- 底面と高さを指定して、直角柱を作成する。
- base - この直角柱の底面
- height - この直角柱の高さ
また、次のようなインスタンスメソッドを用意すること。これらは public として指定すること。
- public double volume()
- この直角柱の体積を計算する。直角柱の体積は、底面積 * 高さで計算できる。
- 戻り値: この直角柱の体積
- public double surfaceArea()
- この直角柱の表面積を計算する。 直角柱の表面積は、底面積 * 2 + 底面の各辺の長さ * 高さ で計算できる
- 戻り値: この直角柱の表面積
- public String toString()
- この直角柱の文字列表現を取得する。文字列の形式は "Prism(" + base + "," + height + ")"
- 戻り値: この直角柱の文字列表現
上記に記載されていないインスタンスフィールド、インスタンスメソッド、クラスメソッド、コンストラクタは必要ならば自由に用意して構わない。
手順
指定した箇所で必ずテストを行うこと。
- 各メソッドに対する詳細な擬似コードを作成する
- パッケージ j2.lesson05 にクラス Prism を作成
- 指定したインスタンスメソッドやコンストラクタを作成する
- テスト項目「Prismに対する骨格テスト」をパス
- インスタンスメソッドやコンストラクタの中身を書く (演習と同様)
- main メソッドを書いて簡単なテストを行う
- JUnit を用いてもよい
- テスト項目「Prismに対する単体テスト」をパス
テストの失敗メッセージ
骨格テスト
| メッセージ | 詳細 |
|---|---|
| (クラス名), existence | パッケージ内に課題で指定したクラスが存在していない。パッケージやクラス名を確認 |
| (クラス名), extends <C> | クラスを作る際に継承するクラスが間違っている。正しくは <C> |
| (メンバ名), existence | 指定されたメンバが存在しない |
| (メンバ名), public | メンバを作る際に public の指定がない |
| (メンバ名), private | メンバを作る際に private の指定がない |
| (メンバ名), final | メンバを作る際に final の指定がない |
| (メンバ名), not static | メンバを作る際に static が余計についている |
| (メンバ名), type <T> | メンバを作る際に型の指定を間違っている。正しくは <T> |
単体テスト
| メッセージ | 詳細 |
|---|---|
| 期待された結果と異なります | (メソッド名)を起動した結果が期待された結果と異なる。テスト項目を参照 |
| 未初期化フィールド | インスタンスを代入すべきフィールドにインスタンスを代入していない可能性がある |
単体テストの項目
テスト失敗時に「Results」の欄の左側に出る「test~」は、テストの項目名を表している。
| 項目名 | 詳細 |
|---|---|
| volume_Triangle | new Prism(new Triangle(3.0, 4.0, 5.0), 6.0).volume() |
| surfaceArea_Triangle | new Prism(new Triangle(3.0, 4.0, 5.0), 6.0).surfaceArea() |
| toString_Triangle | new Prism(new Triangle(3.0, 4.0, 5.0), 6.0).toString() |
| volume_Rectangle | new Prism(new Rectangle(3.0, 4.0), 6.0).volume() |
| surfaceArea_Rectangle | new Prism(new Rectangle(3.0, 4.0), 6.0).surfaceArea() |
| toString_Rectangle | new Prism(new Rectangle(3.0, 4.0), 6.0).toString() |
課題1802
課題1801で作成した Prism クラスを操作するプログラム PrismAction クラスをパッケージ j2.lesson05 に作成しなさい。
このクラスには、mainメソッドだけを用意すればよい。
mainメソッドの動作を表す擬似コードは以下の通りである。出力する文字列などは以下の擬似コードに従うこと。
プログラム全体
type = 0
while type が 1 でも 2 でもない
print "底面の図形を入力(1-三角形,2-長方形):"
type = コンソール入力 (int)
Polygon 型で base を宣言
if 三角形が選択された (type = 1)
print "三角形が選択されました。", 改行
print "三角形の辺aの長さを入力:"
a = コンソール入力 (double)
print "三角形の辺bの長さを入力:"
b = コンソール入力 (double)
print "三角形の辺cの長さを入力:"
c = コンソール入力 (double)
base = 辺 a, b, c を持つ新しい三角形インスタンス
else
print "長方形が選択されました。", 改行
print "長方形の底辺の長さを入力:"
width = コンソール入力 (double)
print "長方形の高さを入力:"
height = コンソール入力 (double)
base = width, height を持つ新しい長方形インスタンス
print "角柱の高さを入力:"
height = コンソール入力 (double)
prism = base, height を持つ新しい角柱インスタンス
print prism, 改行
print "体積は" + prism.volume(), 改行
print "表面積は" + prism.surfaceArea(), 改行
結果の例
入力に順に 1, 12.0, 13.0, 5.0, 3.0 を指定した場合、プログラムを終了まで実行した際のコンソールは以下のようになっている。
底面の図形を入力(1-三角形,2-長方形):1 三角形が選択されました。 三角形の辺aの長さを入力:12.0 三角形の辺bの長さを入力:13.0 三角形の辺cの長さを入力:5.0 角柱の高さを入力:3.0 Prism(Triangle(12.0,13.0,5.0),3.0) 体積は90.0 表面積は150.0
また、入力に順に 2, 3.0, 4.0, 10.0 を指定した場合、プログラムを終了まで実行した際のコンソールは以下のようになっている。
底面の図形を入力(1-三角形,2-長方形):2 長方形が選択されました。 長方形の底辺の長さを入力:3.0 長方形の高さを入力:4.0 角柱の高さを入力:10.0 Prism(Rectangle(3.0,4.0),10.0) 体積は120.0 表面積は164.0
手順
指定した箇所で必ずテストを行うこと。
- 各メソッドに対する詳細な擬似コードを作成する
- パッケージ j2.lesson05 にクラス PrismAction を作成
- クラス内に throws IOException の指定をした mainメソッド (public static void main(String[] args) throws IOException { }) を作成
- 必ず throws IOException の記述を付加しておくこと (つまり、import java.io.*;も必要となる)
- テスト項目「PrismActionに対する骨格テスト」をパス
- 擬似コードをコメントとして貼り付ける
- mainメソッドを実装する
- 実際に実行して動作を確認する
- 機能テスト 「PrismActionに対する機能テスト」 をパス
テストの失敗メッセージ
骨格テスト
| メッセージ | 詳細 |
|---|---|
| (クラス名), existence | パッケージ内に課題で指定したクラスが存在していない。パッケージやクラス名を確認 |
| (メソッド名), existence | 指定されたメソッドが存在しない。名前や仮引数の型を確認 |
| (メソッド名), public | メソッドを作る際に public が抜けている |
| (メソッド名), static | メソッドを作る際に static が抜けている |
| (メソッド名), type <T> | メソッドを作る際に戻り値型の指定を間違っている。正しくは <T> |
| (メソッド名), throws ... | メソッドを作る際に throws... の指定がない |
機能テストの項目
テスト失敗時に「Results」の欄の左側に出る「test~」は、テストの項目名を表している。
| 項目名 | 詳細 |
|---|---|
| sample1 | 1つ目の結果の例と同じ入力 |
| sample2 | 2つ目の結果の例と同じ入力 |
課題1803 (optional)
アラームつきの24時間時計を表すクラス AlarmClock18 をパッケージ j2.lesson05 に作成しなさい。
これは第16週目課題の3つ目のプログラム (課題1603) と同様なプログラムであるが、今回は次のクラスを継承して実装すること。
package j2.lesson05;
public class Clock {
// 時刻の内部表現
private int time;
// 時刻を設定するコンストラクタ
public Clock(int hour, int minute, int second) {
this.time = hour * 3600 + minute * 60 + second;
}
// n 秒進める
public void tick(int n) {
this.time += n;
this.time %= 86400;
}
// 時刻を秒で取得する
protected int getTimeAsSec() {
return this.time;
}
// 時刻を表示する
public final void show() {
// 現在時刻の 時, 分, 秒 を h, m, s で表すとして
// print h + "時" + m + "分" + s + "秒", 改行
int h = this.time / 3600;
int m = (this.time / 60) % 60;
int s = this.time % 60;
System.out.println(h + "時" + m + "分" + s + "秒");
}
}
注意すべき点は、protected int getTimeAsSec() メソッドが増えて、void show() メソッドが final を指定しているという点である。protected で指定したメソッドは子クラスからアクセスできる。また、finalで指定したメソッドはオーバーライドできないことに注意すること。
AlarmClock18 は、上記のクラス Clock を継承し、次のようなpublicとして指定されたコンストラクタ、インスタンスメソッドを用意すること。
- AlarmClock18(int hour, int minute, int second)
- 初期時刻を設定してアラームつき時計を作成する
- 引数 hour: この時計の初期時刻のうち 時間 を設定する
- 引数 minute: この時計の初期時刻のうち 分 を設定する
- 引数 second: この時計の初期時刻のうち 秒 を設定する
- 初期状態ではアラームは設定されていない (解除された状態にある)
- void setAlarmFor(int hour, int minute, int second)
- アラーム時刻を設定する。すでにアラームが設定されていた場合、古いアラームは解除される。
- 引数 hour: アラーム時刻のうち 時間 を設定する
- 引数 minute: アラーム時刻のうち 分 を設定する
- 引数 second: アラーム時刻のうち 秒 を設定する
- 戻り値なし
- アラームをセットした時刻と現在時刻が同じならばアラームを鳴らし(*1)、アラームを解除する
必要に応じてメソッドをオーバーライドしてもかまわないが、その際にもそれらのメソッドは Clock クラスのコメントに合った振る舞いをすること。つまり、このクラスを Clock として扱った場合 (setAlarmFor を一度も呼び出さなかった場合) に、tick や show が本来の Clock とまったく同じ動作をすること。ただし、時刻を進めたことによって、アラーム時刻を通過したりアラーム時刻に達した場合、アラームを鳴らし(*1)、アラームを解除する。
- *1: アラームを鳴らすべき状況では、アラーム と表示し、表示後に改行を入れる
継承したメソッドを含めて、全ての public なメソッドおよびコンストラクタの動作は第16週目課題の3つ目のプログラム (課題1603) と同等のものであること。
手順
指定した箇所で必ずテストを行うこと。
- 各メソッドに対する詳細な擬似コードを作成する
- パッケージ j2.lesson05 にクラス AlarmClock18 を作成
- クラス内に必要なコンストラクタ、メソッドの骨格を作成
- テスト項目「AlarmClock18に対する骨格テスト」をパス
- 擬似コードを各メソッドにコメントとして貼り付ける
- 擬似コードに対するプログラムを書く (main メソッド以外)
- 各メソッドをテストする (JUnitを用いてもよい)
- 単体テスト 「AlarmClock18に対する単体テスト」 をパス
- mainメソッドを実装する
- 実際に実行して動作を確認する
使用例
次のような main メソッドを書いた場合を考える。
// 23時15分 AlarmClock clock = new AlarmClock18(23, 15, 0); clock.show(); // 現在の時刻にセット clock.setAlarmFor(23, 15, 0); // アラームが鳴るはず // 5時にセット clock.setAlarmFor(5, 0, 0); // 2時間進める clock.tick(2 * 3600); clock.show(); // 2時間進める clock.tick(2 * 3600); clock.show(); // 2時間進める clock.tick(2 * 3600); // アラームが鳴るはず clock.show();
これを実行すると、次のように表示される。
23時15分0秒 アラーム 1時15分0秒 3時15分0秒 アラーム 5時15分0秒
今回は、目覚まし時計ではなくただの時計として扱うこともできる。
// 23時15分 Clock clock = new AlarmClock18(23, 15, 0); clock.show(); // 2時間進める clock.tick(2 * 3600); clock.show(); // 2時間進める clock.tick(2 * 3600); clock.show(); // 2時間進める clock.tick(2 * 3600); clock.show();
テストの失敗メッセージ
骨格テスト
| メッセージ | 詳細 |
|---|---|
| (クラス名), existence | パッケージ内に課題で指定したクラスが存在していない。パッケージやクラス名を確認 |
| (クラス名), extends <C> | クラスを作る際に継承するクラスが間違っている。正しくは <C> |
| (メンバ名), existence | 指定されたメンバが存在しない |
| (メンバ名), public | メンバを作る際に public の指定がない |
| (メンバ名), private | メンバを作る際に private の指定がない |
| (メンバ名), final | メンバを作る際に final の指定がない |
| (メンバ名), not static | メンバを作る際に static が余計についている |
| (メンバ名), type <T> | メンバを作る際に型の指定を間違っている。正しくは <T> |
単体テスト
| メッセージ | 詳細 |
|---|---|
| 期待された結果と異なります | (メソッド名)を起動した結果が期待された結果と異なる。テスト項目を参照 |
| 未初期化フィールド | インスタンスを代入すべきフィールドにインスタンスを代入していない可能性がある |
単体テストの項目
テスト失敗時に「Results」の欄の左側に出る「test~」は、テストの項目名を表している。
| 項目名 | 詳細 |
|---|---|
| bCtor_000 | new Clock(0, 0, 0).show() |
| bCtor_123 | new Clock(1, 2, 3).show() |
| btick_000001 | new Clock(0, 0, 0).tick(1).show() |
| btick_000030 | new Clock(0, 0, 0).tick(30).show() |
| btick_000059 | new Clock(0, 0, 0).tick(59).show() |
| btick_000100 | new Clock(0, 0, 0).tick(60).show() |
| btick_003000 | new Clock(0, 0, 0).tick(1800).show() |
| btick_005959 | new Clock(0, 0, 0).tick(3599).show() |
| btick_010000 | new Clock(0, 0, 0).tick(3600).show() |
| btick_120000 | new Clock(0, 0, 0).tick(43200).show() |
| btick_235959 | new Clock(0, 0, 0).tick(86399).show() |
| btick_loop | new Clock(23, 59, 59).tick(1).show() |
| Ctor_000 | new AlarmClock18(0, 0, 0).show() |
| Ctor_123 | new AlarmClock18(1, 2, 3).show() |
| alarm_0 | new AlarmClock18(0, 0, 0), setAlarmFor(0, 0, 0), show() |
| alarm_1a | new AlarmClock18(0, 0, 0), setAlarmFor(0, 0, 1), show() |
| alarm_1b | new AlarmClock18(0, 0, 0), setAlarmFor(0, 0, 1), tick(1), show() |
| alarm_1c | new AlarmClock18(0, 0, 0), setAlarmFor(0, 0, 1), tick(2), show() |
| alarm_f | new AlarmClock18(10, 0, 0), setAlarmFor(15, 0, 0), show() |
| alarm_fM1 | new AlarmClock18(10, 0, 0), setAlarmFor(15, 0, 0), tick(5 * 3600 - 1), show() |
| alarm_f0 | new AlarmClock18(10, 0, 0), setAlarmFor(15, 0, 0), tick(5 * 3600), show() |
| alarm_f1 | new AlarmClock18(10, 0, 0), setAlarmFor(15, 0, 0), tick(5 * 3600 + 1), show() |
| alarm_b | new AlarmClock18(22, 0, 0), setAlarmFor(7, 0, 0), show() |
| alarm_bM1 | new AlarmClock18(22, 0, 0), setAlarmFor(7, 0, 0), tick(9 * 3600 - 1), show() |
| alarm_b0 | new AlarmClock18(22, 0, 0), setAlarmFor(7, 0, 0), tick(9 * 3600), show() |
| alarm_b1 | new AlarmClock18(22, 0, 0), setAlarmFor(7, 0, 0), tick(9 * 3600 + 1), show() |
| alarm_nextM1 | new AlarmClock18(23, 59, 58), setAlarmFor(0, 0, 0), tick(1), show() |
| alarm_next0 | new AlarmClock18(23, 59, 58), setAlarmFor(0, 0, 0), tick(2), show() |
| alarm_next1 | new AlarmClock18(23, 59, 58), setAlarmFor(0, 0, 0), tick(3), show() |
課題1804 (optional)
足跡を残すことができる亀を表すクラス TrackTurtle をパッケージ j2.lesson05 に作成しなさい。
TrackTurtle は下記のクラス Turtle を継承すること。これは第15週目演習の4番目のプログラム (課題1504) に似ている。
package j2.lesson05;
public class Turtle {
// x 座標
private int x;
// y 座標
private int y;
// 現在の向きを表す。
// 0 - North
// 1 - East
// 2 - South
// 3 - West
private int direction;
// Turtle インスタンスを生成する。
// 初期値は (x,y)=(0,0), direction=North.
public Turtle() {
this.x = 0;
this.y = 0;
this.direction = 0;
}
// 現在向いている方向に1だけ移動する。
// つまり、以下のように移動する。
// * North を向いている → y 方向へ +1 移動する
// * South を向いている → y 方向へ -1 移動する
// * East を向いている → x 方向へ +1 移動する
// * West を向いている → x 方向へ -1 移動する
public Turtle move() {
switch(this.direction) {
case 0:
this.y++;
break;
case 1:
this.x++;
break;
case 2:
this.y--;
break;
case 3:
this.x--;
break;
default:
break;
}
return this;
}
// 90度右へ向く
public Turtle turnRight() {
this.direction = (this.direction + 1) % 4;
return this;
}
// 90度左へ向く
public Turtle turnLeft() {
this.direction = (this.direction + 3) % 4;
return this;
}
// 現在のX座標を取得する
public int getX() {
return this.x;
}
// 現在のY座標を取得する
public int getY() {
return this.y;
}
}
TrackTurtle は、上記のクラス Turtle を継承し、次のようなpublicとして指定されたコンストラクタ、インスタンスメソッドを用意すること。
- public TrackTurtle()
- 足跡を残せる亀インスタンスを作成する。足跡を残せる領域は15*15の領域とする。
- 領域について (親クラスのTurtleと南北が逆になっているので注意すること)
- (x, y) から北に1進むと (x, y - 1)
- (x, y) から南に1進むと (x, y + 1)
- (x, y) から東に1進むと (x + 1, y)
- (x, y) から西に1進むと (x - 1, y)
- 領域内で最も北西に位置する点を(0, 0)とする
- 領域内で最も北東に位置する点を(14, 0)とする
- 領域内で最も南西に位置する点を(0, 14)とする
- 領域内で最も南東に位置する点を(14, 14)とする
- 初期状態について
- 足跡は残さない設定
- 北を向いている
- (x, y) = (7, 7) 、つまり足跡を残せる領域の中央にいる
- public void setTrackable(boolean b)
- move() を実行した際に足跡を残すかどうかを設定する。
- turn~() はこの設定に関係なく足跡を残さない
- パラメータ: b - true ならば足跡を残す設定にする
- public boolean isTrackable()
- 足跡を残すかどうか調べる。
- 戻り値: 足跡を残す設定ならば true
- コンストラクタを呼び出した直後にこのメソッドが呼び出されると、false を返す (初期状態では足跡を残さない設定)
- public void show()
- 現在の足跡情報を表示(*1)する。足跡が残っている場所には"@"を表示し、残っていない場所には" "(半角スペース)を表示する。
足跡を残す設定のときに move() メソッドが呼び出されると、足跡を残す。詳しくは以下の仕様である。
- public Turtle move()
- 現在向いている方向に1だけ進む。その際、足跡を残す設定ならば、この操作によって移動する前の位置に足跡を残す。
- ただし、足跡を残せる領域から外れていた場合は、足跡を残す設定であっても足跡を残さずに移動する。
- すでに足跡が残っている場所にさらに足跡を残しても変化はない
- オーバーライド: クラス Turtle 内の move
- 戻り値: 自分自身 (this)
(*1):下記のような擬似コードで表されるように出力すること
// public void show()
show()
for y を 0 から 14 まで
for x を 0 から 14 まで
if (map(x, y))
print "@"
else
print " " // 半角スペース
print 改行
// (x, y) における足跡の状態
map(x, y)
if (x, y) に足跡がある
return true
else
return false
また、TrackTurtle クラス内に簡単な main メソッドを用意し、動作を確認すること。
プログラム例
上記のクラスを使用すると、15x15の領域に簡単な絵を描くことができる。
次の例は、15x15の外周に足跡を残す例である。
TrackTurtle turtle = new TrackTurtle();
// 北西へ
turtle.move().move().move().move().move().move().move();
turtle.turnLeft().move().move().move().move().move().move().move();
// 足跡開始
turtle.setTrackable(true);
// 外周を一周
for (int i = 0; i < 4; i++) {
turtle.turnLeft();
for (int j = 0; j < 14; j++) {
turtle.move();
}
}
turtle.show();
以下のような結果になる。
@@@@@@@@@@@@@@@ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @@@@@@@@@@@@@@@
また、市松模様と呼ばれる模様も描ける。
TrackTurtle turtle = new TrackTurtle();
// 北西へ
turtle.move().move().move().move().move().move().move();
turtle.turnLeft().move().move().move().move().move().move().move();
turtle.setTrackable(true);
turtle.turnLeft().turnLeft();
// 上から下へ
for (int y = 0; y < 15; y++) {
// 左から右へ
for (int x = 0; x < 15; x++) {
// 現在位置の x + y が偶数なら書き込む
turtle.setTrackable((x + y) % 2 == 0);
turtle.move();
}
// 左へ帰る
turtle.setTrackable(false);
turtle.turnLeft().turnLeft();
for (int x = 0; x < 15; x++) {
turtle.move();
}
// 一歩下へ
turtle.turnLeft().move();
// 東を向く
turtle.turnLeft();
}
turtle.show();
@ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @
面白い幾何学模様を描くようなプログラムを考え、作成せよ。
手順
指定した箇所で必ずテストを行うこと。
- パッケージ j2.lesson05 にクラス Turtle を作成
- 各メソッドに対する詳細な擬似コードを作成する
- パッケージ j2.lesson05 にクラス TrackTurtle を作成
- 指定したインスタンスメソッドやコンストラクタを作成する
- main メソッドを作成する (この時点では空でもよい)
- テスト項目「TrackTurtleに対する骨格テスト」をパス
- インスタンスメソッドやコンストラクタの中身を書く (演習と同様)
- main メソッドを書いて簡単なテストを行う
- JUnit を用いてもよい
- テスト項目「TrackTurtleに対する機能テスト」をパス
テストの失敗メッセージ
骨格テスト
| メッセージ | 詳細 |
|---|---|
| (クラス名), existence | パッケージ内に課題で指定したクラスが存在していない。パッケージやクラス名を確認 |
| (クラス名), extends <C> | クラスを作る際に継承するクラスが間違っている。正しくは <C> |
| (メンバ名), existence | 指定されたメンバが存在しない |
| (メンバ名), public | メンバを作る際に public の指定がない |
| (メンバ名), private | メンバを作る際に private の指定がない |
| (メンバ名), final | メンバを作る際に final の指定がない |
| (メンバ名), not static | メンバを作る際に static が余計についている |
| (メンバ名), type <T> | メンバを作る際に型の指定を間違っている。正しくは <T> |
機能テストの項目
テスト失敗時に「Results」の欄の左側に出る「test~」は、テストの項目名を表している。
| 項目名 | 詳細 |
|---|---|
| sample1 | 外周を囲むサンプル |
| sample2 | 市松模様を描くサンプル |
| sample3 | sample2と逆の足跡を残す |