3日目

レポート

必須課題

以下の課題問題を解き,レポートとして提出して下さい.

オプション課題

縦長の画面出力

DisplayScreenWideやDisplayFileWide,DisplayHtmlWideクラスで横に2倍横長の表示が実現できました. 今度は,縦に2倍長い画面表示を実現するクラス(ここではDisplayScreenLongクラスを名付けます)をDisplayScreenクラスを継承して実装してみましょう. この時,他のクラスを一切変更してはいけません.
(ヒント:put()が呼ばれた時にすぐに1マス出力せずに,put()内では何らかのバッファに保存しておき,newLine()が呼ばれた時にバッファに保存しておいた1行分のデータを2回続けて出力すれば実現できます. 1行の長さはあらかじめわからないので,動的配列かSTLなどを利用しましょう.)

出力例

OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO
OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO
S       O   O           O         O   O O
S       O   O           O         O   O O
O OOOOO O O O O OOOOOOO O OOOOOOO O O O O
O OOOOO O O O O OOOOOOO O OOOOOOO O O O O
O O   O   O O O   O     O O       O O   O
O O   O   O O O   O     O O       O O   O
OOO O OOOOO O OOO O OOOOO OOO OOOOO OOO O
OOO O OOOOO O OOO O OOOOO OOO OOOOO OOO O
O O O     O O   O O O   O   O O     O   O
O O O     O O   O O O   O   O O     O   O
O O O OOOOO OOO O O O OOO O O OOO OOO OOO
O O O OOOOO OOO O O O OOO O O OOO OOO OOO
O O O       O   O O O     O O   O   O O O
O O O       O   O O O     O O   O   O O O
O O OOOOOOOOOOOOO O OOOOOOO OOO OOO O O O
O O OOOOOOOOOOOOO O OOOOOOO OOO OOO O O O
O                 O         O       O   G
O                 O         O       O   G
OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO
OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO

横長,縦長の画面出力

縦横に2倍横長,縦長の画面表示を実現するクラス(ここでは,DisplayScreenWideLongクラスと名付けます)をDisplayScreenLongを継承して実装してみましょう. この時,他のクラスを一切変更してはいけません.

出力例

OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO
OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO
SS              OO      OO                      OO                  OO      OO  OO
SS              OO      OO                      OO                  OO      OO  OO
OO  OOOOOOOOOO  OO  OO  OO  OO  OOOOOOOOOOOOOO  OO  OOOOOOOOOOOOOO  OO  OO  OO  OO
OO  OOOOOOOOOO  OO  OO  OO  OO  OOOOOOOOOOOOOO  OO  OOOOOOOOOOOOOO  OO  OO  OO  OO
OO  OO      OO      OO  OO  OO      OO          OO  OO              OO  OO      OO
OO  OO      OO      OO  OO  OO      OO          OO  OO              OO  OO      OO
OOOOOO  OO  OOOOOOOOOO  OO  OOOOOO  OO  OOOOOOOOOO  OOOOOO  OOOOOOOOOO  OOOOOO  OO
OOOOOO  OO  OOOOOOOOOO  OO  OOOOOO  OO  OOOOOOOOOO  OOOOOO  OOOOOOOOOO  OOOOOO  OO
OO  OO  OO          OO  OO      OO  OO  OO      OO      OO  OO          OO      OO
OO  OO  OO          OO  OO      OO  OO  OO      OO      OO  OO          OO      OO
OO  OO  OO  OOOOOOOOOO  OOOOOO  OO  OO  OO  OOOOOO  OO  OO  OOOOOO  OOOOOO  OOOOOO
OO  OO  OO  OOOOOOOOOO  OOOOOO  OO  OO  OO  OOOOOO  OO  OO  OOOOOO  OOOOOO  OOOOOO
OO  OO  OO              OO      OO  OO  OO          OO  OO      OO      OO  OO  OO
OO  OO  OO              OO      OO  OO  OO          OO  OO      OO      OO  OO  OO
OO  OO  OOOOOOOOOOOOOOOOOOOOOOOOOO  OO  OOOOOOOOOOOOOO  OOOOOO  OOOOOO  OO  OO  OO
OO  OO  OOOOOOOOOOOOOOOOOOOOOOOOOO  OO  OOOOOOOOOOOOOO  OOOOOO  OOOOOO  OO  OO  OO
OO                                  OO                  OO              OO      GG
OO                                  OO                  OO              OO      GG
OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO
OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO

