이전에 간단히 렌더링 하는 것을 해봤는데 본격적으로 Map 만드는 연습
기본적인 테두리만 막힌 MAP
메인 함수에서 Board의 size가 [25,25]인 Map
class Board
{
const char CIRCLE = '\u25cf' //원모양
public TileType[,] _tile;
public int _size;
public enum TileType
{
Empty,
Wall
}
public void Initialize(int size)
{
_tile = new TileType[size,size];
_size = size;
for(int y = 0; y < _size; y++)
{
for(int x = 0; x < _size ; x++)
{
if(x == 0 || x == _size-1 || y == 0 || y == _size -1)
_tile[y,x] == TileType.Wall;
else
_tile[y,x] == TileType.Empty;
}
}
}
public void Render()
{
ConsoleColor prevColor = Console.ForegroundColor;
for(int y = 0; y < _size; y++)
{
for(int x = 0; x <_size; x++)
{
Console.ForegroundColor = GetTileColor(_tile[y,x]);
Console.Write(CIRCLE);
}
}
ConsoleForegrounderColor = prevColor;
}
public ConsoleColor GetTileColor(TileType tile)
{
switch(tile)
{
case TileType.Empty:
return ConsoleColor.Green;
case TileType.Wall:
return ConsoleColor.Red;
default:
return ConsoleColor.Green;
}
}
}
Binary Tree 미로
Mazes for Programmers 책에서 나온 가장 기본적인 미로 생성 알고리즘 중 하나
위에서 기본적인 맵을 기반으로 알아보려 한다.
public void Initialize(int size)
{
_tile = new TileType[size,size];
_size = size;
//길을 다 막아버리는 작업
for(int y = 0; y < _size; y++)
{
for(int x = 0; x < _size ; x++)
{
if(x % 2 == 0 || y % 2== 0) // 1단계 : x나 y가 짝수인 경우 벽으로 막는다.
_tile[y,x] == TileType.Wall;
else
_tile[y,x] == TileType.Empty;
}
}
}
public void Initialize(int size)
{
_tile = new TileType[size,size];
_size = size;
//1단계 : 길을 다 막아버리는 작업
for(int y = 0; y < _size; y++)
{
for(int x = 0; x < _size ; x++)
{
if(x % 2 == 0 || y % 2== 0) // 1단계 : x나 y가 짝수인 경우 벽으로 막는다.
_tile[y,x] == TileType.Wall;
else
_tile[y,x] == TileType.Empty;
}
}
//2단계 : Empty에서 랜덤으로 우측 혹은 아래로 길을 뚫는 작업
Random rand = new Random();
for (int y = 0; y < _size; y++)
{
for (int x = 0; x < _size; x++)
{
if (x % 2 == 0 || y % 2 == 0)
continue;
if(rand.Next(0,2) == 0)
_tile[y, x+1] = TileType.Empty;
else
_tile[y+1,x] = TileType.Empty;
}
}
}
결과를 보면,
if(size % 2 ==0)
return;
public void Initialize(int size)
{
_tile = new TileType[size,size];
_size = size;
//1단계 : 길을 다 막아버리는 작업
for(int y = 0; y < _size; y++)
{
for(int x = 0; x < _size ; x++)
{
if(x % 2 == 0 || y % 2== 0) // 1단계 : x나 y가 짝수인 경우 벽으로 막는다.
_tile[y,x] == TileType.Wall;
else
_tile[y,x] == TileType.Empty;
}
}
//2단계 : Empty에서 랜덤으로 우측 혹은 아래로 길을 뚫는 작업
Random rand = new Random();
for (int y = 0; y < _size; y++)
{
for (int x = 0; x < _size; x++)
{
if (x % 2 == 0 || y % 2 == 0)
continue;
//추가해서 가장자리 이전 y좌표는 오른쪽으로 길을 내주고 x좌표는 밑으로 길을 내준다.
if(y == _size -2 && x == _size -2)
continue;
if( y == _size - 2)
{
_tile[y,x+1] = TileType.Empty;
continue;
}
if( x == _size -2)
{
_tile[y+1,x] = TileType.Empty;
continue;
}
if(rand.Next(0,2) == 0)
_tile[y, x+1] = TileType.Empty;
else
_tile[y+1,x] = TileType.Empty;
}
}
}
이 알고리즘의 단점은 마지막 y좌표와 x좌표의 마지막 줄들이 일자로 계속 길이 있는것으로 볼 수 있다.
SideWinder 미로 생성 알고리즘
위에 만들어봤던 binaryTree 알고리즘 처럼 미로 알고리즘 중에서는 간단한 편에 속하는데
간단할수록 미로가 단조롭게 나온다는 것을 알고 있어야한다.
아까처럼 다시 막은 상태에서
for (int y = 0; y < _size; y++)
{
for (int x = 0; x < _size; x++)
{
if (x % 2 == 0 || y % 2 == 0)
_tile[y, x] = TileType.Wall;
else
_tile[y, x] = TileType.Empty;
}
}
Random rand = new Random();
for (int y = 0; y < _size; y++)
{
int count = 1;
for (int x = 0; x < _size; x++)
{
if (x % 2 == 0 || y % 2 == 0)
continue;
if (rand.Next(0, 2) == 0) //가로로 길을 내는 부분
{
_tile[y, x + 1] = TileType.Empty;
count++; //가로로 몇번 길을 냈는지 count
}
else //세로로 길을 내는 부분
{
int randomIndex = rand.Next(0,count);
_tile[y + 1, x - randomIndex * 2] = TileType.Empty;
count = 1;
}
}
}
세로로 길을 내는 부분에서 x - randomIndex * 2 부분은 아까 아이디어 2번부분에서
지금까지 길을 낸 가로줄 초록에서 랜덤으로 하나를 선택해야하니까 [공간][벽][공간][벽]
으로 이루어져있으니 벽을 넘어 이전 공간으로 가기 위해 x좌표를 2씩 뒤로 가야하기 때문이다.
아까 BinaryTree처럼 마지막 이전부분은 똑같은 코드로 처리해준다.
for (int y = 0; y < _size; y++)
{
for (int x = 0; x < _size; x++)
{
if (x % 2 == 0 || y % 2 == 0)
_tile[y, x] = TileType.Wall;
else
_tile[y, x] = TileType.Empty;
}
}
Random rand = new Random();
for (int y = 0; y < _size; y++)
{
int count = 1;
for (int x = 0; x < _size; x++)
{
if (x % 2 == 0 || y % 2 == 0)
continue;
if( y == _size -2 && x == _size -2)
continue;
if( y == _size - 2)
{
_tile[y,x+1] = TileType.Empty;
continue;
}
if( x == _size -2)
{
_tile[y+1,x] = TileType.Empty;
continue;
}
if (rand.Next(0, 2) == 0) //가로로 길을 내는 부분
{
_tile[y, x + 1] = TileType.Empty;
count++; //가로로 몇번 길을 냈는지 count
}
else //세로로 길을 내는 부분
{
int randomIndex = rand.Next(0,count);
_tile[y + 1, x - randomIndex * 2] = TileType.Empty;
count = 1;
}
}
}
BinaryTree처럼 SideWinder 방법도 마지막 이전 줄은 모두 공간으로 단조롭게 나타는 단점이 있다.