C++での迷路表示プログラムについて

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
kaya

C++での迷路表示プログラムについて

#1

投稿記事 by kaya » 4年前

### 前提・実現したいこと
C++で迷路を作成し、ファイル出力をするプログラムを作成しています。
このプログラムを実行中に例外がスローされ、正しく実行が行われません。

### 発生している問題・エラーメッセージ
main.cpp28行目
により ハンドルされない例外が 0x003AD509 (p3k4_1.exe) で発生しました: 0xC00000FD: Stack overflow (パラメーター: 0x00000001, 0x00C72FFC)。 が発生しました

### 該当のソースコード

コード:

// main.cpp
#include "MazeMap.h"
#include <iostream>
MazeMap::MazeMap(int w, int h) {
    width = 2 * w + 1;
    height = 2 * h + 1;
    data = new char* [width];
    for (int i = 0; i < width; ++i) {
        data[i] = new char[height];
    }
}

MazeMap::~MazeMap() {
    for (int i = 0; i < width; ++i) {
        delete[] data[i];
    }
    delete[] data;
}


int MazeMap::getWidth() {
    return width;
}

int MazeMap::getHeight() {
    return height;
}

bool MazeMap::isInside(int x, int y) {
    if ((0 <= x) && (x < width) && (0 <= y) && (y < height)) {
        //std::cout << "Inside true" << std::endl;
        return true;
    } else {
        //std::cout << "Inside false" << std::endl;
        return false;
    }
}

bool MazeMap::isWall(int x, int y) {
    if (isInside(x, y) == false) {
        return false;
    }
    if (**data == wall) {
        return true;
    } else {
        return false;
    }
}

bool MazeMap::set(int x, int y, char c) {
    if (isInside(x, y) == true) {
        //std::cout << "Set true" << std::endl;
        data[x][y] = c;
        return true;
    } else {
        //std::cout << "Set false" << std::endl;
        return false;
    }
}

char MazeMap::get(int x, int y) {
    return data[x][y];
}

void MazeMap::clear() {
    for (int i = 0; i < width; i++) {
        for (int j = 0; j < height; j++)
            data[i][j] = wall;
    }
}



//MaseMakerSimple.cpp
#include "MazeMakerSimple.h"

MazeMakerSimple::MazeMakerSimple(MazeMap* mazeMap) {
    this->mazeMap = mazeMap;
}

void MazeMakerSimple::generate() {
    mazeMap->clear();

    // ランダムに迷路作成開始地点を選択(ただし,奇数座標)
    int x = rand() % (mazeMap->getWidth() / 2) * 2 + 1;
    int y = rand() % (mazeMap->getHeight() / 2) * 2 + 1;

    // (x,y)の座標から迷路の作成開始
    checkPoint(x, y);

    // 左上にスタート地点、右下にゴール地点を置いて終了
    mazeMap->set(0, 1, mazeMap->start);
    mazeMap->set(mazeMap->getWidth() - 1, mazeMap->getHeight() - 2, mazeMap->goal);
}

void MazeMakerSimple::checkDirection(int x, int y, int d) {
    // 4つの方向を示す構造体    

    static const struct pos {
        int x, y;
    } steps[] = {
        {0, +1}, // 下
        {+1, 0}, // 右
        {0, -1}, // 上    
        {-1, 0} // 左
    };

    // 引数dの値により,steps[]で示される方向の1つを決定
    int dx = steps[d & 3].x;
    int dy = steps[d & 3].y;

    if (mazeMap->isWall(x + 2 * dx, y + 2 * dy)) { // 指定された方向の2マス先が壁であれば
        mazeMap->set(x + dx, y + dy); // その方向の1マス先を通路にセット
        mazeMap->set(x + 2 * dx, y + 2 * dy); // その方向の2マス先を通路にセット
        // 注目点を2マス先に移して,チェックを継続
        checkPoint(x + 2 * dx, y + 2 * dy);
    }
}

void MazeMakerSimple::checkPoint(int x, int y) {
    if (!mazeMap->isInside(x, y)) { // 迷路の範囲外なら
        return;
    }
    // 指定座標を通路にセット
    mazeMap->set(x, y);

    // 探索する方向を乱数で設定
    int d = rand();
    // 再探索の順番を設定(時計回り or 反時計回り)
    int dd = (rand() & 1) * 2 - 1; // -1 or +1 

    // 4方向に通路が延ばせるか順番にチェック
    for (int i = 0; i < 4; ++i) {
        checkDirection(x, y, d);
        d += dd;
    }
}

