์์ ๋ก๊ทธ๋ผ์ดํฌ ๋งต ์์ฑ ๋ฐฉ์ ๊ธ์ ํตํด ํ์ฌ ๊ฐ์ฅ ๋ณดํธ์ ์ผ๋ก ์ฌ์ฉ๋๋ ๋ก๊ทธ๋ผ์ดํฌ ๋งต ์์ฑ ์๊ณ ๋ฆฌ์ฆ ์ค ํ๋๊ฐ BSP ์๊ณ ๋ฆฌ์ฆ์ด๋ผ๋ ๊ฒ์ ์์์ต๋๋ค. ๊ทธ๋์ ์ด์ , ์ด๋ฅผ ์ง์ ๊ตฌํํด๋ณด๋ฉฐ ๊ณต๋ถํด๋ณด๋ ค๊ณ ํฉ๋๋ค.
๋จผ์ , BSP ์๊ณ ๋ฆฌ์ฆ์ ์ด์ฉํ ๋๋ค ๋งต ์์ฑ ์๊ณ ๋ฆฌ์ฆ์ ์ ์ฐจ๋ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
- ๊ณต๊ฐ์ ๋ ๊ฐ๋ก ๊ณ์ํด์ ๋๋๋ค. (๋๋ ๊ณต๊ฐ์ ํธ๋ฆฌ๋ก ๊ตฌ์ฑ)
- ๋๋ ๊ณต๊ฐ์ ๊ณต๊ฐ์ ๋ฒ์ด๋์ง ์๋ ํฌ๊ธฐ์ ๋ฐฉ์ ๋ง๋ ๋ค.
- ๋ฐฉ๋ผ๋ฆฌ ์๋ก ์ด์ด์ค๋ค.
1. ๊ณต๊ฐ์ ๋ ๊ฐ๋ก ๊ณ์ํด์ ๋๋๋ค.
BSP ์๊ณ ๋ฆฌ์ฆ์ด ์ค์ง์ ์ผ๋ก ์ฌ์ฉ๋๋ ๋จ๊ณ๋ก ์ด๋ฆ์์๋ ์ ์ ์๋ฏ์ด Binary Space Partitioning, ์ฆ ๊ณต๊ฐ์ ๋ ๊ฐ๋ก ๋๋์ด ํธ๋ฆฌ๋ก ์ ์ฅํ๋ ์๊ณ ๋ฆฌ์ฆ์ ๋๋ค. BSP ์๊ณ ๋ฆฌ์ฆ ์์ฒด๋ ์ด๋ค ๋ชจ์์ ๊ณต๊ฐ์ผ๋ก๋ ๋๋ ์ ์์ง๋ง ์ ๋ Pixel Dungeon ๊ฒ์๊ณผ ๊ฐ์ด ์ฌ๊ฐํ์ผ๋ก ์ด๋ฃจ์ด์ง ๋์ ์ ๋ง๋ค๊ณ ์ ํ๊ธฐ ๋๋ฌธ์ ์ฌ๊ฐํ์ผ๋ก ๊ณต๊ฐ์ ๋๋๊ฒ ์ต๋๋ค. ์ด ๊ณผ์ ์ ๊ทธ๋ฆผ์ผ๋ก ๋ํ๋ด๋ฉด ๋ค์๊ณผ ๊ฐ์ต๋๋ค.

