第20週目課題

課題2001

コンソールから入力された行を逆順に表示するプログラム LineReversePrint クラスをパッケージ j2.lesson07 に作成しなさい。

このプログラムでは、コンソールからドット「.」一文字のみの入力行が来るまで次々と文字列を入力させ、最後に入力された行から逆順にコンソールに表示する。表示する際は、ドット「.」一文字のみの行はコンソールに表示しない

つまり、"a", "b", "c", "." と入力すると、

c
b
a

と出力されるようなプログラムである。

入力部分の擬似コードは次の通りである。擬似コードに従った表示を行うこと。

次を繰り返す
    print "文字列を入力:"
    input = コンソール入力 (文字列)
    input がドット「.」のみであったら繰り返しを終了
    input を記憶しておく

上記のプログラムは、j2.lesson07.LineReversePrint クラスの main メソッドに記述すること。

結果の例

このプログラムを実行し、各行に "apple", "orange", "", "grape", "." と順に入力すると、プログラム終了時のコンソール画面は以下のようになっている。

文字列を入力:apple
文字列を入力:orange
文字列を入力:
文字列を入力:grape
文字列を入力:.
grape

orange
apple

手順

指定した箇所で必ずテストを行うこと。

  1. 詳細な擬似コードを作成する
  2. パッケージ j2.lesson07 にクラス LineReversePrint を作成
  3. main メソッドを作成する
  4. テスト項目「LineReversePrintに対する骨格テスト」をパス
  5. main メソッドにプログラムを書く
  6. テスト項目「LineReversePrintに対する機能テスト」をパス

テストの失敗メッセージ

骨格テスト

メッセージ 詳細
(クラス名), existence パッケージ内に課題で指定したクラスが存在していない。パッケージやクラス名を確認
(メンバ名), existence 指定されたメンバが存在しない
(メンバ名), public メンバを作る際に public の指定がない
(メンバ名), static メンバを作る際に static の指定がない
(メンバ名), type <T> メンバを作る際に型の指定を間違っている。正しくは <T>

機能テスト

メッセージ 詳細
期待された結果と異なります 出力された結果が期待された値と異なる。「期待された値」と「実際の値」を比較し確認。他にも直接プログラムを実行して結果を調べたり、エラーメッセージの2行目にあるat以下を参考にプログラムを見直す

機能テストの項目

テスト失敗時に「Results」の欄の左側に出る「test~」は、テストの項目名を表している。

項目名 詳細
sample 結果の例と同じ入力
empty "." を入力
one "a", "." を入力
two "a", "b", "." を入力
three "a", "b", "c", "." を入力
many 多数の入力を行った後に "." を入力

課題2002

英語の文章を日本語らしき文章に変換する簡単な翻訳機 SimpleTranslator クラスをパッケージ j2.lesson07 に作成しなさい。

このプログラムは、英語の単語を日本語の単語に変換できる辞書を持っており、入力された英文の各単語を日本語に変換して表示するだけの簡単な翻訳機である。

例えば、"Time flies like an arrow" という英文を入力すると、下記のように出力される。

英文を入力:Time flies like an arrow
時間は飛ぶまるでひとつの矢

辞書に使うデータは、次のものを使用すること。

入力される単語 出力する単語
time 時間
is
money お金
flies は飛ぶ
like まるで
a ひとつの
an ひとつの
arrow

辞書にない単語が入力された場合、次のように元の単語を括弧でくくって表示する。

英文を入力:Time flies like a bullet
時間は飛ぶまるでひとつの(bullet)

上記の場合は、bullet という単語が指定した辞書に登録されていないため、(bullet) と表示している。

次の擬似コードに従った出力をすること。

print "英文を入力:"
input = コンソール入力 (文字列)
for word = 入力された英単語をスペース区切りで順に
    if word が辞書に登録されている
        jword = word を辞書から引いた結果
        print jword
    else
        print "(" + word + ")"

ただし、入力される英文は大文字でも小文字でも動作するようにすること。例えば、"Time flies like an arrow" と入力した場合と "TIME FLIES LIKE AN ARROW" と入力した場合に出力される日本語の文章が等しくなるように作成すること。

入力される各単語の区切りは常に半角スペース(" ")一文字であると仮定してもよい。また、半角のアルファベットと半角スペース以外の入力に対しては考慮しなくてよい。

上記のプログラムは、j2.lesson07.SimpleTranslator クラスの main メソッドに記述すること。

結果の例

このプログラムを実行し、"Time flies like an arrow" と入力すると、プログラム終了時のコンソール画面は以下のようになっている。