//MazeMap.cpp
#include "MazeMap.h"
#include <iostream>
MazeMap::MazeMap(int w, int h) {
    width = 2 * w + 1;
    height = 2 * h + 1;
    data = new char* [width];
    for (int i = 0; i < width; ++i) {
        data[i] = new char[height];
    }
}

MazeMap::~MazeMap() {
    for (int i = 0; i < width; ++i) {
        delete[] data[i];
    }
    delete[] data;
}


int MazeMap::getWidth() {
    return width;
}

int MazeMap::getHeight() {
    return height;
}

bool MazeMap::isInside(int x, int y) {
    if ((0 <= x) && (x < width) && (0 <= y) && (y < height)) {
        //std::cout << "Inside true" << std::endl;
        return true;
    } else {
        //std::cout << "Inside false" << std::endl;
        return false;
    }
}

bool MazeMap::isWall(int x, int y) {
    if (isInside(x, y) == false) {
        return false;
    }
    if (**data == wall) {
        return true;
    } else {
        return false;
    }
}

bool MazeMap::set(int x, int y, char c) {
    if (isInside(x, y) == true) {
        //std::cout << "Set true" << std::endl;
        data[x][y] = c;
        return true;
    } else {
        //std::cout << "Set false" << std::endl;
        return false;
    }
}

char MazeMap::get(int x, int y) {
    return data[x][y];
}

void MazeMap::clear() {
    for (int i = 0; i < width; i++) {
        for (int j = 0; j < height; j++)
            data[i][j] = wall;
    }
}

//MazePrinter.cpp
#include "MazePrinter.h"

MazePrinter::MazePrinter(Display* display) {
    this->display = display;
}

void MazePrinter::output(MazeMap* mazeMap) {
    display->start(); // 表示前処理
    for (int y = 0; y < mazeMap->getHeight(); ++y) {
        for (int x = 0; x < mazeMap->getWidth(); ++x) {
            display->put(mazeMap->get(x, y)); // 1文字表示処理
        }
        display->newLine(); // 改行処理
    }
    display->end(); //  表示後処理
}


//Display.cpp
#include "Display.h"
Display::~Display() {
}


//DisplayScreen.cpp
#include "DisplayScreen.h"

void DisplayScreen::start() {
}

void DisplayScreen::end() {
}

void DisplayScreen::put(char c) {
    stream() << c;
}

void DisplayScreen::newLine() {
    stream() << std::endl;
}

std::ostream& DisplayScreen::stream() {
    return std::cout;
}

//DisplayFile.cpp
#include "DisplayFile.h"

DisplayFile::DisplayFile(const char* fileName) {
    /* ここを実装してください */
    fp = fopen(fileName, "w");
}

DisplayFile::~DisplayFile() {
    /* ここを実装してください */
    fclose(fp);
}

std::ostream& DisplayFile::stream() {
    return ofs;
}
```
####DisplayFileWide.cpp
```c++
#include "DisplayFileWide.h"

void DisplayFileWide::put(char c) {
    /* ここを実装してください */
    stream() << c;
}


//MaseMakerSimple.h
#ifndef MAZEMAKERSIMPLE_H
#define MAZEMAKERSIMPLE_H

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

class MazeMakerSimple {
public:
    /**
     * コンストラクタ
     * @param mazeMap MazeMapインスタンス
     */
    MazeMakerSimple(MazeMap* mazeMap);
    /**
     * 迷路生成
     */
    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 */


//MazeMap.h
#ifndef MAZEMAP_H
#define MAZEMAP_H

/**
 * @class MazeMap
 * @breif 迷路情報保持用クラス
 */
class MazeMap {
public:
    /** 「壁」の表示 */
    static const char wall = 'O';
    /** 「通路」の表示 */
    static const char passage = ' ';
    /** 「スタート地点」の表示 */
    static const char start = 'S';
    /** 「ゴール地点」の表示 */
    static const char goal = 'G';

    /**
     * コンストラクタ
     * @param w 迷路幅の基底
     * @param h 迷路高の基底
     * @attention 実際の迷路幅は2w+1,迷路高は2h+1
     */
    MazeMap(int w, int h);

    /**
     *  デストラクタ
     */
    virtual ~MazeMap();

    /**
     * 迷路幅用ゲッタ
     * @return 迷路幅
     */
    int getWidth();

    /**
     * 迷路高用ゲッタ
     * @return 迷路高
     */
    int getHeight();

    /**
     * @retval true 迷路の範囲内
     * @retval false 迷路の範囲外
     */
    bool isInside(int x, int y);