์ด๋ ๊ฒ ํธ๋ฆฌ๋ก ์ ์ฅํ๋ ๊ณผ์ ์์ ๊ฐ ๋ ธ๋์ ๊ณต๊ฐ์ ์ผ์ชฝ ์๋จ ์์น ์ ๋ณด์ ๊ณต๊ฐ์ ๊ฐ๋ก, ์ธ๋ก ๊ธธ์ด๋ฅผ ์ ์ฅํ๋ ๋ฐฉ์์ผ๋ก ๊ตฌํํด๋ณด๊ณ ์ ํฉ๋๋ค. ๊ทธ๋ฌ๊ธฐ ์ํด์๋ ์ผ๋จ ํธ๋ฆฌ์ ๋ ธ๋ ํด๋์ค์ ์์น, ๊ณต๊ฐ ํฌ๊ธฐ๋ฅผ ์ ์ฅํ ๊ตฌ์กฐ์ฒด๋ฅผ ๋จผ์ ์ ์ํด์ผํฉ๋๋ค.
struct Rect
{
int x; int y;
int width; int height;
};
class Node
{
public:
Node* leftNode;
Node* rightNode;
Rect rect;
public:
Node(int x, int y, int width, int height);
};
Node::Node(int x, int y, int width, int height)
{
rect.x = x; rect.y = y;
rect.width = width; rect.height = height;
}
์์น ์ ๋ณด๋ฅผ ์ ์ฅํ๋ Rect ๊ตฌ์กฐ์ฒด์๋ ๊ณต๊ฐ์ ์ผ์ชฝ ์๋จ ์์น์ธ x, y ์ขํ๋ฅผ ์ ์ฅํ๋ ๋ณ์์ ์ฌ๊ฐํ์ผ๋ก ๋๋ ๊ณต๊ฐ์ ํฌ๊ธฐ๋ฅผ ์ ์ฅํ๊ธฐ ์ํด ๊ฐ๋ก, ์ธ๋ก ๊ธธ์ด๋ฅผ ์ ์ฅํ๋ ๋ณ์๋ ๊ฐ์ด ์ ์ธํฉ๋๋ค. ๊ทธ๋ฆฌ๊ณ , ๋ ธ๋์๋ ์์ ์ ์์ ๋ ธ๋๋ฅผ ์ ์ฅํ ์ ์๋ leftNode, rightNode๋ฅผ ์ ์ธํ๊ณ Rect๋ผ๋ ์์น, ๊ณต๊ฐ ์ ๋ณด๋ฅผ ์ ์ฅํ ์ ์๋ rect ๋ณ์๋ฅผ ์ ์ธํฉ๋๋ค.
๊ทธ๋ผ ์ด์ , ๊ณต๊ฐ์ ๋๋ ์ง๋๋ฅผ ๋ง๋ค์ด์ผ ํ๋๋ฐ ์ฌ๊ธฐ์๋ ๊ฐ๋จํ๊ฒ 2์ฐจ์ ๋ฐฐ์ด๋ก ํํํ๊ฒ ์ต๋๋ค.
#define mapWidth 60
#define mapHeight 60
int map[mapHeight][mapWidth];
๋งต๋ ๋ง๋ค์๊ณ ํธ๋ฆฌ๋ฅผ ์ํ ๋ ธ๋์ ์์น, ๊ณต๊ฐ ํฌ๊ธฐ๋ฅผ ์ํ ๊ตฌ์กฐ์ฒด๋ ์ ์ธํ์ผ๋ ์ด์ ๋งต์ ๋ ๊ฐ๋ก ๊ณ์ํด์ ๋๋๋ ํจ์๋ฅผ ํ๋ฒ ์๊ฐํด๋ณด๊ฒ ์ต๋๋ค.
๊ณต๊ฐ์ ๋ ๊ฐ๋ก ๋๋๋ ค๋ฉด ์ด๋ป๊ฒ ํด์ผํ ๊น์? ๋จผ์ ์ต์ด์ ๊ณต๊ฐ์ ๋ํ๋ด๋ root ๋ ธ๋๊ฐ ์์ด์ผ๊ฒ ์ง์. ๊ทธ๋ผ, ์ต์ด์ ๊ณต๊ฐ(๋ ธ๋)์ธ root๋ ธ๋์ ๊ณต๊ฐ ์์น ์ ๋ณด๋ ์ผ์ชฝ ์๋จ ์ขํ๋ฅผ ์ ์ฅํ๊ธฐ๋ก ํ์์ผ๋ (0, 0)์ด๊ณ width, height์ด ๊ฐ๊ฐ 60์์ ์๊ฐํ ์ ์์ต๋๋ค. ์ด๋ฅผ ์ผ๋จ ์ธ๋ก๋ก ๋ถํ ํด 2๊ฐ์ ๊ณต๊ฐ์ผ๋ก ๋๋๋ค๊ณ ํ๊ฒ ์ต๋๋ค. ๊ทธ๋ผ ์ผ์ชฝ์ ์๋ ๊ณต๊ฐ(๋ ธ๋)์ ์ค๋ฅธ์ชฝ์ ์๋ ๊ณต๊ฐ(๋ ธ๋)์ผ๋ก ๋๋๋๋ฐ ๊ฐ๊ฐ ์์น ์ ๋ณด๋ (0,0), (n, 0)์ด๊ณ width๋ root.width - right.width right.width, height์ root.height์ ๋๋ค.
์ด๋ฒ์ ๊ฐ๋ก๋ก ๋ถํ ํ๋ค๊ณ ๊ฐ์ ํด๋ณด๊ฒ ์ต๋๋ค. ๊ทธ๋ผ ์์ชฝ์ ์๋ ๊ณต๊ฐ(๋ ธ๋)์ ์๋์ชฝ์ ์๋ ๊ณต๊ฐ(๋ ธ๋)์ผ๋ก ๋๋๋๋ฐ ์์ชฝ์ ์๋ ๊ณต๊ฐ์ด ๋ฐฐ์ด ์ ๋ ์์ ์ขํ์ ํด๋นํ๋ฏ๋ก ์ผ์ชฝ์ ์๋ ๊ณต๊ฐ์ผ๋ก ํ๊ฒ ์ต๋๋ค. ๊ฐ๊ฐ ์์น ์ ๋ณด๋ (0,0), (0, n)์ด๊ณ width๋ root.width, height์ root.height - right.height, right.height์ ๋๋ค.
๋๋ ๋ ธ๋์ ๋ํด์๋ ์ด ๋ ๊ฐ์ง ๊ฐ์ ์ด ๊ณ์ํด์ ๋ฐ๋ณต๋ ๊ฒ์ด๋ผ๊ณ ์๊ฐ์ด ๋์๋์? ๊ทธ๋ผ ์ด๋ ์ฌ๊ท์ ์ผ๋ก ๊ตฌํํ ์ ์์ ๊ฒ ๊ฐ์ต๋๋ค. ํ์ง๋ง, ์ฌ๊ท์ ๊ณผ์ ์์ ์ด๋ค ๊ณต๊ฐ์ ๊ฐ๋ก ๋๋ ์ธ๋ก๋ก ๋๋์ด์ผ ํ๋์ง๋ ์ ํ์ง ๋ชปํ์ต๋๋ค. ์ ๋ ๋จ์ํ๊ฒ ๊ธธ์ด๊ฐ ๊ธด ์ชฝ์ ๋ํด ์์ง์ผ๋ก ๋ถํ ํ๊ธฐ๋ก ํ์ต๋๋ค. ์ฆ, ๊ฐ๋ก๊ฐ ๋ ๊ธธ๋ฉด ์ธ๋ก๋ก ์๋ฅด๊ณ ์ธ๋ก๊ฐ ๋ ๊ธธ๋ฉด ๊ฐ๋ก๋ก ์๋ฅด๋ ๊ฒ์ ๋๋ค. ๋จ, ์ฝ์์ ์ถ๋ ฅ ์ ๊ฐ์ ํฌ๊ธฐ๋ผ๋ ๊ฐ๋ก๋ณด๋ค ์ธ๋ก๊ฐ ๋ ์ปค๋ณด์ด๋ฏ๋ก ๊ฐ๋ก๋ ์ธ๋ก๊ฐ ๊ฐ์ ํฌ๊ธฐ๋ฉด ๊ฐ๋ก๋ก ์๋ฅด๋๋ก ํ์ต๋๋ค.
๊ทธ๋ผ ์ฌ๊ท์ ์ผ๋ก ๊ตฌํํด์ผํจ๋ ์์๊ณ ๋๋๋ ๊ธฐ์ค๋ ์๊ฐํ์ต๋๋ค. ๋ง์ง๋ง์ผ๋ก ๋๋๋ n๊ณผ right.height ๋๋ right.width์ ์ ํด์ฃผ๋ ๋ฐฉ๋ฒ๋ง ์๋ฉด ๋๋๋ฐ ์๋ ๊ทธ๋ฅ ํน์ ๋น์จ ์ฌ์ด์ ๊ฐ์ ๋๋คํ๊ฒ ๊ฐ์ ธ์ค๋๋ก ํ๋ฉด ๋ฉ๋๋ค. ์ ํน์ ๋น์จ ์ฌ์ด์ ๊ฐ์ ๊ฐ์ ธ์ค๋๋ฉด, ๊ฐ์ด ๋๋ฌด ์๊ฑฐ๋ ํฌ๋ฉด ํ ๊ณต๊ฐ์ ๋ฌด์ฉ์ง๋ฌผ์ด ๋๊ธฐ ๋๋ฌธ์ ๋๋ค.
์ ๊ฐ ๊ตฌํํ ๋งต์ ๋ ๊ฐ๋ก ๊ณ์ํด์ ๋๋๋ ํจ์, Divide๋ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
double minRatio = 0.4, maxRatio = 0.7;
int maxDepth = 4;
// low ~ high ์ฌ์ด์ ๊ฐ ๋ฐํ
int random(int low, int high)
{
return low + rand() % (high - low + 1);
}
void Divide(Node *node, int depth)
{
if (depth == maxDepth) return;
int maxLen = node->rect.width > node->rect.height ? node->rect.width : node->rect.height;
int split = random(round(maxLen * minRatio), round(maxLen * maxRatio));
if (node->rect.width >= node->rect.height)
{
node->leftNode = new Node(node->rect.x, node->rect.y, split, node->rect.height);
node->rightNode = new Node(node->rect.x + split, node->rect.y, node->rect.width - split, node->rect.height);
for (int i = node->leftNode->rect.y; i < node->leftNode->rect.y + node->leftNode->rect.height; i++)
map[i][node->rightNode->rect.x] = 1;
} else
{
node->leftNode = new Node(node->rect.x, node->rect.y, node->rect.width, split);
node->rightNode = new Node(node->rect.x, node->rect.y + split, node->rect.width, node->rect.height - split);
for (int i = node->leftNode->rect.x; i < node->leftNode->rect.x + node->leftNode->rect.width; i++)
map[node->rightNode->rect.y][i] = 1;
}
Divide(node->leftNode, depth + 1);
Divide(node->rightNode, depth + 1);
}
// ๋งต์ ์ถ๋ ฅํ๊ธฐ ์ํ ํจ์
void PrintMap()
{
for (int i = 0; i < mapHeight; i++) {
for (int j = 0; j < mapWidth; j++)
cout << map[i][j];
cout << endl;
}
}