通路部分だけ広い画面出力

通路の部分だけ2倍横長,縦長の画面出力を実現するクラス(ここでは,DisplayScreenPassageWideクラスと名付けます)を実装してみましょう. この時,他のクラスを一切変更してはいけません. (ヒント:出力時に奇数行,偶数行,奇数列,偶数列で出力方法を変えること)

出力例

OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO
S           O     O                 O              O     O  O
S           O     O                 O              O     O  O
O  OOOOOOO  O  O  O  O  OOOOOOOOOO  O  OOOOOOOOOO  O  O  O  O
O  O     O     O  O  O     O        O  O           O  O     O
O  O     O     O  O  O     O        O  O           O  O     O
OOOO  O  OOOOOOO  O  OOOO  O  OOOOOOO  OOOO  OOOOOOO  OOOO  O
O  O  O        O  O     O  O  O     O     O  O        O     O
O  O  O        O  O     O  O  O     O     O  O        O     O
O  O  O  OOOOOOO  OOOO  O  O  O  OOOO  O  O  OOOO  OOOO  OOOO
O  O  O           O     O  O  O        O  O     O     O  O  O
O  O  O           O     O  O  O        O  O     O     O  O  O
O  O  OOOOOOOOOOOOOOOOOOO  O  OOOOOOOOOO  OOOO  OOOO  O  O  O
O                          O              O           O     G
O                          O              O           O     G
OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO
ここまでのオプション課題の動作チェックのために,main.cppのselectDisplay関数を以下のように修正しましょう.

selectDisplay関数の修正

#include "DisplayScreenLong.h"
#include "DisplayScreenWideLong.h"
#include "DisplayScreenPassageWide.h"

Display *selectDisplay() {
    int outputMode;
    Display *display = NULL;
    do {
        std::cout << "output mode [1-9] ? ";
        std::cin >> outputMode;
        switch (outputMode) {
            case 1: display = new DisplayScreen; // 画面に出力
                break;
            case 2: display = new DisplayFile; // ファイルに出力
                break;
            case 3: display = new DisplayHtml; // HTMLファイルに出力
                break;
            case 4: display = new DisplayScreenWide; // 画面に横長に出力
                break;
            case 5: display = new DisplayFileWide; // ファイルに横長に出力
                break;
            case 6: display = new DisplayHtmlWide; // HTMLファイルに横長に出力
                break;
            case 7: display = new DisplayScreenLong; // 画面に縦長に出力
                break;
            case 8: display = new DisplayScreenWideLong; // 画面に横長・縦長に出力
                break;
            case 9: display = new DisplayScreenPassageWide; // 画面に通路だけ広く出力
                break;
            default:
                std::cout << "illegal output mode " << outputMode << std::endl;
                break;
        }
    } while (display == NULL);
    return display;
}

本式穴掘り法の実装

穴掘り法の本式の迷路作成クラス(ここでは,MazeMakerNormalと名付けます)を実装してみましょう. main.cppでMazeMakerSimpleと該当する箇所を書き換えて,動作を確認してみましょう.

迷路作成アルゴリズムの多態化

MazeMakerNormalクラスが実装できたら,迷路作成アルゴリズムを切り替えられるようにしてみましょう. 抽象クラスとして,以下のMazeMakerクラスを準備します. MazeMakerクラスはgenerateが純粋仮想関数として定義されています.

MazeMaker.h

#ifndef MAZEMAKER_H
#define MAZEMAKER_H

