質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
87.20%
C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

解決済

ダンジョンマップ生成アルゴリズムで乱数を微調整する方法が知りたい

samidare_chan
samidare_chan

総合スコア142

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

1回答

-6評価

0クリップ

379閲覧

投稿2022/05/05 03:50

編集2022/05/05 15:07

提示コードはダンジョンマップ生成アルゴリズムなのですが参考サイトよりステージを縦横に分割する処理を実装しているのですが乱数のばらまきをもう少し調整したいのですがこの場合どうやって調整するべきなのでしょうか?現状だと提示画像のように6回分割を行っており5以上でエリアの最大値より5小さいという制限をかけて乱数を取得していますが提示画像のように乱数の値がバラバラすぎて区画が大きいのと小さいのとで不揃いになってしまいます。どう調整すればまんべんなく区画を生成できるのでしょうか?
Generate_Dungeon.cppソースファイルのvoid Generate_Dungeon::SetLine_X(int posY)関数部ですがvoid Generate_Dungeon::setGenerate()関数で乱数を設定しています。

参考サイト:http://rainbowvortex.blog.fc2.com/blog-entry-127.html

イメージ説明

Generate_Dungeon.cpp

cpp

#include "../header/Generate_Dungeon.hpp" #include "../../FrameWork/header/FrameWork.hpp" #include <glm/glm.hpp> // ##################################### コンストラクタ ##################################### Generate_Dungeon::Generate_Dungeon(glm::ivec2 s,glm::ivec2 div = glm::ivec2(0,0)) { setDivisionNum_X(div.x); setDivisionNum_Y(div.y); //printf("%d\n",s.y); allSize = s; stage.resize(s.x * s.y); area.resize(0); area.push_back(Area { s.x * s.y,glm::ivec2(0,0),s }); } // ##################################### ステージ再設定 ##################################### void Generate_Dungeon::setReSetStage(glm::ivec2 s,glm::ivec2 div) { setDivisionNum_X(div.x); setDivisionNum_Y(div.y); allSize = s; stage.resize(s.x * s.y); area.resize(0); area.push_back(Area { s.x * s.y,glm::ivec2(0,0),s }); } // ##################################### 一番大きいエリアを削除 ##################################### void Generate_Dungeon::DeleteMaxArea() { Area map = Area{0,glm::ivec2(0,0),glm::ivec2(allSize.x,allSize.y)}; int i = 0; int num = -1; for(std::vector<Area>::iterator itr = area.begin(); itr != area.end(); itr++) { if(map.size < itr->size) { map = *itr; num = i; // std::cout<<map.size<<std::endl; } i++; } if(num != -1) { area.erase(area.begin() + num); } else { std::cout<< "Error: 削除するエリアがありません。"<<std::endl; } } // ##################################### 一番大きいエリアを取得 ##################################### Generate_Dungeon::Area Generate_Dungeon::GetMaxArea() { Area map = Area{0,glm::ivec2(0,0),glm::ivec2(0,0)}; for(std::vector<Area>::iterator itr = area.begin(); itr != area.end(); itr++) { if(map.size < itr->size) { map = *itr; std::cout<<" map.start.y: " << map.start.y<<std::endl; // std::cout<<map.size<<std::endl; } // std::cout<<" map.start.y: " << map.start.y<<std::endl; } std::cout<<"return map.start.y: " << map.start.y<<std::endl; // std::cout<<std::endl; // std::cout<<std::endl; // std::cout<<std::endl; return map; } // ##################################### エリアに値を設定 ##################################### void Generate_Dungeon::SetArea(glm::ivec2 start,glm::ivec2 size,byte b) { for(int y = start.y; y < start.y + size.y; y++) { for(int x = start.x; x < start.x + size.x; x++) { // std::cout<<((y * allSize.x) + x)<<std::endl; stage.at((y * allSize.x) + x) = b; } } } // ##################################### X軸からYの長さを取得 ##################################### /* 説明 マス目の数を返す */ int Generate_Dungeon::GetCheckLine_Y(glm::ivec2 start,int posX) { //std::cout<<( (allSize.x * start.y) + start.x + posX - 1)<<std::endl; byte b = stage.at( (allSize.x * start.y) + start.x + posX); int y = 0; for(int i = start.y; i < allSize.y; i++) { //std::cout<<( (allSize.x * i + start.x) + posX)<<std::endl; if(stage.at( (allSize.x * i + start.x) + posX) != b) { return y; } y++; } return y; } // ##################################### Y軸からXの長さを取得 ##################################### int Generate_Dungeon::GetCheckLine_X(glm::ivec2 start,int posY) { //std::cout<<"aaaaaaa "<< (allSize.x * (start.y + posY) ) + start.x -1 <<std::endl; byte b = stage.at( (allSize.x * (start.y + posY) ) + start.x - 1); int x = 0; for(int i = start.x; i < allSize.x; i++) { // std::cout<<(allSize.x * posY) + i<<std::endl; if(stage.at( (allSize.x * posY) + i) != b) { return x; } x++; } return x; } // ##################################### ステージに値を設定 ##################################### void Generate_Dungeon::SetStage(glm::ivec2 start,glm::ivec2 pos,byte b) { stage.at((allSize.x * (pos.y + start.y)) + pos.x + start.x) = b; } // ##################################### ステージに値を取得 ##################################### byte Generate_Dungeon::GetStage(glm::ivec2 start,glm::ivec2 pos) { return stage.at((allSize.x * (pos.y + start.y)) + pos.x + start.x); } // ##################################### X軸に分割ラインを引く ##################################### void Generate_Dungeon::SetLine_X(int posY) { // std::cout<<"posY: " << posY<<std::endl; Area map = GetMaxArea(); //一番大きいエリアを取得 DeleteMaxArea(); //一番大きいエリアを削除 // printf("allSize.y: %d\n",posY); int rangeX = GetCheckLine_X(map.start,posY); //X軸のマス目の個数を取得 SetArea(map.start,glm::ivec2(rangeX,posY),flag); //範囲に値を設定 glm::ivec2 s = glm::ivec2(map.end.y - map.start.y,map.end.x - map.start.x); area.push_back(Area{ rangeX * posY,map.start,glm::ivec2(map.start.x + rangeX,map.start.y + posY) }); //エリアを追加 flag++; // std::cout<<"posY: " << posY<<std::endl; int y = GetCheckLine_Y(map.start + glm::ivec2(0,posY),0); //乱数のY軸から範囲の下までの個数を得る std::cout<<"posY: " << posY<<std::endl; std::cout<<"y: " << y<<std::endl; // std::cout<< (map.start + glm::ivec2(rangeX,posY)).x<<std::endl; // std::cout<< (map.start + glm::ivec2(rangeX,posY)).y<<std::endl; SetArea(map.start + glm::ivec2(0,posY),glm::ivec2(rangeX,y),flag); //範囲に値を設定 area.push_back(Area{ s.x * s.y,map.start + glm::ivec2(0,posY),glm::ivec2(map.start.x + rangeX,map.start.y + posY + y - 1) }); //エリアを追加 std::cout<<"map.start.y + posY + y - 1: " << map.start.y + posY + y - 1<<std::endl; //std::cout<<allSize.y<<std::endl; //std::cout<<GetMaxArea().end.y <<std::endl; //std::cout<<GetMaxArea().start.x <<std::endl; flag++; } // ##################################### Y軸に分割ラインを引く ##################################### void Generate_Dungeon::SetLine_Y(int pos) { } // ##################################### ステージを生成 ##################################### void Generate_Dungeon::setGenerate() { //std::cout<<divsion_X<<std::endl; for(int i = 0; i< 6; i++) { Area map = GetMaxArea(); //std::cout<<"map.end.y: " <<map.end.y<<std::endl; //std::cout<<"map.end.X: " <<map.end.x<<std::endl; // std::cout<<map.end.y - map.start.y<<std::endl; //printf("random : %d\n",map.end.y - map.start.y); std::cout<<map.end.y - map.start.y - 5 - 1<<std::endl; if(map.end.y - map.start.y - 5 - 1 < 5) { break; } //std::cout<<map.end.y - map.start.y - 5<<std::endl; //std::cout<<"random: "<< FrameWork::GetRandom(5,map.end.y - map.start.y - 5)<<std::endl; int rand = FrameWork::GetRandom(5,map.end.y - map.start.y - 5 - 1); std::cout<<"Random: "<<rand<<std::endl; SetLine_X(rand); //SetLine_X(29 - 1); //printf("aaaaa\n"); // flag++; /* for(int i = 0; i< divsion_Y; i++) { } */ //SetLine_Y(FrameWork::GetRandom(10,allSize.X)); } }

