迷路の生成
①クロススプリット再帰バージョン
②BFS(つまり幅優先アルゴリズム)
クロスセグメンテーションメソッドの生成
迷路は最初は通路でいっぱいで、次にランダムに交差して壁を構築し、次に3つの壁にランダムに穴を開けて4つの部分空間を接続する必要があります。
要件:クロスポイントの水平座標と垂直座標の両方が偶数である必要があり(つまり、マップの行と列が奇数である)、穴あけポイントが奇数である必要があります。
DFSメソッドの生成:
ホリネズミが穴を開けるのと同じように、迷路は最初にすべての障害物(壁)を必要とし、次にランダムな方向に穴を開けます(壁を掘る)。
掘る壁の経路(穴の方向)は、訪問したノードでのみ貫通できる必要があります。
実際の戦闘訓練
クロススプリット
非常に簡単な方法ですが、ゲームの効果はあまり良くありません。次に、アルゴリズムプロセスについて説明します。
最初にすべてを囲み、次にクロスウォールを作成します
クロスウォールの3つの壁を突破する
クロスウォールを再帰的に生成してから、任意の3つのウォールを開きます
次に、最も単純な迷路が生成されます(実際、卵の迷路はありません。レビューの再帰と考えてください)
DFS方式
実は壁を掘るアルゴリズムなのですが、そうですね。このアルゴリズムについて詳しく説明してください。
マップを定義するノード構造を見てみましょう。
#define MAP_ROW 20
#define MAP_COL 25
Node map[MAP_ROW][MAP_COL] = {
0 }; //每个墙 都没打通的 每个结点 都是没有访问过
struct Node
{
int flag; //表示关键结点是否访问过 0:未访问 1:已访问 2:待访问
// 3:人物 4:目的地
bool left, right, top, buttom; //表示这个节点周围的四堵墙 0:不可通过的墙 1:可通过的空地
};
次に、初期化関数init()である迷路マップを生成します。最初に、キャラクターの場所でもある迷路への入り口として左上隅を選択します。
map[0][0].flag = 1; //这个节点已经访问过
訪問するノードを格納するための補助配列を定義します
COORD waitForVisit[MAP_COL * MAP_ROW]; //存放待访问的结点
int len = 0; //map里面的坐标的个数
同時に、訪問したノードの周囲に訪問するノードがあり、それらを補助アレイに追加します。
waitForVisit[len++] = {
1, 0 }; //下方的结点 可以访问
map[1][0].flag = 2; //待访问
waitForVisit[len++] = {
0, 1 }; //右边的结点 可以访问
map[0][1].flag = 2; //待访问
効果は次のとおりです。
マップを描画するときは、白を未訪問ノード、ピンクを訪問ノード、青を訪問ノードとして設定します。
if (map[i][j].flag == 0) //没有访问过这个节点
{
setfillcolor(WHITE);
}
else if (map[i][j].flag == 1) //访问过
{
setfillcolor(RGB(255, 193, 193));
}
else if(map[i][j].flag == 2) //待访问
{
setfillcolor(BLUE);
}
次に、訪問するノードを1つずつ訪問し、すべてのノードを訪問する必要があります。つまり、幅優先探索です。
len为待访问节点的数量,从中随机选取一个节点进行访问,并将访问后该节点周围的未访问节点初始化为待访问节点
while (len > 0)
{
//随机选取其中的一个结点 进行访问
m = rand() % len; //从可以访问的结点中随机取一个
/*打通这个节点 把这个节点相邻的结点放到map里面*/
borderThrough(map, waitForVisit[m]); //borderThrough作用:打通waitForVisit[m]节点的任意一面(上下左右任意一面)
map[waitForVisit[m].X][waitForVisit[m].Y].flag = 1; /*标记已访问*/
}
ノードを開く関数borderThrough()は、2番目のパラメーターが渡されるノードの任意の側(上、下、左、右)を開くことです。開くための要件は、このサーフェスの隣接ノードがノードであるということです。訪問された。
void borderThrough(Node map[][MAP_COL], const COORD node)///函数原型
条件を乗り越える:
(node.X + 1 < MAP_ROW) && map[node.X + 1][node.Y].flag == 1 //向下打通
(node.Y - 1 >= 0) && map[node.X][node.Y - 1].flag == 1 //向左打通
開いた後、ノードは訪問済みノード(flag == 1)として設定され、次に周囲の4つのノード(未訪問ノードがある場合)が訪問対象ノードとして設定されます。
m为随机选取的待访问节点下标
/*周围的四个节点(如果有) 全部放到map里面*/
if (waitForVisit[m].X - 1 >= 0 && map[waitForVisit[m].X - 1][waitForVisit[m].Y].flag == 0)
{
//如果上方的结点没有访问过 设置为待访问 并且把这个位置放到map里面
map[waitForVisit[m].X - 1][waitForVisit[m].Y].flag = 2; /*标记待访问*/
waitForVisit[len++] = {
waitForVisit[m].X - 1, waitForVisit[m].Y };/*添加进待访问节点辅助数组里面*/
}
if (waitForVisit[m].X + 1 < MAP_ROW && map[waitForVisit[m].X + 1][waitForVisit[m].Y].flag == 0)
{
//下
map[waitForVisit[m].X + 1][waitForVisit[m].Y].flag = 2; /*标记待访问*/
waitForVisit[len++] = {
waitForVisit[m].X + 1, waitForVisit[m].Y };/*添加进待访问节点辅助数组里面*/
}
訪問済みとしてマークされたノードは、訪問対象のノードの配列から削除されます
//map[m]已经访问过 从map里面删掉就可以
if (m == len - 1)
len--;
else
{
waitForVisit[m] = waitForVisit[len - 1];
len--;
}
プロセス全体のスローモーション再生は次のとおりです。
キャラクターの動きは何度も説明されており、前・次の記事から「倉庫番」などの前のチュートリアルを確認できます。
より詳細な操作については、バックグラウンドでキーワードを送信して[迷路アルゴリズム]ソースコードを取得してください