์ ๋๋ก ๋๋ ๊ฒ์ ํ์ธํ ์ ์์ฃ ?
2. ๋๋ ๊ณต๊ฐ์ ๋ฒ์ด๋์ง ์๋ ํฌ๊ธฐ์ ๋ฐฉ์ ๋ง๋ ๋ค.
์ด์ ๊ณต๊ฐ๋ ๋๋์๊ณ ๊ฐ ๊ณต๊ฐ์ ์์น ์ ๋ณด์ ํฌ๊ธฐ ์ ๋ณด๋ ์ ์ฅํด๋์์ต๋๋ค. ์ด๋ฅผ ์ด์ฉํด ๊ฐ ๊ณต๊ฐ์ ๋ฐฉ์ ๋ง๋ค ์ ์์ ๊ฒ ๊ฐ์ต๋๋ค. ์ด์ ๊ณผ์ ์์ ๋น์จ์ ํตํด ๋๋๋ ํฌ๊ธฐ๋ฅผ ์ ํ์๋ฏ์ด ๋ฐฉ์ ์์น, ํฌ๊ธฐ ์ ๋ณด๋ฅผ ๋น์จ์ ์ฌ์ด์ ์ ์ ๊ฐ์ผ๋ก ๋๋คํ๊ฒ ์ ํ๋๋ก ํ๊ฒ ์ต๋๋ค. ๊ทธ๋ฆฌ๊ณ ๊ณต๊ฐ์ ์ด๋ป๊ฒ ๋๋์๋ ์ต์ข leaf ๋ ธ๋๋ค ๋ด์ ๋ฐฉ์ ๋ง๋ค์ด์ผ ํ๋ฏ๋ก leaf ๋ ธ๋๊ฐ ๋์ฌ๋๊น์ง ์ฌ๊ท ํธ์ถํด์ผ๊ฒ ๋ค์.
์ฌ๊ธฐ์ ์ฃผ์ํ ์ ์ ์์น ์ ๋ณด๋ฅผ ๋จผ์ ๊ฒฐ์ ํด๋ฒ๋ฆฌ๋ฉด ํฌ๊ธฐ ์ ๋ณด๋ฅผ ์ ํ๋ ๊ณผ์ ์์ ๊ณต๊ฐ์ ๋ฒ์ด๋๊ฑฐ๋ ๋๋ฌด ์์ ๊ณต๊ฐ์ด ์๊ธธ ์ ์์ต๋๋ค. ๊ทธ๋ฌ๋ฏ๋ก ํฌ๊ธฐ ์ ๋ณด๋ฅผ ๋จผ์ ๊ฒฐ์ ํ๊ณ ํ์ ์์น ์ ๋ณด๋ฅผ ๊ฒฐ์ ํ๋ ๋ฐฉ์์ด ๋ ํธํ ๊ฒ ๊ฐ๋ค์.
์ ๋ ์ด๋ ๊ฒ ๊ตฌํํ์์ต๋๋ค.
class Node
{
public:
Node* leftNode;
Node* rightNode;
Rect rect;
Rect room; // ๋ฐฉ ์ ๋ณด ์ ์ฅ์ ์ํ ๋ณ์ ์ถ๊ฐ
public:
Node(int x, int y, int width, int height);
};
Rect GenerateRoom(Node* node, int depth)
{
Rect rect;
if (depth == maxDepth)
{
rect.width = random(round(node->rect.width * minRatio), round(node->rect.width * maxRatio));
rect.height = random(round(node->rect.height * minRatio), round(node->rect.height * maxRatio));
rect.x = random(node->rect.x + 1, node->rect.x + (node->rect.width-rect.width));
rect.y = random(node->rect.y + 1, node->rect.y + (node->rect.height-rect.height));
} else
{
node->leftNode->room = GenerateRoom(node->leftNode, depth + 1);
node->rightNode->room = GenerateRoom(node->rightNode, depth + 1);
}
return rect;
}
// ๋ฐฉ์ ์ถ๋ ฅํ๊ธฐ ์ํ ํจ์
void PrintRoom(Node* node, int depth)
{
if (depth == maxDepth)
{
for (int j = node->room.y; j < node->room.y + node->room.height; j++)
for (int i = node->room.x; i < node->room.x + node->room.width; i++)
map[j][i] = 3;
} else {
PrintRoom(node->leftNode, depth + 1);
PrintRoom(node->rightNode, depth + 1);
}
}