#####Stage.cpp

cpp

// ##################################### コンストラクタ ##################################### Stage::Stage() { stage.resize( (int)(FrameWork::GetCurrentWindow()->getSize().x / 24) * (int)(FrameWork::GetCurrentWindow()->getSize().y / 24) ); std::fill(stage.begin(),stage.end(),(byte)0x00); sprite = FrameWork::LoadTexture("asset/texture/brickChip.png"); dungeon = std::make_shared<Generate_Dungeon>(glm::ivec2((FrameWork::GetCurrentWindow()->getSize().x / 24),(FrameWork::GetCurrentWindow()->getSize().y / 24)),glm::ivec2(3,3)); dungeon->setGenerate(); //printf("aaaa\n"); stage = dungeon->getStage(); int xNum = (int)(FrameWork::GetCurrentWindow()->getSize().x / 24); int yNum = (int)(FrameWork::GetCurrentWindow()->getSize().y / 24); //std::cout<<"X: " << xNum<<std::endl; //std::cout<<"Y: " << yNum<<std::endl; //std::cout<<"Y * X: " << yNum * xNum<<std::endl; for(int i = 0; i< yNum; i++) { for(int j = 0; j < xNum; j++) { switch(stage.at(xNum * i + j)) { case 0x00: { printf("*"); } break; case 0x01: { printf("A"); } break; case 0x02: { printf("B"); } break; // 文字数の関係で省略 } } printf("\n"); } }
FrameWork::GetRandom

cpp

// ##################################### 乱数 取得 ##################################### int FrameWork::GetRandom(int start, int end) { std::random_device rnd; // 非決定的な乱数生成器を生成 std::mt19937 mt(rnd()); // メルセンヌ・ツイスタの32ビット版、引数は初期シード値 std::uniform_int_distribution<> Rand(start, end); // [start, end] 範囲の一様乱数 return Rand(mt); } ``

良い質問の評価を上げる

以下のような質問は評価を上げましょう

  • 質問内容が明確
  • 自分も答えを知りたい
  • 質問者以外のユーザにも役立つ

評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

気になる質問をクリップする

クリップした質問は、後からいつでもマイページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

  • プログラミングに関係のない質問
  • やってほしいことだけを記載した丸投げの質問
  • 問題・課題が含まれていない質問
  • 意図的に内容が抹消された質問
  • 過去に投稿した質問と同じ内容の質問
  • 広告と受け取られるような投稿

評価を下げると、トップページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

Zuishin

2022/05/05 03:52

同じ質問。 前の質問は削除された。
Zuishin

2022/05/05 03:54

提示画像と言いつつ画像がないところを見ると、おそらくマルチポスト。

まだ回答がついていません

会員登録して回答してみよう

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
87.20%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問

同じタグがついた質問を見る

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。