英文を入力:Time flies like an arrow
時間は飛ぶまるでひとつの矢

手順

指定した箇所で必ずテストを行うこと。

  1. 詳細な擬似コードを作成する
  2. パッケージ j2.lesson07 にクラス SimpleTranslator を作成
  3. main メソッドを作成する
  4. テスト項目「SimpleTranslatorに対する骨格テスト」をパス
  5. main メソッドにプログラムを書く
  6. テスト項目「SimpleTranslatorに対する機能テスト」をパス

テストの失敗メッセージ

骨格テスト

メッセージ 詳細
(クラス名), existence パッケージ内に課題で指定したクラスが存在していない。パッケージやクラス名を確認
(メンバ名), existence 指定されたメンバが存在しない
(メンバ名), public メンバを作る際に public の指定がない
(メンバ名), static メンバを作る際に static の指定がない
(メンバ名), type <T> メンバを作る際に型の指定を間違っている。正しくは <T>

機能テスト

メッセージ 詳細
期待された結果と異なります 出力された結果が期待された値と異なる。「期待された値」と「実際の値」を比較し確認。他にも直接プログラムを実行して結果を調べたり、エラーメッセージの2行目にあるat以下を参考にプログラムを見直す

機能テストの項目

テスト失敗時に「Results」の欄の左側に出る「test~」は、テストの項目名を表している。

項目名 詳細
sample1 入力 "Time flies like an arrow"
sample_upper 入力 "TIME FLIES LIKE AN ARROW"
sample_lower 入力 "time flies like an arrow"
bullet 入力 "Time flies like a bullet"
ismoney 入力 "Time is money"
moneyflies 入力 "Money flies"

課題2003 (optional)

指定した日数後の日付を表示するプログラム DaysLater クラスをパッケージ j2.lesson07 に作成しなさい。

このプログラムは、まずコンソールに日数を入力させ、その値が 0 ならば今日の日付を表示し、正の値 n ならば今日から n 日後の日付を表示する。不の値が入力された場合は "正の値を入力してください" と表示し、プログラムを終了させる。

次の擬似コードに従った出力をすること。

print "日数を入力:"
days = コンソール入力 (int)
if days が 0
    print "今日は" + (年) + "年" + (月) + "月" + (日) + "日", 改行
else if days が正の値
    print days + "日後は" + (年) + "年" + (月) + "月" + (日) + "日", 改行
else if days が負の値
    print "正の値を入力してください", 改行

表示する部分の (年), (月), (日) には、それぞれ次のような数値を出力すること。

例えば、コンソールに入力された値が 0 で、今日の日付が 2005年1月23日だったとすると、次のように表示される。

日数を入力:0
今日は2005年1月23日

上記のプログラムは、j2.lesson07.DaysLater クラスの main メソッドに記述すること。

結果の例

このプログラムを実行し、"365" と入力すると、プログラム終了時のコンソール画面は以下のようになっている。

日数を入力:365
365日後は2006年11月4日

なお、この資料を作成した時点の日付は 2005年11月4日 である。

手順

指定した箇所で必ずテストを行うこと。

  1. 詳細な擬似コードを作成する
  2. パッケージ j2.lesson07 にクラス DaysLater を作成
  3. main メソッドを作成する
  4. テスト項目「DaysLaterに対する骨格テスト」をパス
  5. main メソッドにプログラムを書く
  6. テスト項目「DaysLaterに対する機能テスト」をパス

ヒント

日付を計算するプログラムを自分で用意してもよいが、できれば API 仕様を調べてそちらを使ってみてほしい。

java.util パッケージに 日付に関するクラスが 2~3 用意されている。そのうち java.util.Date クラスは古い実装で使いにくいため、使用を避けたほうがよい。

テストの失敗メッセージ

骨格テスト

メッセージ 詳細
(クラス名), existence パッケージ内に課題で指定したクラスが存在していない。パッケージやクラス名を確認
(メンバ名), existence 指定されたメンバが存在しない
(メンバ名), public メンバを作る際に public の指定がない
(メンバ名), static メンバを作る際に static の指定がない
(メンバ名), type <T> メンバを作る際に型の指定を間違っている。正しくは <T>

機能テスト

メッセージ 詳細
期待された結果と異なります 出力された結果が期待された値と異なる。「期待された値」と「実際の値」を比較し確認。他にも直接プログラムを実行して結果を調べたり、エラーメッセージの2行目にあるat以下を参考にプログラムを見直す

機能テストの項目