๋ฐฉ์ ์๋ฏธํ๋ 3์ด ๊ณต๊ฐ์ ๋ฒ์ด๋์ง ์๊ณ ์ ์์ฑ๋์์ต๋๋ค. ๊ทธ๋ฆฌ๊ณ ์ฌ๋ฌ ๋ฒ ๋๋ ค๋ณด๋ฉด ์์๊ฒ ์ง๋ง ๊ณ์ ๋๋คํ๊ฒ ๋ฐฉ์ด ์์ฑ๋จ์ ๋ณด์ค ์ ์์ต๋๋ค.
3. ๋ฐฉ๋ผ๋ฆฌ ์๋ก ์ด์ด์ค๋ค.
์ฌ์ค ๊ฐ์ฅ ์ ๋ฅผ ๋จน์๋ ๊ตฌ๊ฐ์ ๋๋ค. ๋จผ์ , ์ ๋ ์ด๋ฐ์์ผ๋ก ๊ธธ์ ๋ง๋ค๊ณ ์ถ์์ต๋๋ค.

๋ณด์๋ฉด ๊ฐ๋ก์ ์ธ๋ก ๊ฒฝ๋ก๊ฐ ๋ชจ์์ ๊ฐ์ง๋ง ๋ฐฐ์ด๋ก ํํํ๋ ค๋ฉด x, y ์ขํ๊ฐ ์๋ก ๋ค๋ฅธ ๋ฐฉ์์ผ๋ก ํํ๋จ์ ์์ํ ์ ์์ต๋๋ค. ๊ทธ๋์ ๊ฐ๋ก๋ก ์ด์ด์ฃผ๋ ํจ์์ ์ธ๋ก๋ก ์ด์ด์ฃผ๋ ํจ์๋ก ๋๋์ด ๊ตฌํํ์์ต๋๋ค. ๊ทธ๋ฆฌ๊ณ ๊ธธ์ 3๋จ๊ณ๋ก ๋๋์ด ์ผ์ชฝ ๋ฐฉ๋ถํฐ ๊บพ์ด๋ ๊ตฌ๊ฐ๊น์ง๋ฅผ 1๋จ๊ณ, ๊บพ์ด๋ ๊ตฌ๊ฐ์ 2๋จ๊ณ, ๊บพ์ด๋ ๊ตฌ๊ฐ๋ถํฐ ์ค๋ฅธ์ชฝ ๋ฐฉ๊น์ง๋ฅผ 3๋จ๊ณ๋ก ํ์์ต๋๋ค.
๋จผ์ , ๊ฐ๋ก๋ก ๋ถํ ๋ ๊ณต๊ฐ ์ ๋ฐฉ ๋ ๊ฐ๋ฅผ ์ด์ด์ค๋ค๊ณ ์๊ฐํ๊ณ ๋จ๊ณ๋ณ๋ก ํ๋ฒ ๊ตฌํํด๋ณด๊ฒ ์ต๋๋ค. ์ฒ์ 1๋จ๊ณ์์ ์ผ์ชฝ ๋ฐฉ์ ํญ์ ๋ฐฉ์ ์๋์ชฝ์์ ๊ธธ์ด ์ด์ด์ง๋๋ค. ๊ทธ๋ผ, y ์ขํ๋ ๊ณ ์ ๋๊ฒ ๋ค์. ํ์ง๋ง x ์ขํ๋ ์๊ด์ด ์์ฃ ? ๊ทธ๋์ ์ ๋ ์ค์์ผ๋ก ๊ณ ์ ์์ผ์ฃผ์์ต๋๋ค. ์ผ์ชฝ ๋ฐฉ์ ์ค๊ฐ ์๋ ์ขํ๊ฐ ํญ์ (room.x + (room.width/2), room.y + room.height)์ผ๋ก ์ ํด์ ธ์์ต๋๋ค. ์ด ์ขํ์์ ๊บพ์ด๋ ๊ตฌ๊ฐ๊น์ง y์ขํ๋ง 1์ฉ ์ฆ๊ฐ์์ผ์ฃผ๋ฉด ๋ ๊ฑฐ ๊ฐ๋ค์. ๊ทผ๋ฐ ์ด์ ๊บพ์ด๋ ๊ตฌ๊ฐ ์ขํ๋ฅผ ์ด๋ป๊ฒ ์ ํด์ค์ผ ํ ์ง ๋ชจ๋ฅด๊ฒ ๋๊ตฐ์.. ๊ทธ๋ฐ๋ฐ ๊ฐ์๊ธฐ ์๊น 1๋จ๊ณ์์ ์ฐ์ธ split ๋ณ์๊ฐ ์๊ฐ์ด ๋ฌ์ต๋๋ค. ์ผ์ชฝ ๋ฐฉ ์ค๊ฐ ์ขํ์์ rect.y + split๋งํผ ๊ธธ์ ๊ทธ๋ ธ๋ค๊ฐ (1๋จ๊ณ) rect.y + split์์ ๊บพ์ด๋ ๊ตฌ๊ฐ์ ๋ง๋ค๋ฉด ์ฝ๊ฒ ๋ง๋ค ์ ์๊ฒ ๋ค๋ ์๊ฐ์ด ๋ค๋๊ตฐ์.
2๋จ๊ณ๋ ๊ทธ๋ผ ์ฝ๊ฒ ๊ตฌํ์ด ๋๊ฒ ๋ค์. y ์ขํ๋ ์ด๋ฏธ ์์๊ณ , x ์ขํ๋ง ์ผ์ชฝ x ์ขํ์์ ์ค๋ฅธ์ชฝ x ์ขํ๋ก ์ด๋์์ผ์ฃผ๋ฉด ๋๋๋ฐ ์ผ์ชฝ x ์ขํ๊ฐ ๋ ์์ ์๋ ์์ง๋ง, ํด ์๋ ์์์์? ๊ทธ๋์ ์ผ์ชฝ, ์ค๋ฅธ์ชฝ x ์ขํ๋ฅผ ๋น๊ตํด์ ์์ ์ชฝ์ x ์ขํ์์ ํฐ ์ชฝ์ x ์ขํ๋ก ์ด๋์ํค๋ฉด์ ๊ธธ์ ๊ทธ๋ฆฌ๋๋ก ํ์ต๋๋ค.
3๋จ๊ณ๋ 1๋จ๊ณ์ ๋น์ทํ ๋ฐฉ์์ผ๋ก ๊ตฌํ์ด ๋ฉ๋๋ค. ์ค๋ฅธ์ชฝ ๋ฐฉ์ ํญ์ ์ค์ ์ ์ขํ์์ ๊ธธ์ ๊ทธ๋ฆฌ๋ฉฐ ์ค์ ์ขํ๋ (room.x + (room.width/2), room.y)์ ๋๋ค. x ์ขํ๋ ๊ณ ์ ํ์ฑ rect.y + split๋ถํฐ room.y๊น์ง ๊ทธ๋ฆฌ๋ฉด ๋๊ฒ ๊ตฐ์. ์ธ๋ก๋ก ๋ถํ ๋ ๊ฒฝ์ฐ๋ ๊ฐ์ ๋ฐฉ์์ผ๋ก ์๊ฐํ๋ฉด ์ฝ๊ฒ ํด๊ฒฐ๊ฐ๋ฅํฉ๋๋ค.
๊ทธ๋ผ ์ด์ ์ด ๋ ํจ์๋ฅผ ์ด์ฉํด์ ๊ธธ์ ๋ง๋๋ ํจ์๋ฅผ ์์ฑํด์ผ ํ๋๋ฐ, ์ ๋ leaf ๋ ธ๋๋ถํฐ ํธ๋ฆฌ๋ฅผ ํ๊ณ ๊ฐ๋ฉด์ ์ผ์ชฝ, ์ค๋ฅธ์ชฝ ๋ ธ๋์ ๊ธธ์ ์ด์ด์ฃผ๋ ๋ฐฉ์์ ์๊ฐํ์ต๋๋ค. ํ์ง๋ง, ์ ํฌ๋ ๋ฐฉ ์ ๋ณด๋ฅผ leaf ๋ ธ๋์๋ง ์ ์ฅํ๊ณ ๋ถ๋ชจ ๋ ธ๋๋ค์๋ ์ ์ฅํ์ง ์์์ต๋๋ค. ์ด๋ฌ๋ฉด ๋ฌธ์ ๋ ์ผ์ชฝ, ์ค๋ฅธ์ชฝ leaf ๋ ธ๋๋ง ๊ธธ์ด ์ด์ด์ ธ์ ๊ฒฐ๊ตญ ๋ชจ๋ ๋ฐฉ์ด ์ฐ๊ฒฐ๋๋ ๊ฒฝ์ฐ๊ฐ ์๊ธฐ์ง ์์ต๋๋ค.
๊ทธ๋์ ์ ์ด์ ๋ฐฉ์ ์์ฑํ๋ ํจ์ GenerateRoom์์ ๋ถ๋ชจ ๋ ธ๋์ ๊ฐ leaf ๋ ธ๋์ ์์ฑ๋ ๋ฐฉ ์ ๋ณด ์ค ํ๋๋ฅผ ์ ์ฅํ๋๋ก ํด์ผํฉ๋๋ค. ๊ทธ๋์ ์ ๋ else ๋ฌธ์ ์ผ์ชฝ, ์ค๋ฅธ์ชฝ ๋ฐฉ ์ ๋ณด ์ค ๋๋คํ๊ฒ ์ ํํ์ฌ ์ด๋ฅผ ๋ถ๋ชจ์๊ฒ ๋๊ฒจ์ฃผ๋ ์์ผ๋ก ์ฝ๋๋ฅผ ์ด์ง ์์ ํ์ต๋๋ค.
๊ทธ๋ผ ์ด์ leaf ๋ ธ๋๊น์ง ๊ฐ ํ ํธ๋ฆฌ๋ฅผ ํ๊ณ ์ฌ๋ผ๊ฐ๋ฉด์ ์๋ก ๊ธธ์ ์ด์ด์ฃผ๊ธฐ๋ง ํ๋ฉด ์์ฑ์ ๋๋ค. ๋จ, ๋ถ๋ชจ ๋ ธ๋์ ๊ธธ์ ์ด์ด์ฃผ๋ ๊ณผ์ ์์ ๋ฐฉ์ ํต๊ณผํ๋ ๊ฒฝ์ฐ๊ฐ ์๊ธธ ์ ์์ด์ ๋ฐฉ ์ ๋ณด๋ฅผ ์ด์ฉํด ๊ธธ์ ์ด์ด ์ค ๋ค ๋จผ์ ์ถ๋ ฅํ๊ณ ๋ฐฉ์ ์ถ๋ ฅํ๋ ์์ผ๋ก ๊ตฌํํ์ต๋๋ค.
Rect GenerateRoom(Node* node, int depth)
{
if (depth == maxDepth)
{
... // ์ด์ ๊ณผ ๊ฐ์์ ์๋ตํ๊ฒ ์ต๋๋ค.
} else
{
...
if (random(0, 2)) // ๋๋คํ๊ฒ ์ ํํ์ฌ ๋ถ๋ชจ์๊ฒ ์ผ์ชฝ ํน์ ์ค๋ฅธ์ชฝ ๋
ธ๋์ ๋ฐฉ ์ ๋ณด๋ฅผ ๋๊ฒจ์ค๋ค.
rect = node->leftNode->room;
else
rect = node->rightNode->room;
}
...
}
void RoomSplitHorizon(Node* node) // ์ธ๋ก๋ก ๋ถํ ๋ ๊ณต๊ฐ์ ๊ธธ ์ด์ด์ค ๋ ์ฌ์ฉ
{
int lCenterY = node->leftNode->room.y + node->leftNode->room.height;
int lCenterX = node->leftNode->room.x + (node->leftNode->room.width/2);
int rCenterY = node->rightNode->room.y;
int rCenterX = node->rightNode->room.x + (node->rightNode->room.width/2);
for (int y = lCenterY; y <= node->leftNode->rect.y + node->leftNode->split; y++)
map[y][lCenterX] = 7;
int from = lCenterX <= rCenterX ? lCenterX : rCenterX;
int to = lCenterX <= rCenterX ? rCenterX : lCenterX;
for (int x = from; x <= to; x++)
map[node->leftNode->rect.y + node->leftNode->split][x] = 7;
for (int y = node->leftNode->rect.y + node->leftNode->split; y < rCenterY; y++)
map[y][rCenterX] = 7;
}
void RoomSplitVertical(Node* node) // ๊ฐ๋ก๋ก ๋ถํ ๋ ๊ณต๊ฐ์ ๊ธธ ์ด์ด์ค ๋ ์ฌ์ฉ
{
int lCenterY = node->leftNode->room.y + (node->leftNode->room.height/2);
int lCenterX = node->leftNode->room.x + node->leftNode->room.width;
int rCenterY = node->rightNode->room.y + (node->rightNode->room.height/2);
int rCenterX = node->rightNode->room.x;
for (int x = lCenterX; x <= node->leftNode->rect.x + node->leftNode->split; x++)
map[lCenterY][x] = 7;
int from = lCenterY <= rCenterY ? lCenterY : rCenterY;
int to = lCenterY <= rCenterY ? rCenterY : lCenterY;
for (int y = from; y <= to; y++)
map[y][node->leftNode->rect.x + node->leftNode->split] = 7;
for (int x = node->leftNode->rect.x + node->leftNode->split; x < rCenterX; x++)
map[rCenterY][x] = 7;
}
void GeneratePath(Node* node, int depth) // ๊ธธ ์์ฑ
{
if (depth == maxDepth) return;
GeneratePath(node->leftNode, depth + 1);
GeneratePath(node->rightNode, depth + 1);
if (node->leftNode->rect.x == node->rightNode->rect.x)
RoomSplitHorizon(node);
else
RoomSplitVertical(node);
}

