ダンジョンの自動生成について

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
華風えくれあ
記事: 25
登録日時: 13年前
住所: 岐阜県大垣市
連絡を取る:

ダンジョンの自動生成について

#1

投稿記事 by 華風えくれあ » 13年前

こちらのコード( Racanhackコード解説様 http://racanhack.sourceforge.jp/rhdoc/index.html
を参考にしながらvectorなどに置き換えてコードを書いてみました。

それで実行してみたのですが、イレテーターが不正?のようなアサートウィンドウが出ました。
無理してスマートポインタなどを組み込んで実行しているのでそのせいかもしれません・・・。

どこかおかしい点は見受けられるでしょうか?ご教授お願いします。

長くなるのでスポイラーで。
► スポイラーを表示
最後に編集したユーザー 華風えくれあ on 2012年5月17日(木) 00:16 [ 編集 1 回目 ]

アバター
h2so5
副管理人
記事: 2212
登録日時: 14年前
住所: 東京
連絡を取る:

Re: ダンジョンの自動生成について

#2

投稿記事 by h2so5 » 13年前

84行目のスマートポインタはNULLポインタなのでアクセスできませんね。
あと、89行目の「イテレーターから代入できなかったため」とはどういうことでしょうか?

華風えくれあ
記事: 25
登録日時: 13年前
住所: 岐阜県大垣市
連絡を取る:

Re: ダンジョンの自動生成について

#3

投稿記事 by 華風えくれあ » 13年前

h2so5 さんが書きました:84行目のスマートポインタはNULLポインタなのでアクセスできませんね。
あと、89行目の「イテレーターから代入できなかったため」とはどういうことでしょうか?
あぁ・・・領域作るの忘れていました・・・。

それぞれに代入するための4行を書く前に、
make_sharedで行っていたのですが、謎のコンパイルエラー・・・。
以前vectorやスマートポインタ関係で書き間違い起こすと場所がどこだかわからなくなるというのがあり、
まさにそのことが起きましたので、一つ一つでいいかなと・・・。

少し書き直してみます。

華風えくれあ
記事: 25
登録日時: 13年前
住所: 岐阜県大垣市
連絡を取る:

Re: ダンジョンの自動生成について

#4

投稿記事 by 華風えくれあ » 13年前

123行目を削除したら、アサートは消えてくれました。
ですが、やはりどこかで処理が止まってしまいます。

領域は確保済みです。

アバター
h2so5
副管理人
記事: 2212
登録日時: 14年前
住所: 東京
連絡を取る:

Re: ダンジョンの自動生成について

#5

投稿記事 by h2so5 » 13年前

では、どこで止まるか特定してください。

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 14年前
住所: 東海地方
連絡を取る:

Re: ダンジョンの自動生成について

#6

投稿記事 by softya(ソフト屋) » 13年前

華風えくれあ さんが書きました:123行目を削除したら、アサートは消えてくれました。
ですが、やはりどこかで処理が止まってしまいます。

領域は確保済みです。
デバッガで止まった場所は特定できるはずです。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

華風えくれあ
記事: 25
登録日時: 13年前
住所: 岐阜県大垣市
連絡を取る:

Re: ダンジョンの自動生成について

#7

投稿記事 by 華風えくれあ » 13年前

softya(ソフト屋) さんが書きました:
華風えくれあ さんが書きました:123行目を削除したら、アサートは消えてくれました。
ですが、やはりどこかで処理が止まってしまいます。

領域は確保済みです。
デバッガで止まった場所は特定できるはずです。
デバッガの使い方がわからないのでちょっと勉強がいるかな・・・と思いました。
返信より先に自分で解決できましたのでご報告いたします。

原因は、ダムポインタとスマートポインタの混在でした。
なので種類の違う値が入り混じってしまい動作が停止したんだと思います。

なので、戻り値・引数をすべてスマートポインタで返すようにしてみました。
► スポイラーを表示
区画に対して1を代入する部分は少し休憩してから行いたいと思います。
最後に編集したユーザー 華風えくれあ on 2012年5月17日(木) 00:16 [ 編集 1 回目 ]

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 14年前
住所: 東海地方
連絡を取る:

Re: ダンジョンの自動生成について

#8

投稿記事 by softya(ソフト屋) » 13年前

何処かよくわからない場所で落ちた場合は、呼び出し履歴ウィンドウを使います。
「Visual Studio 2008での呼び出し履歴の表示 - 酢ろぐ(ch3cooh.jp)」
http://d.hatena.ne.jp/ch3cooh393/20100902/1283425268
「【ハウツー】最初にマスターしたいVisual Studioのデバッグ機能 - 応用編 (2) 呼び出し履歴ウィンドウ/ビジュアライザ | エンタープライズ | マイナビニュース」
http://news.mynavi.jp/articles/2008/08/ ... g/001.html
 ↑ C#の説明なので途中までしか参考にはなりませんが。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

華風えくれあ
記事: 25
登録日時: 13年前
住所: 岐阜県大垣市
連絡を取る:

Re: ダンジョンの自動生成について

#9

投稿記事 by 華風えくれあ » 13年前

すいません・・・かなり危ないところを間違えていました・・・。
イテレーターから参照して代入の部分でエラーが出ていたのではなく、
下のfor文のところでした。

ここをコメントアウトしたとき実行したら右上に不正な#があったのでデバッグしてみたところ、
map_iのi分が40しかなかったのであれ?と思って宣言を見てみたらMAP_WIDTHとMAP_HEIGHTが
逆でした^^;

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 14年前
住所: 東海地方
連絡を取る:

Re: ダンジョンの自動生成について

#10

投稿記事 by softya(ソフト屋) » 13年前

そういう間違いが起きるのは、
(1)int map_i[MAP_HEIGHT][MAP_WIDTH];
と定義しているからです。
(2)int map_i[MAP_WIDTH][MAP_HEIGHT];
とすれば間違うことはないはずです。

(1) の形で定義して便利なのは、直接マップデータを数値定義するときで自動生成の場合は無意味ですのでバグを減らすためにも(2)であるべきです。
あと、i,jと言う変数名もミスを誘発しやすいのでx,yを使うべきでしょう。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

華風えくれあ
記事: 25
登録日時: 13年前
住所: 岐阜県大垣市
連絡を取る:

Re: ダンジョンの自動生成について

#11

投稿記事 by 華風えくれあ » 13年前

softya(ソフト屋) さんが書きました:そういう間違いが起きるのは、
(1)int map_i[MAP_HEIGHT][MAP_WIDTH];
と定義しているからです。
(2)int map_i[MAP_WIDTH][MAP_HEIGHT];
とすれば間違うことはないはずです。

(1) の形で定義して便利なのは、直接マップデータを数値定義するときで自動生成の場合は無意味ですのでバグを減らすためにも(2)であるべきです。
あと、i,jと言う変数名もミスを誘発しやすいのでx,yを使うべきでしょう。
ありがとうございます。
宣言時から間違っていたので気づくのに遅れてしまったんでしょう・・・、以後気を付けます。

さて、何事もなく表示はされるようになりました。
ですが、作られた枠が一つもなくなってしまいました。

デバッグしてもデータは分割されているようです、
どこが問題かわかりません・・・。
ここら辺が正しくないなど指摘していただけないでしょうか。

コード:

#include <cstdio>
#include <cstdlib>
#include <ctime>
#include <vector>
#include <memory>
#include <iterator>

#define MAP_WIDTH	50
#define	MAP_HEIGHT	40

#define	MIN_ROOM	4
#define MAX_ROOM	6
#define MIN_RECT	8
#define MAX_RECT	NULL

#define Rand(MIN,MAX) rand()%MAX+MIN

int map_i[MAP_WIDTH][MAP_HEIGHT];

struct rect_s
{
	int lx,ly,hx,hy;
};// 区画情報構造体

std::vector<std::shared_ptr<rect_s>> rect_list;



std::shared_ptr<rect_s> rect_add(int lx,int ly,int hx,int hy)
{
	std::shared_ptr<rect_s> rect(new rect_s);
	rect->lx = lx;
	rect->ly = ly;
	rect->hx = hx;
	rect->hy = hy;
	rect_list.push_back(rect);
	return(rect);
}

void rect_split(std::shared_ptr<rect_s> &rect_parent)
{
	std::shared_ptr<rect_s> rect_child;
	int split_coord;

	if((rect_parent->hy - rect_parent->ly <= MIN_RECT*2) ||
		(rect_parent->hx - rect_parent->lx <= MIN_RECT*2) )
	{ return ; }
	
	// 子区画にコピー
	rect_child = rect_add(rect_parent->lx, rect_parent->ly,rect_parent->hx,rect_parent->hy);
	if(Rand(0,2)==0)
	{
		split_coord = Rand(rect_parent->ly + MIN_RECT, rect_parent->hy - MIN_RECT);
		rect_parent->hy = split_coord;
		rect_child->ly  = split_coord;
		rect_split(rect_parent);
		rect_split(rect_child);
		return;
	}
	else
	{
		split_coord = Rand(rect_parent->lx + MIN_RECT, rect_parent->hx - MIN_RECT);
		rect_parent->hx = split_coord;
		rect_child->lx		= split_coord;
		rect_split(rect_parent);
		rect_split(rect_child);
		return;
	}
}

// 描画処理
void map_print( void )
{
	int x,y;

	std::shared_ptr<rect_s> rect(new rect_s);

	// コンテナの中身をコピー
	for(auto it = rect_list.begin();it == rect_list.end();++it)
	{
		// 一つずつ行う
		rect->lx = it->get()->lx;
		rect->ly = it->get()->ly;
		rect->hx = it->get()->hx;
		rect->hy = it->get()->hy;

		for(x = rect->lx, y = rect->ly; x <= rect->hx; x++){ map_i[x][y] = 1; }
		for(x = rect->lx, y = rect->hy; x <= rect->hx; x++){ map_i[x][y] = 1; }
		for(x = rect->lx, y = rect->ly; x <= rect->hy; y++){ map_i[x][y] = 1; }
		for(x = rect->hx, y = rect->ly; x <= rect->hy; y++){ map_i[x][y] = 1; }
	}

	// 配列の中身をすべて調べ、0以外であれば#を書く
	for(y=0;y<MAP_HEIGHT;y++)
	{
		for(x=0;x<MAP_WIDTH;x++)
		{
			if(map_i[x][y]!=0){ printf("#"); }
			else			  { printf("."); }
		}
		printf("\n");
	}
}

int main(void)
{
	srand((unsigned)time(NULL));

	int i,j;
	for(j=0;j<MAP_HEIGHT;j++)
	{
		for(i=0;i<MAP_WIDTH;i++)
		{
			map_i[i][j] = 0;
		}
	}
	rect_split(rect_add(0,0,MAP_WIDTH-1,MAP_HEIGHT));
	
	map_print();
	return 0;
}

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 14年前
住所: 東海地方
連絡を取る:

Re: ダンジョンの自動生成について

#12

投稿記事 by softya(ソフト屋) » 13年前

gcc 4.3.4でg++ -std=c++0xでコンパイルエラーですが環境は何でしょうか?
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

beatle
記事: 1281
登録日時: 13年前
住所: 埼玉
連絡を取る:

Re: ダンジョンの自動生成について

#13

投稿記事 by beatle » 13年前

ぱっと見

コード:

for(auto it = rect_list.begin();it == rect_list.end();++it)
この行でit == rect_list.end()としているのが気になります。このfor文は一回も実行されませんよ。

beatle
記事: 1281
登録日時: 13年前
住所: 埼玉
連絡を取る:

Re: ダンジョンの自動生成について

#14

投稿記事 by beatle » 13年前

それから、

コード:

rect->lx = it->get()->lx;
はせっかくスマートポインタを使っていますから、生ポインタを取り出してlxにアクセスするのではなくて

コード:

rect->lx = (*it)->lx;
とする方がいいでしょうね。

華風えくれあ
記事: 25
登録日時: 13年前
住所: 岐阜県大垣市
連絡を取る:

Re: ダンジョンの自動生成について

#15

投稿記事 by 華風えくれあ » 13年前

softya(ソフト屋) さんが書きました:gcc 4.3.4でg++ -std=c++0xでコンパイルエラーですが環境は何でしょうか?
環境はVC++2010Express版です。
beatle さんが書きました:ぱっと見

コード:

for(auto it = rect_list.begin();it == rect_list.end();++it)
この行でit == rect_list.end()としているのが気になります。このfor文は一回も実行されませんよ。
なんと・・・、見落としてました、申し訳ないです。
beatle さんが書きました:それから、

コード:

rect->lx = it->get()->lx;
はせっかくスマートポインタを使っていますから、生ポインタを取り出してlxにアクセスするのではなくて

コード:

rect->lx = (*it)->lx;
とする方がいいでしょうね。
ありがとうございます、書き換えてみました。

これでデバッグしてみると、for文に不定期でアクセスエラーが起きてしまってます。
評価式がおかしいのでしょうか・・・。

コード:


/* map_print( void ) 改変点 */
	int x,y;

	std::shared_ptr<rect_s> rect(new rect_s);

	// コンテナの中身をコピー
	for(auto it = rect_list.begin();it < rect_list.end();++it)
	{
		// 一つずつ行う
		rect->lx = (*it)->lx;
		rect->ly = (*it)->ly;
		rect->hx = (*it)->hx;
		rect->hy = (*it)->hy;

		for(x = rect->lx, y = rect->ly; x <= rect->hx; x++){ map_i[x][y] = 1; }
		for(x = rect->lx, y = rect->hy; x <= rect->hx; x++){ map_i[x][y] = 1; }
		for(x = rect->lx, y = rect->ly; y <= rect->hy; y++){ map_i[x][y] = 1; }
		for(x = rect->hx, y = rect->ly; y <= rect->hy; y++){ map_i[x][y] = 1; }
	}

beatle
記事: 1281
登録日時: 13年前
住所: 埼玉
連絡を取る:

Re: ダンジョンの自動生成について

#16

投稿記事 by beatle » 13年前

コード:

for(auto it = rect_list.begin();it < rect_list.end();++it)
これもおかしいですよ。いや、rect_listがstd::vectorだということを前提にしているならいいのですが、普通は

コード:

for(auto it = rect_list.begin();it != rect_list.end();++it)
というように、イテレータとend()の比較は!=を使います。
!=を使っておけば、rect_listがどんな型でも処理できます。これこそイテレータを使う価値があるというものです。

「アクセスエラー」というのは、具体的にどの部分でどんなエラーが出ますか?for文と言っても、外側のfor文には初期化部、条件部、更新部、実行される文と、大きく4つありますね。文の中にはまた8行の文が含まれます。

華風えくれあ
記事: 25
登録日時: 13年前
住所: 岐阜県大垣市
連絡を取る:

Re: ダンジョンの自動生成について

#17

投稿記事 by 華風えくれあ » 13年前

beatle さんが書きました: 「アクセスエラー」というのは、具体的にどの部分でどんなエラーが出ますか?for文と言っても、外側のfor文には初期化部、条件部、更新部、実行される文と、大きく4つありますね。文の中にはまた8行の文が含まれます。
おそらく、更新部のところだと思います。
デバッグでは最初の中括弧で停止しました。ですので、インクリメント直後にエラーが出たんだと思います。
外のfor文は何回か実行していたので要素数は0ではないのですが、なぜEnd()で止まってくれないのでしょうか・・・。

追記:
it != rect_list.End()には書き換えておきました。

beatle
記事: 1281
登録日時: 13年前
住所: 埼玉
連絡を取る:

Re: ダンジョンの自動生成について

#18

投稿記事 by beatle » 13年前

華風えくれあ さんが書きました:
beatle さんが書きました: 「アクセスエラー」というのは、具体的にどの部分でどんなエラーが出ますか?for文と言っても、外側のfor文には初期化部、条件部、更新部、実行される文と、大きく4つありますね。文の中にはまた8行の文が含まれます。
おそらく、更新部のところだと思います。
デバッグでは最初の中括弧で停止しました。ですので、インクリメント直後にエラーが出たんだと思います。
外のfor文は何回か実行していたので要素数は0ではないのですが、なぜEnd()で止まってくれないのでしょうか・・・。

追記:
it != rect_list.End()には書き換えておきました。
大文字、小文字はC++では区別されますから注意してくださいね。

具体的なエラーメッセージなどは出ませんでしたか?
それから、なぜend()で止まっていないことが判明したのでしょうか。
for文がrect_list.size()回より多くループしていることをチェックした、とかでしょうか。

for文の条件部分に、for文のループ回数がrect_list.size()以下になっていることをチェックする式を追加したらどうでしょうか。

コード:

size_t count = 0;
for(auto it = rect_list.begin();it != rect_list.end() && count < rect_list.size();++it, ++count)
という感じに。

閉鎖

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