テスト失敗時に「Results」の欄の左側に出る「test~」は、テストの項目名を表している。

このテストを日付変更の瞬間に実行した際、正しい結果が得られない場合がある。その際は、再度テストを行ってみること。

項目名 詳細
main_M10 入力に "-10"
main_M1 入力に "-1"
main_0 入力に "0"
main_1 入力に "1"
main_2 入力に "2"
main_15 入力に "15"
main_28 入力に "28"
main_29 入力に "29"
main_30 入力に "30"
main_31 入力に "31"
main_32 入力に "32"
main_182 入力に "182"
main_365 入力に "365"
main_1461 入力に "1461"

課題2004 (optional)

二つの java.util.List インスタンスを連結して、一つの List のように扱うためのクラス SyzygyList をパッケージ j2.lesson07 に作成しなさい。

この SyzygyList クラスは List インターフェースを実装するクラスで、「二つの java.util.List インスタンスを連結して、一つの List のように扱う」ことができる。コンストラクタに連結させる 2つの java.util.List インスタンスをとる。コンストラクタの第一引数に渡した List インスタンスが SyzygyList の前半部分で、第二引数に渡した List インスタンスが後半部分となる。

List first = new ArrayList();
List last = new ArrayList();
first.add("a");
first.add("b");
last.add("c");
last.add("d");

System.out.println(first); // -> [a, b]
System.out.println(last);  // -> [c, d]

List syzygy = new SyzygyList(first, last);
System.out.println(syzygy); // -> [a, b, c, d]

連結されたリストは get(int) メソッドを呼び出すことによって、連結された元のリストの内容を取得できる。

List first = new ArrayList();
List last = new ArrayList();
first.add("a");
first.add("b");
last.add("c");
last.add("d");
List syzygy = new SyzygyList(first, last);
System.out.println(syzygy.get(0)); // -> a
System.out.println(syzygy.get(1)); // -> b
System.out.println(syzygy.get(2)); // -> c
System.out.println(syzygy.get(3)); // -> d

連結されたリストは set(int, Object) メソッドによって変更が可能で、連結されたリストの一部を変更すると、元になったリストの該当部分も同時に変更される。

List first = new ArrayList();
List last = new ArrayList();
first.add("a");
first.add("b");
last.add("c");
last.add("d");
List syzygy = new SyzygyList(first, last);
syzygy.set(0, "A");
syzygy.set(3, "D");
System.out.println(first.get(0)); // -> A
System.out.println(last.get(1));  // -> D

また、元のリストに対して変更を加えると、連結されたリストの中身も変更される。

List first = new ArrayList();
List last = new ArrayList();
first.add("a");
first.add("b");
last.add("c");
last.add("d");
List syzygy = new SyzygyList(first, last);
first.add("first");
last.add("last");
System.out.println(syzygy); // -> [a, b, first, c, d, last]

連結されたリストに対して size() メソッドを呼び出すと、連結元のリストの長さの合計が返される。

SyzygyList は java.util.List インターフェースを実装し (親クラスの誰かが実装しているだけでもよい)、上記のような振る舞いを List の仕様に従ってそれぞれのメソッドに定義すること

下記のメソッドについては、呼び出し時にどのような動作をしてもよい。

ただし、これまでに例外については解説を行っていないため、例外については考慮しなくてよい

手順

指定した箇所で必ずテストを行うこと。

  1. パッケージ j2.lesson07 にクラス SyzygyList を作成
  2. 指定したインスタンスメソッドやコンストラクタを作成する
  3. テスト項目「SyzygyListに対する骨格テスト」をパス
  4. インスタンスメソッドやコンストラクタの中身を書く (演習と同様)
  5. main メソッドを書いて簡単なテストを行う
  6. テスト項目「SyzygyListに対する単体テスト」をパス

ヒント

java.util.List の全てのメソッドを実装すると非常に大変である。そのため、このインターフェースの骨格実装を行っているクラスを探すとよい。API 仕様の「関連項目:」という欄が参考になるはずである。

骨格実装を見つければ、メソッドを3つオーバーライドするだけで済む。

テスト

今回はテストプログラムを公開する。単体テストではこれと同様のテストを行う。このテストプログラムの起動方法は、通常の main メソッドを持つクラスと同様である。コメントにある // # は、単体テスト失敗時のメッセージを表している。

このテストケースは、JUnit を用いて記述している。JUnit については、下記の URL にある過去の演習を参考にするとよい。