    /**
     * @retval true 壁
     * @retval false 壁でない
     * @attention 指定座標が迷路範囲外であればfalseを返す
     */
    bool isWall(int x, int y);

    /**
     * 指定座標のマップ情報のセッタ
     * @param c 要素
     * @retval true 迷路の範囲内
     * @retval false 迷路の範囲外
     * @attention 要素を指定しない場合,通路とする
     */
    bool set(int x, int y, char c = passage);

    /**
     * 指定座標のマップ情報のゲッタ
     * @return マップ情報
     * @attention 迷路範囲外の座標を指定した場合,'\0'を返す
     */
    char get(int x, int y);

    /**
     * マップ情報の初期化
     * @attention 全ての要素を「壁」にする
     */
    void clear();
private:
    /** 迷路幅 */
    int width;
    /** 迷路高 */
    int height;
    /** 迷路情報 */
    char** data;
};

#endif /* MAZEMAP_H */

//MazePrinter.h
#ifndef MAZEPRINTER_H
#define MAZEPRINTER_H

#include "Display.h"
#include "MazeMap.h"

class MazePrinter {
public:
    /**
     * コンストラクタ
     * @param display Displayインスタンスのポインタ
     */
    MazePrinter(Display* display);
    /**
     * 出力
     * @param mazeMap MazeMapインスタンスのポインタ
     */
    virtual void output(MazeMap* mazeMap);
private:
    /** Displayインスタンスのポインタ*/
    Display* display;
};

#endif /* MAZEPRINTER_H */


//Display.h
#ifndef DISPLAY_H
#define DISPLAY_H

#include <ostream>

class Display {
public:
    /**
     * デストラクタ
     */
    virtual ~Display();
    /**
     * 表示前処理(純粋仮想関数)
     */
    virtual void start() = 0;
    /**
     * 表示後処理(純粋仮想関数)
     */
    virtual void end() = 0;
    /**
     * 1文字出力処理 (純粋仮想関数)
     * @param c 出力文字
     */
    virtual void put(char c) = 0;
    /**
     * 改行処理(純粋仮想関数)
     */
    virtual void newLine() = 0;
protected:
    /**
     * 出力先の参照(純粋仮想関数)
     * @return 出力先の参照
     */
    virtual std::ostream& stream() = 0;
};

#endif /* DISPLAY_H*/


//DisplayScreen.h
#ifndef DISPLAYSCREEN_H
#define DISPLAYSCREEN_H

#include <iostream>
#include "Display.h"

class DisplayScreen : public Display {
public:
    virtual void start();
    virtual void end();
    virtual void put(char c);
    virtual void newLine();
protected:
    virtual std::ostream& stream();
};

#endif /* DISPLAYSCREEN_H */


//DisplayFile.h
#ifndef DISPLAYFILE_H
#define DISPLAYFILE_H

#include <fstream>
#include "DisplayScreen.h"

class DisplayFile : public DisplayScreen {
public:
    DisplayFile(const char* fileName = "output.txt");

    virtual ~DisplayFile();
protected:
    virtual std::ostream& stream();
private:
    std::ofstream ofs;
    FILE* fp;
};

#endif /* DISPLAYFILE_H */


//DisplayFileWide.h
#ifndef DISPLAYFILEWIDE_H
#define DISPLAYFILEWIDE_H

#include "DisplayFile.h"

class DisplayFileWide : public DisplayFile {
public:
    virtual void put(char c);
};

#endif /* DISPLAYFILEWIDE_H */
### 補足情報
VisualStudio2019
ソースファイルは//でコメントアウトして分けてあります。
DisplayFileWideは一つの壁を"00"と、通路を"  "(スペース二つ)で表現したものです。
DisplayFileとDisplayFileWideの"ここを実装してください"とある部分になにかしらの問題があるのだと踏んでいます。また、DisplayFileクラスでfpを宣言していますが、それを使わなく実装できるのであればそうしたいです。

kayaa

Re: C++での迷路表示プログラムについて

#2

投稿記事 by kayaa » 4年前

補足です。例外エラーが発生しているのはMazeMapクラスのisInside関数内であるので、if文の条件式の作り方に何らかの問題があるのではないかと思うのですが、、、

アバター
いわん
記事: 32
登録日時: 9年前

Re: C++での迷路表示プログラムについて

#3

投稿記事 by いわん » 4年前

main.cpp の内容が MazeMap.cpp の内容と同じですね。そして main 関数がありません。
main.cpp の内容が間違ってるのでは?

返信

“C言語何でも質問掲示板” へ戻る