미로찾기 기능 구현
저번 시간에 만들었던 의사코드를 이제는 실제 기능으로 구현하려고 한다.
void MoveMaze(현재 플레이어의 위치좌표 (x), (y) 포인터 )
{
int nkey;
if (_kbhit())
{
nkey = _getch();
if (nkey == ARROW)
{
nkey = _getch();
switch (nkey)
{
case UP:
if (위쪽이 막히지 않았다면)
{
미로의 *(x), *(y)를 길로 변경;
미로의 *(x), *(y)-1을 플레이어로 변경;
*(y)를 *(y)-1 로 변경
}
else if (위쪽이 도착지라면)
{
미로의 *(x), *(y)를 길로 변경;
미로의 *(x), *(y)-1을 플레이어로 변경;
프로그램 종료;
}
break;
case DOWN:
if (아래쪽이 막히지 않았다면)
{
미로의 *(x), *(y)를 길로 변경;
미로의 *(x), *(y)+1을 플레이어로 변경;
*(y)를 *(y)+1 로 변경
}
else if (아래쪽이 도착지라면)
{
미로의 *(x), *(y)를 길로 변경;
미로의 *(x), *(y)-1을 플레이어로 변경;
프로그램 종료;
}
break;
case LEFT:
if (왼쪽이 막히지 않았다면)
{
미로의 *(x), *(y)를 길로 변경;
미로의 *(x)-1, *(y)을 플레이어로 변경;
*(x)를 *(x)-1 로 변경
}
else if (왼쪽이 도착지라면)
{
미로의 *(x), *(y)를 길로 변경;
미로의 *(x), *(y)-1을 플레이어로 변경;
프로그램 종료;
}
break;
case RIGHT:
if (오른쪽이 막히지 않았다면)
{
미로의 *(x), *(y)를 길로 변경;
미로의 *(x)+1, *(y)을 플레이어로 변경;
*(x)를 *(x)+1 로 변경
}
else if (오른쪽이 도착지라면)
{
미로의 *(x), *(y)를 길로 변경;
미로의 *(x), *(y)-1을 플레이어로 변경;
프로그램 종료;
}
break;
}
}
}
}
IsBlock 함수
(막히지 않았다면) 기능은 주어진 좌표가 막힌 곳, 혹은 도착지인지 판정하는 함수로 구현하고자 한다.
2차원 배열에서 막힌 곳은 '1', 도착지는 'y'로 설정했으므로 다음과 같이 구현이 될 수 있다.
int IsBlock(int i, int j)
{
if (maze[i][j] == '1' || maze[i][j] == 'y')
return 1;
else
return 0;
}
해당 좌표가 막힌 곳이거나 도착지라면 1을 리턴, 그렇지 않다면 0을 리턴
IsFinish
(도착지라면) 기능은 좌표가 도착지인지 확인하면 된다.
즉, 해당 좌표가 y인지 확인하면 된다.
int IsFinish(int i, int j)
{
if (maze[i][j] == 'y')
return 1;
else
return 0;
}
해당좌표가 도착지라면 1을 리턴, 아니라면 0을 리턴
좌표 포인터
1, 2, 3단계 미로를 다 출력해보면 플레이어의 위치가 3행 2열 위치에 고정되어 있다는 것을 알 수 있다.
즉, 현재 플레이어 위치좌표 x, y 포인터를 받는 것은 다음과 같이 수정할 수 있다.
// 의사 코드
void MoveMaze(현재 플레이어의 위치좌표 (x), (y) 포인터 )
{
//...
}
// 수정된 코드
void MoveMaze(int *row, int *col )
{
//...
}
int main(void)
{
//...
int row = 2, col = 1; //시작 위치 초기화
while (1)
{
//PrintMazeGame();
MoveMaze(&row, &col);
}
return 0;
}
MoveMaze 함수의 매개변수를 포인터인 int* row, int* col 로 설정했다.
그리고 main 함수에서 row = 2, col = 1로 시작 위치를 초기화했다. (3행 2열)
그 후, 매개변수로 포인터를 받기 때문에 주소값을 넣어줘야 한다.
기능 구현
함수의 매개변수를 완성했으므로 의사코드 기능을 실제 코드로 구현하겠다.
우선, 이전 코드에서 매개변수를 *(x) --> *col, *(y) --> *row 로 바꿔야 한다.
위쪽으로 가는 경우,
case UP:
if (!(IsBlock(*row-1, *col)))
{
maze[*row][*col] = '0';
maze[*row-1][*col] = 'x';
*row -= 1;
}
else if (IsFinish(*row-1, *col))
{
// 임시로 강제종료!
exit(0);
}
break;
IsBlock
// if (위쪽이 막히지 않았다면)
if (!(IsBlock(*row-1, *col))) // 리턴값이 1이므로, !를 붙이세요!
{
//...
}
매개변수로 *row-1을 사용한 이유는?
--> 이동하고자 하는 좌표가 한 칸 위의 좌표이기 때문이다.
if (!(IsBlock(*row-1, *col)))
{
// 미로의 *(x), *(y)를 길로 변경;
maze[*row][*col] = '0';
// 미로의 *(x), *(y)-1을 플레이어로 변경;
maze[*row-1][*col] = 'x';
// *(y)를 *(y)-1 로 변경
*row -= 1;
}
막힌 곳이 아니라면, 이동시켜야 한다.
현재 좌표를 길로 바꾸고 이동할 좌표를 플레이어로 변경시키면 된다.
위쪽으로 이동하는 것이므로 *row의 값을 *row-1로 변경시키면 된다.
IsFinish
//else if (위쪽이 도착지라면)
else if (IsFinish(*row-1, *col))
{
// 임시로 강제종료!
exit(0);
}
IsBlock 함수와 마찬가지로 매개변수는 *row-1을 사용해줬다.
도착지라면 exit 함수를 통해 콘솔을 강제 종료하도록 했다.
최종 코드
// maze.c
#include "mheader.h"
int main(void)
{
int row = 2, col = 1;
char level;
CursorView(0);
GotoXY(XP, YP - 3);
printf("미로 찾기 게임\n");
GotoXY(XP, YP - 2);
printf("난이도를 선택하세요. (1, 2, 3) ");
scanf("%c", &level);
LoadMaze(level);
while (1)
{
PrintMazeGame();
PlayMaze(&row, &col);
}
}
// mheader.h
#ifndef HEADER
#define HEADER
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
#include <Windows.h>
#include <conio.h>
#define SIZE 19
#define XP 40
#define YP 5
#define LEFT 75
#define RIGHT 77
#define UP 72
#define DOWN 80
#define ARROW 224
void LoadMaze(char num);
void GotoXY(int x, int y);
void PrintMazeGame();
void CursorView(char show);
void PlayMaze(int* row, int* col);
int IsBlock(int i, int j);
int IsFinish(int i, int j);
char maze[SIZE][SIZE];
#endif
// mheader.c
#include "mheader.h"
void LoadMaze(char num)
{
char path[20] = "./Maze";
strcat(path, &num);
strcat(path, ".txt");
char str_tmp[50] = { 0, };
FILE* f = fopen(path, "r");
for (int i = 0; i < SIZE; i++)
{
fgets(str_tmp, 50, f);
char* ptr = strtok(str_tmp, "\t");
for (int j = 0; j < SIZE; j++)
{
maze[i][j] = *ptr;
ptr = strtok(NULL, "\t");
}
}
fclose(f);
}
void GotoXY(int x, int y)
{
COORD Pos;
Pos.X = x;
Pos.Y = y;
SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), Pos);
}
void PrintMazeGame()
{
for (int i = 0; i < SIZE; i++)
{
GotoXY(XP, YP + i);
for (int j = 0; j < SIZE; j++)
{
if (maze[i][j] == '1')
printf("■");
else if (maze[i][j] == 'y')
printf("★");
else if (maze[i][j] == '0')
printf("□");
else
printf("●");
}
puts("");
}
}
void CursorView(char show)
{
CONSOLE_CURSOR_INFO ConsoleCursor;
ConsoleCursor.bVisible = show;
ConsoleCursor.dwSize = 1;
SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE), &ConsoleCursor);
}
void PlayMaze(int* row, int* col)
{
int nkey;
if (_kbhit())
{
nkey = _getch();
if (nkey == ARROW)
{
nkey = _getch();
switch (nkey)
{
case UP:
if (!(IsBlock(*row - 1, *col)))
{
maze[*row][*col] = '0';
maze[*row - 1][*col] = 'x';
*row -= 1;
}
else if (IsFinish(*row - 1, *col))
{
exit(0);
}
break;
case DOWN:
if (!(IsBlock(*row + 1, *col)))
{
maze[*row][*col] = '0';
maze[*row + 1][*col] = 'x';
*row += 1;
}
else if (IsFinish(*row + 1, *col))
{
exit(0);
}
break;
case LEFT:
if (!(IsBlock(*row, *col-1)))
{
maze[*row][*col] = '0';
maze[*row][*col-1] = 'x';
*col -= 1;
}
else if (IsFinish(*row, *col-1))
{
exit(0);
}
break;
case RIGHT:
if (!(IsBlock(*row, *col + 1)))
{
maze[*row][*col] = '0';
maze[*row][*col + 1] = 'x';
*col += 1;
}
else if (IsFinish(*row, *col + 1))
{
exit(0);
}
break;
}
}
}
}
int IsBlock(int i, int j)
{
if (maze[i][j] == '1' || maze[i][j] == 'y')
return 1;
else
return 0;
}
int IsFinish(int i, int j)
{
if (maze[i][j] == 'y')
return 1;
else
return 0;
}
'C' 카테고리의 다른 글
[C] 미로찾기 게임 최종 (0) | 2021.10.02 |
---|---|
[C] #5 미로찾기 게임 (0) | 2021.10.02 |
[C] #3 미로찾기 게임 (0) | 2021.09.30 |
[C] #2 미로찾기 게임 (0) | 2021.09.28 |
[C] #1 미로찾기 게임 (0) | 2021.09.27 |