W : 위로, A : 왼쪽으로, S : 아래로, D : 오른쪽으로 이동할 수 있으며, R키를 눌러 재시작할 수 있습니다.○ : 골 / ● : 폭탄 / ◆ : 플레이어
// 게임 내에 사용할 변수를 전역으로 선언하였으며, 큰 크기로 사용하지 않을 예정이라 byte(1 byte)로 선언했습니다.
const byte PLAYER = 1; // 플레이어의 객체 값입니다.
const byte PLAYER_ON_GOAL = 2; // 플레이어가 골 지점에 들어가 있을때 표시할 값입니다.
const byte BOMB = 3; // 폭탄
const byte BOMB_ON_GOAL = 4; // 폭탄 위 골
const byte GOAL = 5; // 골
const byte WALL = 9; // 벽
const byte EMPTY = 0; // 빈공간
static byte[,] map = new byte[20,20]; // 맵은 고정크기로 20 * 20으로 선업했습니다.
const byte MAXBOMB = 8; // 최대 폭탄 갯수(후술할 맵 생성기에서 사용)
static byte bombs = 0; // 폭탄 갯수
static int CountFootStep = 0; // 후술할 점수 계산에 사용될 예정입니다.
static Position player = new Position(); // 후술할 좌표를 저장하기 위한 struct입니다.
static void Main(string[] args)
{
// 커서(마우스가 아닌 Console 내에 깜빡이는 부분)를 Console 내에 보이게 할 것인지 정하는 명령어입니다.
Console.CursorVisible = true;
// 함수입니다.
Loader();
// 게임에 승리 조건을 만족하기 전까지 게임이 종료 되지 않게 무한 루프를 걸어줬습니다.
while(true)
{
// BOMB이라고 선언된 전역변수를 넘겨줘 BOMB이 있는 지 없는 지를 판별합니다.
if (!ScanerBool(BOMB))
{
// Ending이라는 함수를 만들어 게임 종료 조건을 검사하며, 만약 재시작을 원하는 경우도 추가되어 있습니다.
if(Ending())
{
break; // 조건 성립시 게임 종료
}
}
Move(); // 조건에 부합하지 않는 경우 움직임으로 넘겨줍니다.
}
}
static bool ScanerBool(byte target)
{
// 2중첩 for문을 사용하여, 모든 맵에서 검사를 진행하지만, 가장자리 부분은 벽만 존재하기 때문에 i와 j에 1을 넣고 map 크기보다 1 작게 검사를 합니다.
for (int i = 1; i < map.GetLength(0) - 1; i++)
{
for (int j = 1; j < map.GetLength(1) - 1; j++)
{
// 입력받은 객체가 존재하는 검사 후 있을 경우 반환하며, 종료됩니다.
if (map[i,j] == target)
{
return true;
}
}
}
// 없는 경우 false로 반환됩니다.
return false;
}
// 움직임을 제어할 함수입니다.
static void Move()
{
// key에 키보드로 입력 받은 키 값을 저장하며 ReadKey(true)는 console에 입력된 키 값을 보이지 않게 합니다.
ConsoleKey key = Console.ReadKey(true).Key;
// 움직이는 것이기 때문에 움직임에 1을 더했습니다.
CountFootStep++;
// 키보드로 입력 받은 값을 검사할 switch(key)입니다.
switch(key)
{
// w키를 입력했을 시, 해당 좌표에 맞게 움직임을 제어합니다.
case ConsoleKey.W:
// 위로 이동시 console 상에서는 반대로 가는 것이기 때문에 -1을 해줍니다.
Swaper(0, -1);
break;
case ConsoleKey.A:
Swaper(-1, 0);
break;
case ConsoleKey.S:
Swaper(0, 1);
break;
case ConsoleKey.D:
Swaper(1, 0);
break;
// R키를 누를 시 이동이 아닌 재시작을 할 것이기 때문에 Loader()라는 함수를 만들었습니다.
case ConsoleKey.R:
Loader();
break;
}
}
static void Swaper(int dX, int dY)
{
// 현제 위치에서 다음 위치에 있는 객체를 조사 및 교체를 위해 좌표를 저장합니다.
Position tPos = new Position()
{
X = player.X + dX,
Y = player.Y + dY
};
// 만약 폭탄을 미는 경우 그 다음에 있는 객체를 조사해야 하기 때문에 추가로 더 더해서 저장합니다.
Position tOPos = new Position()
{
X = tPos.X + dX,
Y = tPos.Y + dY
};
//처음 움직였을때 갖일 수 있는 변수는 빈 공간, 골 위에 폭탄, 폭탄, 골, 벽이 있습니다.
// 벽은 따로 조건을 넣지 않아도 조건 검사에서 참이 될 수 없기 때문에 따로 넣지 않았습니다.
// 다음 좌표가 공간인 경우
if (map[tPos.Y,tPos.X] == EMPTY)
{
//빈 공간인 경우 현제 좌표만 검사하면 되고 현제 좌표에 변수는 2가지 밖에 없기 때문에 2가지만 넣었습니다.
// 현제 좌표가 골 위에 있는 경우
if (map[player.Y,player.X] == PLAYER_ON_GOAL)
{
// 골인 경우, 현제 좌표에는 goal을 넣고 다음 좌표에는 플레이어를 넣습니다.
map[player.Y, player.X] = GOAL;
// 다음 좌표에 플레이어 넣기
map[tPos.Y, tPos.X] = PLAYER;
// Printer(Position, byte)함수로 넣어줍니다.
Printer(player, GOAL);
Printer(tPos,PLAYER);
// 마지막에는 플레이어의 좌표를 넣어줍니다.
player = tPos;
}
// 아닌 경우에는 빈 공간 위에 서 있을 것이기 때문에 빈 공간으로 대체합니다.
else
{
map[player.Y, player.X] = EMPTY;
map[tPos.Y, tPos.X] = PLAYER;
Printer(player, EMPTY);
Printer(tPos, PLAYER);
player = tPos;
}
}
// 다음 좌표가 골 위에 폭탄인 경우
else if(map[tPos.Y, tPos.X] == BOMB_ON_GOAL)
{
// 현제 좌표가 골 위에 플레이어가 있는 경우
if(map[player.Y, player.X] == PLAYER_ON_GOAL)
{
// 이 다음 다음 좌표(이동 방향에 2번째 지점)이 EMPTY인 경우
if (map[tPos.Y + dY, tPos.X + dX] == EMPTY)
{
map[player.Y, player.X] = GOAL;
map[tPos.Y, tPos.X] = PLAYER_ON_GOAL;
map[tOPos.Y, tOPos.X] = BOMB;
Printer(player, GOAL);
Printer(tPos, PLAYER_ON_GOAL);
Printer(tOPos, BOMB);
player = tPos;
}
// 골인 경우
else if (map[tPos.Y + dY, tPos.X + dX] == GOAL)
{
map[player.Y, player.X] = GOAL;
map[tPos.Y, tPos.X] = PLAYER_ON_GOAL;
map[tOPos.Y, tOPos.X] = BOMB_ON_GOAL;
Printer(player, GOAL);
Printer(tPos, PLAYER_ON_GOAL);
Printer(tOPos, BOMB_ON_GOAL);
player = tPos;
}
}
// 플레이어가 골 위에 있는 경우가 아니라면, 빈 공간에 있는 경우 밖에 없기 때문에 2가지만 검사합니다.
else
{
// 다음 다음 이 빈 공간인 경우
if (map[tOPos.Y, tOPos.X] == EMPTY)
{
map[player.Y, player.X] = EMPTY;
map[tPos.Y, tPos.X] = PLAYER_ON_GOAL;
map[tOPos.Y, tOPos.X] = BOMB;
Printer(player, EMPTY);
Printer(tPos, PLAYER_ON_GOAL);
Printer(tOPos, BOMB);
player = tPos;
}
// 골인 경우
else if (map[tOPos.Y, tOPos.X] == GOAL)
{
map[player.Y, player.X] = EMPTY;
map[tPos.Y, tPos.X] = PLAYER_ON_GOAL;
map[tOPos.Y, tOPos.X] = BOMB_ON_GOAL;
Printer(player, EMPTY);
Printer(tPos, PLAYER_ON_GOAL);
Printer(tOPos, BOMB_ON_GOAL);
player = tPos;
}
}
}
// 다음 지점이 폭탄인 경우
else if(map[tPos.Y, tPos.X] == BOMB)
{
// 위와 같습니다.
if(map[player.Y, player.X] == PLAYER_ON_GOAL)
{
if (map[tOPos.Y, tPos.X + dX] == EMPTY)
{
map[player.Y, player.X] = GOAL;
map[tPos.Y, tPos.X] = PLAYER;
map[tOPos.Y, tOPos.X] = BOMB;
Printer(player, GOAL);
Printer(tPos, PLAYER);
Printer(tOPos, BOMB);
player = tPos;
}
else if (map[tOPos.Y, tOPos.X] == GOAL)
{
map[player.Y, player.X] = GOAL;
map[tPos.Y, tPos.X] = PLAYER;
map[tOPos.Y, tOPos.X] = BOMB_ON_GOAL;
Printer(player, GOAL);
Printer(tPos, PLAYER);
Printer(tOPos, BOMB_ON_GOAL);
player = tPos;
}
}
else
{
if (map[tOPos.Y, tPos.X + dX] == EMPTY)
{
map[player.Y, player.X] = EMPTY;
map[tPos.Y, tPos.X] = PLAYER;
map[tOPos.Y, tOPos.X] = BOMB;
Printer(player, EMPTY);
Printer(tPos, PLAYER);
Printer(tOPos, BOMB);
player = tPos;
}
else if (map[tOPos.Y, tOPos.X] == GOAL)
{
map[player.Y, player.X] = EMPTY;
map[tPos.Y, tPos.X] = PLAYER;
map[tOPos.Y, tOPos.X] = BOMB_ON_GOAL;
Printer(player, EMPTY);
Printer(tPos, PLAYER);
Printer(tOPos, BOMB_ON_GOAL);
player = tPos;
}
}
}
// 다음 좌표가 골인 경우
else if (map[tPos.Y, tPos.X] == GOAL)
{
if (map[player.Y, player.X] == PLAYER_ON_GOAL)
{
map[player.Y, player.X] = GOAL;
map[tPos.Y, tPos.X] = PLAYER_ON_GOAL;
Printer(player, GOAL);
Printer(tPos, PLAYER_ON_GOAL);
player = tPos;
}
else
{
map[player.Y, player.X] = EMPTY;
map[tPos.Y, tPos.X] = PLAYER_ON_GOAL;
Printer(player, EMPTY);
Printer(tPos, PLAYER_ON_GOAL);
player = tPos;
}
}
}
// 2중첩 For문을 사용하여, 제작하여도 되지만, 그런 경우, 이동키를 누를 경우 반짝이는 현상(해당 console을 지운 후 빠르게 다시 작성 되지만, 눈에 보이기 때문)이 있으며, 꾹 누를 경우, 매우 빨라 화면이 표시 되지 않습니다.
// 그래서 다른 방식(왔던 곳과 이동할 곳만 선택적으로 덮어쓰기)을 사용했습니다.
static void Printer(Position pos, byte target)
{
//Console에서 지원하는 SetCursorPosition()함수를 이용하여, 해당 좌표로 이동(X만 *2를 한 이유는 ●와 같은 문자는 2 byte(2개의 공간)이 필요하기 때문에 빈공간도 2 byte를 점유하기때문에, 해당 좌표보다 2배로 더 이동해야 합니다.) 후 덮어쓰기 했습니다.
Console.SetCursorPosition(pos.X*2, pos.Y);
switch (target)
{
// 받은 수에 부합하는 문자를 표시합니다.
case EMPTY:
Console.Write(" ");
break;
case BOMB:
Console.Write("●");
break;
case BOMB_ON_GOAL:
Console.Write("◎");
break;
case GOAL:
Console.Write("○");
break;
case PLAYER:
Console.Write("◆");
break;
case PLAYER_ON_GOAL:
Console.Write("@");
break;
// default로 예외처리는 따로 하지 않았습니다. (플레이어의 직접적인 입력이 따로 없었기 때문이지만, 협업 시 반드시 넣어야합니다.)
}
}
static bool Ending()
{
// 간단하게 넣은 점수 계산입니다.
float score = (float) (bombs * 500) / CountFootStep;
// 표시를 맵보다 아래쪽에 출력하기 위해 커서 위치를 강제 이동시켰습니다.
Console.SetCursorPosition(map.GetLength(1), map.GetLength(0));
// 축하 메세지 및 이동거리와 점수 출력
Console.WriteLine("\n축하합니다.\n"+
"게임을 클리어 하셨습니다.\n"+
$"총 이동거리는 {CountFootStep}입니다.\n"+
$"당신의 점수는 {score.ToString("n3")}입니다.",
"재시작할려면, R 키를 눌러주세요.");
// R키를 누를 경우, 재시작 할 수 있게 예외처리 하였습니다.
if (Console.ReadKey().Key == ConsoleKey.R)
{
// 재시작 시 맵을 재생성해야 하기 때문에 따로 함수를 제작하였습니다.
Loader();
return false;
}
return true;
}
static void Loader()
{
// Console의 모든 출력을 지운 후
Console.Clear();
// MapGen()이라는 함수를 통해 맵을 재생성 후
MapGen();
// Player의 위치를 찾은 후 저장하고
player = ScanerPos(PLAYER);
// MapPrint() 함수를 이용해 맵을 출력합니다.
MapPrint();
}
static void MapGen()
{
// 무작위로 생성하기 위해 random 함수를 사용했습니다.
Random rd = new Random();
// 플레이어는 1개의 객체만 존재해야하기 때문에 bool 타입으로 선언했습니다.
bool playerAlive = false;
// 만약 운이 낮아 플레이어가 끝지점까지 생성이 안될 경우 강제 생성되게하기 위해 short 타입(map은 20*20 으로 400이지만 byte는 255까지 밖에 검사할 수 없기 때문에)으로 선언했습니다.
short playerExepsion = 0;
// 폭탄의 갯수를 셉니다.
byte bombCounter = 0;
// 골의 갯수를 셉니다. 폭탄보다 갯수가 많아지면 안되고 적으면 안되기 때문입니다.
byte goalCounter = 0;
for (int i = 0; i < map.GetLength(0); i++)
{
for (int j = 0; j < map.GetLength(1); j++)
{
// 가장자리는 벽만 있을 예정이기 때문에 조건을 걸어 줍니다.
// i와 j가 0인 경우는 가장자리이며, map의 크기(배열은 0부터 세기 때문에 -1을 해줍니다)의 끝 부분 또한 가장자리입니다.
if ((i == 0 || i == map.GetLength(0)-1 ) || ( j == 0 || j == map.GetLength(1)-1) )
{
// 해당 좌표에 WALL이라는 숫자(객체)를 넣어줍니다.
map[i, j] = WALL;
}
// 가장자리가 아닌경우 랜덤함수로 0~49(1/50 확률로) 플레이어가 생성되며, 만약 특정 지점까지 갔을때까지 생성이 안된 경우 강제 생성됩니다.
// 플레이어는 2개 이상의 객체가 존재하면 안되기 때문에 존재하는 지 검사합니다.
else if ((rd.Next(0,50) == 0 || playerExepsion > 300) && !playerAlive )
{
map[i,j] = PLAYER;
// 생성된 경우 예외처리를 위해 true로 전환합니다.
playerAlive = true;
}
// 폭탄의 최대치 이상 스폰하지 않게 하면서, 1/30 확률로 생성되고, 벽과 바로 붙은 경우, 문제를 해결할 수 없는 상황이 만들어 질 수 있기 때문에 예외처리해줍니다.
else if ((bombCounter < MAXBOMB && rd.Next(0,30) == 0) && ((i > 1 && i < map.GetLength(0) - 2) && (j > 1 && j < map.GetLength(1) - 2)))
{
// 폭탄이 생성된 경우, 최대 갯수를 넘지 않게 하기 위해 1을 더해줍니다.
bombCounter++;
map[i, j] = BOMB;
}
// 폭탄보다 많은 양의 goal을 생성하면 안되기 때문에, 예외처리해주면서, 맵에 끝(벽 바로 전 지점)에 가까워진 경우, 강제로 생성하게 만듭니다.
// 완전 무작위로 생성할 경우, 폭탄 갯수보다 낮게 생성 될 수 있기 때문입니다.
else if ((bombCounter > goalCounter && rd.Next(0, 10) == 0) || (i == (map.GetLength(1)-2) && bombCounter > goalCounter ))
{
goalCounter++;
map[i, j] = GOAL;
}
else
{
// 그 외에 경우에는 빈 공간으로 넣어줍니다.
map[i, j] = EMPTY;
}
// 변수를 사용했지만 지금 생각해보면, i와 j만을 이용해서, 예외처리를 할 수 있었던것 같습니다.
if (!playerAlive)
playerExepsion++;
}
}
// 이후 폭탄 갯수를 전역변수에 전달합니다.
bombs = bombCounter;
}
static void MapPrint()
{
for (int i = 0; i < map.GetLength(0); i++)
{
for (int j = 0; j < map.GetLength(1); j++)
{
// map의 좌표를 받아와서 맞는 문자로 전환해서 표시합니다.
switch(map[i,j])
{
case WALL:
Console.Write("※");
break;
case GOAL:
Console.Write("○");
break;
case BOMB:
Console.Write("●");
break;
case PLAYER:
Console.Write("◆");
break;
case EMPTY:
// 위에서도 서술했 듯이 2칸으로 표시합니다.
Console.Write(" ");
break;
}
}
Console.WriteLine();
}
// 폭탄의 갯수를 표시해줍니다.
Console.WriteLine($"폭탄 갯수 : {bombs}");
}
static Position ScanerPos(byte target)
{
Position pos;
for (int i = 1; i < map.GetLength(0) - 1; i++)
{
for (int j = 1; j < map.GetLength(1) - 1; j++)
{
// 맵에 처음으로 식별된 객체의 좌표를 반환합니다.
if (map[i, j] == target)
{
return pos = new Position()
{
X = j,
Y = i
};
}
}
}
// 만약 식별하지 못한 경우, -1로 반환합니다.
// 저는 간단하게만 작성하여, 반환처리하지 않았지만, 항상 모든 경우에 대비하기 위해, 반드시 예외처리를 해야합니다.
return pos = new Position()
{
X = -1,
Y = -1
};
}
// struct로 선언된 좌표값을 저장할 구조체입니다.
public struct Position
{
public int X;
public int Y;
}
using System;
using System.Collections.Generic;
using System.Data;
using System.IO;
using System.Linq;
using System.Runtime.Remoting.Messaging;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleProject_0
{
internal class Program
{
const byte PLAYER = 1;
const byte PLAYER_ON_GOAL = 2;
const byte BOMB = 3;
const byte BOMB_ON_GOAL = 4;
const byte GOAL = 5;
const byte WALL = 9;
const byte EMPTY = 0;
static byte[,] map = new byte[20,20];
const byte MAXBOMB = 8;
static byte bombs = 0;
static int CountFootStep = 0;
static Position player = new Position();
static void Main(string[] args)
{
Console.CursorVisible = false;
Loader();
while(true)
{
if (!ScanerBool(BOMB))
{
if(Ending())
{
break;
}
}
Move();
}
}
static void Move()
{
ConsoleKey key = Console.ReadKey(true).Key;
CountFootStep++;
switch (key)
{
case ConsoleKey.W:
Swaper(0, -1);
break;
case ConsoleKey.A:
Swaper(-1, 0);
break;
case ConsoleKey.S:
Swaper(0, 1);
break;
case ConsoleKey.D:
Swaper(1, 0);
break;
case ConsoleKey.R:
Loader();
break;
}
}
static void Swaper(int dX, int dY)
{
Position tPos = new Position()
{
X = player.X + dX,
Y = player.Y + dY
};
Position tOPos = new Position()
{
X = tPos.X + dX,
Y = tPos.Y + dY
};
if (map[tPos.Y,tPos.X] == EMPTY)
{
if (map[player.Y,player.X] == PLAYER_ON_GOAL)
{
map[player.Y, player.X] = GOAL;
map[tPos.Y, tPos.X] = PLAYER;
Printer(player, GOAL);
Printer(tPos,PLAYER);
player = tPos;
}
else
{
map[player.Y, player.X] = EMPTY;
map[tPos.Y, tPos.X] = PLAYER;
Printer(player, EMPTY);
Printer(tPos, PLAYER);
player = tPos;
}
}
else if(map[tPos.Y, tPos.X] == BOMB_ON_GOAL)
{
if(map[player.Y, player.X] == PLAYER_ON_GOAL)
{
if (map[tPos.Y + dY, tPos.X + dX] == EMPTY)
{
map[player.Y, player.X] = GOAL;
map[tPos.Y, tPos.X] = PLAYER_ON_GOAL;
map[tOPos.Y, tOPos.X] = BOMB;
Printer(player, GOAL);
Printer(tPos, PLAYER_ON_GOAL);
Printer(tOPos, BOMB);
player = tPos;
}
else if (map[tPos.Y + dY, tPos.X + dX] == GOAL)
{
map[player.Y, player.X] = GOAL;
map[tPos.Y, tPos.X] = PLAYER_ON_GOAL;
map[tOPos.Y, tOPos.X] = BOMB_ON_GOAL;
Printer(player, GOAL);
Printer(tPos, PLAYER_ON_GOAL);
Printer(tOPos, BOMB_ON_GOAL);
player = tPos;
}
}
else
{
if (map[tOPos.Y, tOPos.X] == EMPTY)
{
map[player.Y, player.X] = EMPTY;
map[tPos.Y, tPos.X] = PLAYER_ON_GOAL;
map[tOPos.Y, tOPos.X] = BOMB;
Printer(player, EMPTY);
Printer(tPos, PLAYER_ON_GOAL);
Printer(tOPos, BOMB);
player = tPos;
}
else if (map[tOPos.Y, tOPos.X] == GOAL)
{
map[player.Y, player.X] = EMPTY;
map[tPos.Y, tPos.X] = PLAYER_ON_GOAL;
map[tOPos.Y, tOPos.X] = BOMB_ON_GOAL;
Printer(player, EMPTY);
Printer(tPos, PLAYER_ON_GOAL);
Printer(tOPos, BOMB_ON_GOAL);
player = tPos;
}
}
}
else if(map[tPos.Y, tPos.X] == BOMB)
{
if(map[player.Y, player.X] == PLAYER_ON_GOAL)
{
if (map[tOPos.Y, tPos.X + dX] == EMPTY)
{
map[player.Y, player.X] = GOAL;
map[tPos.Y, tPos.X] = PLAYER;
map[tOPos.Y, tOPos.X] = BOMB;
Printer(player, GOAL);
Printer(tPos, PLAYER);
Printer(tOPos, BOMB);
player = tPos;
}
else if (map[tOPos.Y, tOPos.X] == GOAL)
{
map[player.Y, player.X] = GOAL;
map[tPos.Y, tPos.X] = PLAYER;
map[tOPos.Y, tOPos.X] = BOMB_ON_GOAL;
Printer(player, GOAL);
Printer(tPos, PLAYER);
Printer(tOPos, BOMB_ON_GOAL);
player = tPos;
}
}
else
{
if (map[tOPos.Y, tPos.X + dX] == EMPTY)
{
map[player.Y, player.X] = EMPTY;
map[tPos.Y, tPos.X] = PLAYER;
map[tOPos.Y, tOPos.X] = BOMB;
Printer(player, EMPTY);
Printer(tPos, PLAYER);
Printer(tOPos, BOMB);
player = tPos;
}
else if (map[tOPos.Y, tOPos.X] == GOAL)
{
map[player.Y, player.X] = EMPTY;
map[tPos.Y, tPos.X] = PLAYER;
map[tOPos.Y, tOPos.X] = BOMB_ON_GOAL;
Printer(player, EMPTY);
Printer(tPos, PLAYER);
Printer(tOPos, BOMB_ON_GOAL);
player = tPos;
}
}
}
else if (map[tPos.Y, tPos.X] == GOAL)
{
if (map[player.Y, player.X] == PLAYER_ON_GOAL)
{
map[player.Y, player.X] = GOAL;
map[tPos.Y, tPos.X] = PLAYER_ON_GOAL;
Printer(player, GOAL);
Printer(tPos, PLAYER_ON_GOAL);
player = tPos;
}
else
{
map[player.Y, player.X] = EMPTY;
map[tPos.Y, tPos.X] = PLAYER_ON_GOAL;
Printer(player, EMPTY);
Printer(tPos, PLAYER_ON_GOAL);
player = tPos;
}
}
}
static void Printer(Position pos, byte target)
{
Console.SetCursorPosition(pos.X*2, pos.Y);
switch (target)
{
case EMPTY:
Console.Write(" ");
break;
case BOMB:
Console.Write("●");
break;
case BOMB_ON_GOAL:
Console.Write("◎");
break;
case GOAL:
Console.Write("○");
break;
case PLAYER:
Console.Write("◆");
break;
case PLAYER_ON_GOAL:
Console.Write("@");
break;
}
}
static bool Ending()
{
float score = (float) (bombs * 500) / CountFootStep;
Console.SetCursorPosition(map.GetLength(1), map.GetLength(0));
Console.WriteLine("\n축하합니다.\n"+
"게임을 클리어 하셨습니다.\n"+
$"총 이동거리는 {CountFootStep}입니다.\n"+
$"당신의 점수는 {score.ToString("n3")}입니다.",
"재시작할려면, R 키를 눌러주세요.");
if (Console.ReadKey().Key == ConsoleKey.R)
{
Loader();
return false;
}
return true;
}
static void Loader()
{
Console.Clear();
MapGen();
player = ScanerPos(PLAYER);
MapPrint();
}
static bool ScanerBool(byte target)
{
for (int i = 1; i < map.GetLength(0) - 1; i++)
{
for (int j = 1; j < map.GetLength(1) - 1; j++)
{
if (map[i,j] == target)
{
return true;
}
}
}
return false;
}
static Position ScanerPos(byte target)
{
Position pos;
for (int i = 1; i < map.GetLength(0) - 1; i++)
{
for (int j = 1; j < map.GetLength(1) - 1; j++)
{
if (map[i, j] == target)
{
return pos = new Position()
{
X = j,
Y = i
};
}
}
}
return pos = new Position()
{
X = -1,
Y = -1
};
}
static void MapPrint()
{
for (int i = 0; i < map.GetLength(0); i++)
{
for (int j = 0; j < map.GetLength(1); j++)
{
switch(map[i,j])
{
case WALL:
Console.Write("※");
break;
case GOAL:
Console.Write("○");
break;
case BOMB:
Console.Write("●");
break;
case PLAYER:
Console.Write("◆");
break;
case EMPTY:
Console.Write(" ");
break;
}
}
Console.WriteLine();
}
Console.WriteLine($"폭탄 갯수 : {bombs}");
}
static void MapGen()
{
Random rd = new Random();
bool playerAlive = false;
short playerExepsion = 0;
byte bombCounter = 0;
byte goalCounter = 0;
for (int i = 0; i < map.GetLength(0); i++)
{
for (int j = 0; j < map.GetLength(1); j++)
{
if ((i == 0 || i == map.GetLength(0)-1 ) || ( j == 0 || j == map.GetLength(1)-1) )
{
map[i, j] = WALL;
}
else if ((rd.Next(0,50) == 0 || playerExepsion > 300) && !playerAlive )
{
map[i,j] = PLAYER;
playerAlive = true;
}
else if ((bombCounter < MAXBOMB && rd.Next(0,30) == 0) && ((i > 1 && i < map.GetLength(0) - 2) && (j > 1 && j < map.GetLength(1) - 2)))
{
bombCounter++;
map[i, j] = BOMB;
}
else if ((bombCounter > goalCounter && rd.Next(0, 10) == 0) || (i == (map.GetLength(1)-2) && bombCounter > goalCounter ))
{
goalCounter++;
map[i, j] = GOAL;
}
else
{
map[i, j] = EMPTY;
}
if (!playerAlive)
playerExepsion++;
}
}
bombs = bombCounter;
}
}
}
public struct Position
{
public int X;
public int Y;
}