์ด์ ๊ฐ ๋จ๊ณ๋ฅผ ์ ์ ํ ์์ด์ฃผ๋ฉด ์ต์ข ์ฝ๋๋ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
/*
๋๋คํ ๋งต์ ๋ง๋ค๊ธฐ ์ํ ์ ์ฐจ์ ์ฝํ
์ธ ์์ฑ (PCG) ๋ฐฉ์์ BSP ์๊ณ ๋ฆฌ์ฆ (C++)
0 -> ํ๊ณต void
3 -> ๋์ dungeon
7 -> ๊ธธ path
*/
#include <iostream>
#include <cmath>
#include <stdlib.h>
#include <time.h>
using namespace std;
#define mapWidth 60
#define mapHeight 60
int map[mapHeight][mapWidth];
int maxDepth = 4;
double minRatio = 0.4, maxRatio = 0.7; // ๋ฐฉ์ ํฌ๊ธฐ์ ๊ฐ์ ๋๋ค ์์์ ์ฌ์ฉ๋๋ ์ต์, ์ต๋ ๋น์จ
// ๋ฐฐ์ด ๋ด ์์น ์ ๋ณด๋ฅผ ์ ์ฅํ๊ธฐ ์ํ ๊ตฌ์กฐ์ฒด
// ์ผ์ชฝ ์๋จ ์์น์ ํด๋นํจ
struct Rect
{
int x; int y;
int width; int height;
};
class Node
{
public:
Node* leftNode;
Node* rightNode;
Rect rect;
Rect room;
int split;
public:
Node(int x, int y, int width, int height, int split);
};
Node::Node(int x, int y, int width, int height, int split)
{
rect.x = x; rect.y = y;
rect.width = width; rect.height = height;
this->split = split;
}
// void initMap() // ๋งต์ ๊ฐ์ฅ์๋ฆฌ๋ฅผ 1๋ก ๋ฐ๊พผ๋ค.
// {
// for (int i = 0; i < mapHeight; i++) {
// for (int j = 0; j < mapWidth; j++) {
// if (i == 0 || i == mapHeight-1)
// map[i][j] = 1;
// else {
// map[i][0] = 1;
// map[i][mapWidth-1] = 1;
// }
// }
// }
// }
void PrintMap()
{
for (int i = 0; i < mapHeight; i++) {
for (int j = 0; j < mapWidth; j++)
cout << map[i][j];
cout << endl;
}
}
int random(int low, int high) // low ~ high ๋ฒ์์ ๋๋ค ์ ์ ํ๋๋ฅผ ๋ฝ๋๋ค.
{
return low + rand() % (high - low + 1);
}
void Divide(Node *node, int depth) // ๊ณต๊ฐ์ ๋๋๋ฉด์ ํธ๋ฆฌ ์์ฑํจ
{
if (depth == maxDepth) return;
// width์ height ์ค ๊ธด ์ชฝ์ ์ ํํด์ width๋ฉด ์ธ๋ก๋ก ๋ถํ , height์ด๋ฉด ๊ฐ๋ก๋ก ๋ถํ
int maxLen = node->rect.width > node->rect.height ? node->rect.width : node->rect.height;
// ๋๋ฌด ์๊ฑฐ๋ ํฐ ๋ฐฉ์ด ์์ฑ๋๋ ๊ฒ์ ๋ง๊ธฐ ์ํด ๋น์จ์ ์ ํด์ ๋๋ค ์ถ์ถ
int split = random(round(maxLen * minRatio), round(maxLen * maxRatio));
if (node->rect.width >= node->rect.height) // ํ์ฌ ๋
ธ๋์ ๊ฐ๋ก๊ฐ ๋ ํฌ๋ค๋ฉด, ์ธ๋ก๋ก ๋๋๋ค.
{
// width, height์ด ๊ฐ์ ํฌ๊ธฐ๋ผ๋ ์ถ๋ ฅ ์์๋ height์ด ๋ ํฌ๊ฒ ์ถ๋ ฅ๋๋ฏ๋ก, ๊ฐ์ ํฌ๊ธฐ๋ผ๋ ์ธ๋ก๋ก ๋๋๋ ๊ฒ์ด ๋ซ๋ค. ์๊ทธ๋ฌ๋ฉด ๋ฐฉ์ด ๋ ์์๋ณด์
node->leftNode = new Node(node->rect.x, node->rect.y, split, node->rect.height, split);
node->rightNode = new Node(node->rect.x + split, node->rect.y, node->rect.width - split, node->rect.height, split);
// for (int i = node->leftNode->rect.y; i < node->leftNode->rect.y + node->leftNode->rect.height; i++)
// map[i][node->rightNode->rect.x] = 1;
} else { // ํ์ฌ ๋
ธ๋์ ์ธ๋ก๊ฐ ๋ ํฌ๋ค๋ฉด, ๊ฐ๋ก๋ก ๋๋๋ค.
node->leftNode = new Node(node->rect.x, node->rect.y, node->rect.width, split, split);
node->rightNode = new Node(node->rect.x, node->rect.y + split, node->rect.width, node->rect.height - split, split);
// for (int i = node->leftNode->rect.x; i < node->leftNode->rect.x + node->leftNode->rect.width; i++)
// map[node->rightNode->rect.y][i] = 1;
}
Divide(node->leftNode, depth + 1);
Divide(node->rightNode, depth + 1);
}
void PrintRoom(Node* node, int depth)
{
if (depth == maxDepth)
{
for (int j = node->room.y; j < node->room.y + node->room.height; j++)
for (int i = node->room.x; i < node->room.x + node->room.width; i++)
map[j][i] = 3;
} else {
PrintRoom(node->leftNode, depth + 1);
PrintRoom(node->rightNode, depth + 1);
}
}
Rect GenerateRoom(Node* node, int depth)
{
Rect rect;
if (depth == maxDepth)
{
// ๋๋ ๊ณต๊ฐ์ ํฌ๊ธฐ๋ฅผ ๋ฒ์ด๋์ง ์๋ ์ ์์ width, height, x, y๋ฅผ ๋๋คํ๊ฒ ์ ํด์ค๋ค.
rect.width = random(round(node->rect.width * minRatio), round(node->rect.width * maxRatio));
rect.height = random(round(node->rect.height * minRatio), round(node->rect.height * maxRatio));
rect.x = random(node->rect.x + 1, node->rect.x + (node->rect.width-rect.width));
rect.y = random(node->rect.y + 1, node->rect.y + (node->rect.height-rect.height));
} else
{
node->leftNode->room = GenerateRoom(node->leftNode, depth + 1);
node->rightNode->room = GenerateRoom(node->rightNode, depth + 1);
if (random(0, 2)) // ๋๋คํ๊ฒ ์ ํํ์ฌ ๋ถ๋ชจ์๊ฒ ์ผ์ชฝ ํน์ ์ค๋ฅธ์ชฝ ๋
ธ๋์ ๋ฐฉ ์ ๋ณด๋ฅผ ๋๊ฒจ์ค๋ค.
rect = node->leftNode->room;
else
rect = node->rightNode->room;
}
return rect;
}
void RoomSplitHorizon(Node* node) // ์ธ๋ก๋ก ๋ถํ ๋ ๊ณต๊ฐ์ ๊ธธ ์ด์ด์ค ๋ ์ฌ์ฉ
{
int lCenterY = node->leftNode->room.y + node->leftNode->room.height;
int lCenterX = node->leftNode->room.x + (node->leftNode->room.width/2);
int rCenterY = node->rightNode->room.y;
int rCenterX = node->rightNode->room.x + (node->rightNode->room.width/2);
for (int y = lCenterY; y <= node->leftNode->rect.y + node->leftNode->split; y++)
map[y][lCenterX] = 7;
int from = lCenterX <= rCenterX ? lCenterX : rCenterX;
int to = lCenterX <= rCenterX ? rCenterX : lCenterX;
for (int x = from; x <= to; x++)
map[node->leftNode->rect.y + node->leftNode->split][x] = 7;
for (int y = node->leftNode->rect.y + node->leftNode->split; y < rCenterY; y++)
map[y][rCenterX] = 7;
}
void RoomSplitVertical(Node* node) // ๊ฐ๋ก๋ก ๋ถํ ๋ ๊ณต๊ฐ์ ๊ธธ ์ด์ด์ค ๋ ์ฌ์ฉ
{
int lCenterY = node->leftNode->room.y + (node->leftNode->room.height/2);
int lCenterX = node->leftNode->room.x + node->leftNode->room.width;
int rCenterY = node->rightNode->room.y + (node->rightNode->room.height/2);
int rCenterX = node->rightNode->room.x;
for (int x = lCenterX; x <= node->leftNode->rect.x + node->leftNode->split; x++)
map[lCenterY][x] = 7;
int from = lCenterY <= rCenterY ? lCenterY : rCenterY;
int to = lCenterY <= rCenterY ? rCenterY : lCenterY;
for (int y = from; y <= to; y++)
map[y][node->leftNode->rect.x + node->leftNode->split] = 7;
for (int x = node->leftNode->rect.x + node->leftNode->split; x < rCenterX; x++)
map[rCenterY][x] = 7;
}
void GeneratePath(Node* node, int depth) // ๊ธธ ์์ฑ
{
if (depth == maxDepth) return;
GeneratePath(node->leftNode, depth + 1);
GeneratePath(node->rightNode, depth + 1);
if (node->leftNode->rect.x == node->rightNode->rect.x)
RoomSplitHorizon(node);
else
RoomSplitVertical(node);
}
int main(void)
{
srand(time(NULL)); // ๋์ ์์ฑ
Node* root = new Node(0, 0, mapWidth, mapHeight, 0); // ํธ๋ฆฌ์ root ๋
ธ๋ ์์ฑ
memset(map, 0, sizeof(map));
Divide(root, 0);
GenerateRoom(root, 0);
GeneratePath(root, 0);
// ๊ณต๊ฐ ์ ๋ณด๋ก ๊ธธ์ ๊ทธ๋ ค์ฃผ๊ณ , ๋ฐฉ์ ๊ทธ๋ ค์ฃผ์ด ๋ฐฉ์ ํต๊ณผํ๋ ๊ธธ์ด ๋ณด์ด์ง ์๋๋ก ํจ
PrintRoom(root, 0);
PrintMap();
return 0;
}

'๊ฒ์๊ฐ๋ฐ' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
| Xcode, C++ ์ด๋ ์์ฑ์ ํธ์ถ ์๋ ๋ (2) | 2023.09.10 |
|---|---|
| ๋ก๊ทธ๋ผ์ดํฌ ๋งต ์์ฑ ๋ฐฉ์ (2) | 2023.07.26 |
| [1] ํฌ๋กฌ ๋ค์ด๋ ธ ๊ฒ์ - ๋ฐฐ๊ฒฝ, ์บ๋ฆญํฐ ๋ง๋ค๊ธฐ (1) | 2023.07.23 |
| [0] ํฌ๋กฌ ๋ค์ด๋ ธ ๊ฒ์ (T-Rex ๊ฒ์) (1) | 2023.07.23 |