下記のプログラム内にある assertEquals(Object, Object) メソッドは、「assertEquals(a, b);」と書いたときに、a.equals(b) が実行されて、a と b が同じ内容ならば何もせずに次の行を実行し、a と b の内容が異なればそこでテストを失敗させるメソッドである。また、assertTrue(boolean) や assertFalse(boolean) メソッドは、引数にとられた boolean の値が assert~ で示された値と違う場合はそこでテストを失敗させる。

詳しくは、次のドキュメントを参考にすること。

package j2.lesson07;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;

import junit.framework.TestCase;
import junit.swingui.TestRunner;

/**
 * Test for {@link SyzygyList}.
 */
public class SyzygyListTest extends TestCase {
    
    public static void main(String[] args) {
        TestRunner.run(SyzygyListTest.class);
    }

    /**
     * Test method for 'java.util.List.equals(Object)'
     */
    public void testEquals() {
        List ee = new SyzygyList(Collections.EMPTY_LIST, Collections.EMPTY_LIST);
        List ee2 = new SyzygyList(Collections.EMPTY_LIST, Collections.EMPTY_LIST);
        assertEquals(ee, ee2); // # equals-0
        
        List ae = new SyzygyList(Collections.singletonList("a"), Collections.EMPTY_LIST);
        List ea = new SyzygyList(Collections.EMPTY_LIST, Collections.singletonList("a"));
        assertEquals(ae, ea); // # equals-1
        
        List abe = new SyzygyList(Arrays.asList(new String[]{"a", "b"}), Collections.EMPTY_LIST);
        List ab = new SyzygyList(Collections.singletonList("a"), Collections.singletonList("b"));
        List eab = new SyzygyList(Collections.EMPTY_LIST, Arrays.asList(new String[]{"a", "b"}));
        assertEquals(abe, ab); // # equals-2a
        assertEquals(ab, eab); // # equals-2b
        assertEquals(eab, abe); // # equals-2c
    }

    /**
     * Test method for 'java.util.List.iterator()'
     */
    public void testIterator() {
        List ls = new SyzygyList(
            Arrays.asList(new String[]{"a", "b", "c"}),
            Arrays.asList(new String[]{"d", "e"})
        );
        Iterator iter = ls.iterator();
        assertTrue(iter.hasNext()); // # iterator-hasNext-0
        assertEquals("a", iter.next()); // # iterator-next-1
        assertTrue(iter.hasNext()); // # iterator-hasNext-1
        assertEquals("b", iter.next()); // # iterator-next-2
        assertTrue(iter.hasNext()); // # iterator-hasNext-2
        assertEquals("c", iter.next()); // # iterator-next-3
        assertTrue(iter.hasNext()); // # iterator-hasNext-3
        assertEquals("d", iter.next()); // # iterator-next-4
        assertTrue(iter.hasNext()); // # iterator-hasNext-4
        assertEquals("e", iter.next()); // # iterator-next-5
        assertFalse(iter.hasNext()); // # iterator-hasNext-5
    }

    /**
     * Test method for 'java.util.List.get(int)'
     */
    public void testGetInt() {
        List ls = new SyzygyList(
            Arrays.asList(new String[]{"a", "b", "c"}),
            Arrays.asList(new String[]{"d", "e"})
        );
        assertEquals("a", ls.get(0)); // # get-0
        assertEquals("b", ls.get(1)); // # get-1
        assertEquals("c", ls.get(2)); // # get-2
        assertEquals("d", ls.get(3)); // # get-3
        assertEquals("e", ls.get(4)); // # get-4
    }

    /**
     * Test method for 'java.util.List.set(int, E)'
     */
    public void testSetIntE() {
        List ls = new SyzygyList(
            Arrays.asList(new String[]{"a", "b"}),
            Arrays.asList(new String[]{"c", "d", "e"})
        );
        assertEquals("a", ls.set(0, "A")); // # set-0
        assertEquals("b", ls.set(1, "B")); // # set-1
        assertEquals("c", ls.set(2, "C")); // # set-2
        assertEquals("d", ls.set(3, "D")); // # set-3
        assertEquals("e", ls.set(4, "E")); // # set-4
        assertEquals("A", ls.get(0)); // # set-0a
        assertEquals("B", ls.get(1)); // # set-1a
        assertEquals("C", ls.get(2)); // # set-2a
        assertEquals("D", ls.get(3)); // # set-3a
        assertEquals("E", ls.get(4)); // # set-4a
    }