class MazeMaker {
public:
    virtual ~MazeMaker();
    virtual void generate() = 0;
};

#endif /* MAZEMAKER_H */

MazeMaker.cpp

#include "MazeMaker.h"

MazeMaker::~MazeMaker() {
}

MazeMakerSimpleクラスを以下のように抽象クラスMazeMakerクラスを継承するように修正します.

MazeMakerSimple.hの修正

#ifndef MAZEMAKERSIMPLE_H
#define MAZEMAKERSIMPLE_H

#include <cstdlib>
#include "MazeMap.h"
#include "MazeMaker.h"

class MazeMakerSimple : public MazeMaker {
public:
    /**
     * コンストラクタ
     * @param mazeMap MazeMapインスタンス
     */
    MazeMakerSimple(MazeMap *mazemap);
    /**
     * 迷路生成
     */
    virtual void generate();
private:
    /** MazeMapインスタンス */
    MazeMap *mazeMap;
    /**
     * 座標(x,y)において dで指定された方向をチェック
     * @param x x座標
     * @param y y座標
     * @param d 方向を示すインデックス
     */
    void checkDirection(int x, int y, int d);
    /**
     * 座標(x,y)において全方向をチェック
     * @param x x座標
     * @param y y座標
     */
    void checkPoint(int x, int y);
};

#endif /* MAZEMAKERSIMPLE_H */

MazeMakerNormalクラスも同様に,MazeMakerクラスを継承する形に書き換えてみましょう.
main.cppにselectDisplay関数を参考に,selectMazeMaker関数で迷路生成アルゴリズムを選択できるようにしています.

main.cppの修正(参考)

#include "MazeMaker.h"
#include "MazeMakerNormal.h"

/**
 * 迷路生成アルゴリズム選択
 * @param mazeMap マップ情報
 * @return MazeMakerインスタンスのポインタ
 */
MazeMaker *selectMazeMaker(MazeMap *mazeMap) {
    int makeMode;
    MazeMaker *mazeMaker = NULL;
    do {
        std::cout << "make mode [1-2] ? ";
        std::cin >> makeMode;
        switch (makeMode) {
            case 1: mazeMaker = new MazeMakerSimple(mazeMap);
                break;
            case 2: mazeMaker = new MazeMakerNormal(mazeMap);
                break;
            default:
                std::cout << "illegal make mode " << makeMode << std::endl;
                break;
        }
    } while (mazeMaker == NULL);
    return mazeMaker;
}

int main(int argc, char** argv) {
    // 乱数の初期化設定
    // 本来は実行する度に変化する時刻情報などを用いたほうが良いが,開発を容易に(実行の度に結果が変わらないように)するために,乱数の初期値を手動で設定し固定する
    int seed;
    std::cout << "seed ? ";
    std::cin >> seed;
    srand(seed); // 乱数種の設定

    // 迷路幅,迷路高の基底の設定
    int w, h;
    std::cout << "size (w, h) ? ";
    std::cin >> w >> h;

    // 迷路マップ情報生成
    MazeMap mazeMap(w, h);

    // 迷路作成
    MazeMaker *mazeMaker = selectMazeMaker(&mazeMap);
    mazeMaker->generate();

    // 迷路出力
    Display *display = selectDisplay();
    MazePrinter mazePrinter(display);
    mazePrinter.output(&mazeMap);

    // selectDisplay()内で生成したインスタンスを解放
    delete display;

    return 0;
}

他の迷路生成アルゴリズムの実装

穴掘り法以外の他の迷路生成アルゴリズムを調べて,MazeMakerクラスを継承する形で実装してみましょう. 実装した新しいクラスをselectMazeMaker関数の中で利用してみましょう.

迷路を解くアプリケーションの実装

コンピュータが自動的に生成した迷路を,コンピュータに解かせ,その解を表示するアプリケーションを実装しましょう.

その他

迷路アプリケーションの新しい機能を自分で考えて,実装してみましょう.

提出

注意事項

スケジュール