맨 처음 문제가
1. 포인터
2. 동적할당
3. 파일입출력
4. 텍스트 게임 금지(글로만 된 스토리 게임)
필자는 곰곰히 생각하고 하루만에 구현 할 수 있는 쉽고 재밌는 게임인 오목을 만들기로 했다.
또한, 규칙은 복잡하니 단 하나 5개이상으로 연결만 되면 승리 라는 소박한 규칙만 만들었다.
맨 처음으로 Define.h / Define.cpp 를 만들었다. 필자의 프로그래밍 습관이기도 한데 #include XXX 이렇게 계속 선언할 것을 그냥 헤더파일 하나로 모았다.
// Define.h
#pragma once
#include<iostream>
#include<Windows.h>
#include<conio.h>
using namespace std;
void gotoxy(int x, int y); // 이동을 지시해 줄 함수
enum { LEFT = 75, RIGHT = 77, UP = 72, DOWN = 80, SPACE = 32 };
// Define.cpp
#include"Define.h"
void gotoxy(int x, int y)
{
COORD Pos = { x,y };
SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), Pos);
}
그 다음 게임을 만들기 위해서 이동을 해야되지 않겠는가? 필자는 CPoint.h / CPoint.cpp로 그리는 함수, 움직이게 키를 받는 함수, 승리 조건 체크 함수를 만들었다.
// CPoint.h
#pragma once
#include"map.h"
class CPoint : public MAP
{
int x; // x좌표
int y; // y좌표
public:
CPoint(int x, int y); // 생성자
void screen(); // 그리는 함수
void input(int &p); //키를 입력 받는 함수
bool check(int &p); // 승리 조건 체크 함수
};
// CPoint.cpp
#include"CPoint.h"
CPoint::CPoint(int x, int y)
{
this->x = x;
this->y = y;
}
void CPoint::screen()
{
system("cls");
for (int j = 0; j < Get_height(); j++)
{
for (int i = 0; i < Get_width(); i++)
{
if (xy[j][i] == 1)
cout << "★";
else if (xy[j][i] == 2)
cout << "☆";
else if (xy[j][i] == 0)
cout << "╋";
}
cout << "\n";
}
}
void CPoint::input(int &p)
{
int c;
bool turn = true;
while (turn)
{
c = getch();
switch (c)
{
case RIGHT:
{
++x;
if (x >= Get_width() - 1)
--x;
gotoxy(x * 2, y);
break;
}
case LEFT:
{
--x;
if (x <= 0)
++x;
gotoxy(x * 2, y);
break;
}
case UP:
{
--y;
if (y <= 0)
++y;
gotoxy(x * 2, y);
break;
}
case DOWN:
{
++y;
if (y >= Get_height() - 1)
--y;
gotoxy(x * 2, y);
break;
}
case SPACE:
if (xy[y][x] != 0)
break;
if (p == 2)
{
xy[y][x] = 2;
}
else
{
xy[y][x] = 1;
}
turn = false;
break;
}
}
}
bool CPoint::check(int &p)
{
int j, sum = 0;
for (j = -5; j <= 5; j++) // 좌우 체크
{
if (x + j <= 0 || x + j >= Get_width())
continue;
if (p == xy[y][x + j])
{
sum++;
if (sum == 5)
return false;
}
else
sum = 0;
}
for (j = -5; j <= 5; j++) // 상하 체크
{
if (y + j <= 0 || y + j >= Get_height())
continue;
if (p == xy[y + j][x])
{
sum++;
if (sum == 5)
return false;
}
else
sum = 0;
}
for (j = -5; j <= 5; j++) // 오른쪽 위 왼쪽 아래 체크
{
if (y + j <= 0 || y + j >= Get_height())
continue;
if (x + j <= 0 || x + j >= Get_width())
continue;
if (p == xy[y + j][x + j])
{
sum++;
if (sum == 5)
return false;
}
else
sum = 0;
}
for (j = -5; j <= 5; j++) // 왼쪽 위 오른쪽 아래 체크
{
if (y + j <= 0 || y + j >= Get_height())
continue;
if (x + j <= 0 || x + j >= Get_width())
continue;
if (p == xy[y + j][x - j])
{
sum++;
if (sum == 5)
return false;
}
else
sum = 0;
}
return true;
}
그 다음 맵을 만들려고 했다. 그런데 아까 문제중 파일 입출력을 사용하라고 했는데 오목에서 파일 입출력을 받을 것이라고는 맵 / 랭킹정도 밖에 없다고 생각했다. 하지만 필자는 하루동안 (4시간) 만들어야하는 사명을 가지고 있으므로 맵만 파일입출력을 받기로 했다. 맵 받는게 무진장 쉽다고 생각한 것은 내 착오였다.
일단 텍스트로 맵 정보를 받는데, 그 크기를 자유자제로 조정할 수 있어야 하므로 맵을 읽어 드리는 2차원 배열또한 크기가 자유자제로 바뀌어야한다. 하지만 여러분들은 (필자포함) 배열의 인덱스는 변경될 수 없다고 배웠을 것이다. 실제로 배열 인덱스에 변수를 넣으면 "변수 넣지마 꺼져" 라는 컴파일 에러를 발견하게 될 것이다 (VS2015기준 / C99였나부터 잘 모르겠지만 가변변수가 배열 인덱스에 허용된다고 한다.)
따라서 필자는 동적할당으로 배열을 만들겠다는 망상을 가지고 map.h / map.cpp를 만들었다.
//map.h
#pragma once
#include"Define.h"
class MAP
{
private:
int width; // 넓이
int height; // 높이
public:
int **xy=NULL; // 동적할당을 위한 더블포인터 xy
void Init(); // 초기화
void Release(); // 메모리 해제
int Get_width(); // 넓이 가져오기
int Get_height(); // 높이 가져오기
};
//map.cpp
#include"map.h"
void MAP::Init()
{
FILE *fp = fopen("mapsize.txt", "r");
int ret = 0;
while (ret != EOF)
ret = fscanf(fp, "%d %d", &width, &height);
xy = new int*[height];
for (int i = 0; i < height; i++)
{
xy[i] = new int[width];
memset(xy[i], 0, sizeof(int)*width);
}
}
void MAP::Release()
{
for (int i = 0; i < height; i++)
delete xy[i];
}
int MAP::Get_height() { return height; }
int MAP::Get_width() { return width; }
마지막으로 대망의 main.cpp를 만들 차례이다!
//main.cpp
#include"Define.h"
#include"CPoint.h"
int main()
{
CPoint cpt(1, 1);
cpt.Init();
int user = 1;
bool check = true;
char name[2][256];
for (int i = 0; i < 2; i++)
{
cout << i + 1 << "번째 님의 이름을 입력:\n";
cin >> name[i];
}
for (int j = 0; j < cpt.Get_height(); j++)
for (int i = 0; i < cpt.Get_width(); i++)
cpt.xy[j][i] = 0;
cpt.screen();
while (check)
{
gotoxy(0, 20);
cout << name[user - 1] << "님 차례";
cpt.input(user);
cpt.screen();
check = cpt.check(user);
if (user == 1)
user = 2;
else
user = 1;
}
gotoxy(0, 20);
cout << name[user - 2] << "님의 승리" << endl;
cpt.Release();
}
이것으로 오목을 4시간(실제 작업시간은 7시간) 만에 만들고 잤다. 사실 시간이 가장 걸렸던건 2차원 배열을 동적으로 받는것에서 3시간을 날렸다. 후... 다시는 하기 싫은 노가다였다.
'프로그래밍 > C++언어' 카테고리의 다른 글
[C++언어]더미노드가 있는 단순연결리스트로 주소록 만들기 (0) | 2016.04.15 |
---|---|
[C++언어]하노이탑(hanoi) 게임 만들기 (0) | 2016.04.15 |