    /**
     * Test method for 'java.util.List.indexOf(Object)'
     */
    public void testIndexOf() {
        List ls = new SyzygyList(
            Arrays.asList(new String[]{"a", "b", "c", "d", "e"}),
            Arrays.asList(new String[]{"A", "b", "C", "d", "E"})
        );
        assertEquals(0, ls.indexOf("a")); // # indexOf-0
        assertEquals(1, ls.indexOf("b")); // # indexOf-1
        assertEquals(2, ls.indexOf("c")); // # indexOf-2
        assertEquals(3, ls.indexOf("d")); // # indexOf-3
        assertEquals(4, ls.indexOf("e")); // # indexOf-4
        assertEquals(5, ls.indexOf("A")); // # indexOf-5
        assertEquals(7, ls.indexOf("C")); // # indexOf-6
        assertEquals(9, ls.indexOf("E")); // # indexOf-7
    }

    /**
     * Test method for 'java.util.List.lastIndexOf(Object)'
     */
    public void testLastIndexOf() {
        List ls = new SyzygyList(
            Arrays.asList(new String[]{"a", "b", "c", "d", "e"}),
            Arrays.asList(new String[]{"A", "b", "C", "d", "E"})
        );
        assertEquals(0, ls.lastIndexOf("a")); // # lastIndexOf-0
        assertEquals(2, ls.lastIndexOf("c")); // # lastIndexOf-1
        assertEquals(4, ls.lastIndexOf("e")); // # lastIndexOf-2
        assertEquals(5, ls.lastIndexOf("A")); // # lastIndexOf-3
        assertEquals(6, ls.lastIndexOf("b")); // # lastIndexOf-4
        assertEquals(7, ls.lastIndexOf("C")); // # lastIndexOf-5
        assertEquals(8, ls.lastIndexOf("d")); // # lastIndexOf-6
        assertEquals(9, ls.lastIndexOf("E")); // # lastIndexOf-7
    }

    /**
     * Test method for 'java.util.List.subList(int, int)'
     */
    public void testSubList() {
        List head = Arrays.asList(new String[]{"a", "b", "c", "d", "e"});
        List tail = Arrays.asList(new String[]{"A", "B", "C", "D", "E"});
        List syzygy = new SyzygyList(head, tail);
        assertEquals(head, syzygy.subList(0, 5)); // # subList-0
        assertEquals(tail, syzygy.subList(5, 10)); // # subList-1
        assertEquals(Arrays.asList(new String[]{"e", "A"}), syzygy.subList(4, 6)); // # subList-2
    }
    
    /**
     * Test method for original method has called 'add(Object)'.
     */
    public void testExternalAdd() {
        List head = new ArrayList(Arrays.asList(new String[]{"a", "b", "c", "d", "e"}));
        List tail = new ArrayList(Arrays.asList(new String[]{"A", "B", "C", "D", "E"}));
        List syzygy = new SyzygyList(head, tail);
        assertEquals(10, syzygy.size()); // # exadd-0
        assertEquals("e", syzygy.get(4)); // # exadd-1
        assertEquals("A", syzygy.get(5)); // # exadd-2
        head.add("f");
        assertEquals(11, syzygy.size()); // # exadd-3
        assertEquals("e", syzygy.get(4)); // # exadd-4
        assertEquals("f", syzygy.get(5)); // # exadd-5
        assertEquals("A", syzygy.get(6)); // # exadd-6
        tail.add("F");
        assertEquals(12, syzygy.size()); // # exadd-7
        assertEquals("E", syzygy.get(10)); // # exadd-8
        assertEquals("F", syzygy.get(11)); // # exadd-9
    }

    /**
     * Test method for original method has called 'remove(int)'.
     */
    public void testExternalRemove() {
        List head = new ArrayList(Arrays.asList(new String[]{"a", "b", "c", "d", "e"}));
        List tail = new ArrayList(Arrays.asList(new String[]{"A", "B", "C", "D", "E"}));
        List syzygy = new SyzygyList(head, tail);
        assertEquals(10, syzygy.size()); // # exremove-0
        assertEquals("e", syzygy.get(4)); // # exremove-1
        assertEquals("A", syzygy.get(5)); // # exremove-2
        head.remove(3);
        assertEquals(9, syzygy.size()); // # exremove-3
        assertEquals("e", syzygy.get(3)); // # exremove-4
        assertEquals("A", syzygy.get(4)); // # exremove-5
        tail.remove(0);
        assertEquals(8, syzygy.size()); // # exremove-6
        assertEquals("e", syzygy.get(3)); // # exremove-7
        assertEquals("B", syzygy.get(4)); // # exremove-8
    }
}