본문 바로가기

강의자료/C/C++

055. 오목 프로그램을 확장하자 - 화살표 이동 방식.

◈ 이 글은 강의를 위하여 제가 직접 작성한 내용입니다. 따라서 퍼가실 경우, 출처를 명확히 해주시기 바랍니다!!
◈ This ariticle was written by me for teaching. So if you want to copy this article, please clarify the source!!


2011/01/18 - [강의자료/C/C++] - 054. 오목 프로그램을 작성하자.

(1) 바둑알 위치를 좌표로 입력받는 기존의 형식에 추가하여 화살표로 이동하고 스페이스바로 입력할 수 있도록 기능을 추가한다.
-- (현재 위치를 의미하는 커서 문자는 ☞를 사용한다.)
-- (기본 입력모드는 화살표 모드로 진행하되, 'I'키를 누르면 좌표입력모드로 변경되게 한다.)
(2) 입력모드 중에 ESC키를 누르면 게임을 바로 종료할 수 있는 기능을 추가한다.
(3) 바둑판 그림 옆에 아래 출력화면과 같이 게임에 관한 정보를 출력한다.
(4) 그 외 출력 메시지는 오른쪽 출력화면 아래부분에 출력되도록 작성한다.
/*
(1) 바둑알 위치를 좌표로 입력받는 기존의 형식에 추가하여 화살표로 이동하고 스페이스바로 입력할 수 있도록 기능을 추가한다. 
-- (현재 위치를 의미하는 커서 문자는 ☞를 사용한다.)
-- (기본 입력모드는 화살표 모드로 진행하되, 'I'키를 누르면 좌표입력모드로 변경되게 한다.)
(2) 입력모드 중에 ESC키를 누르면 게임을 바로 종료할 수 있는 기능을 추가한다.
(3) 바둑판 그림 옆에 아래 출력화면과 같이 게임에 관한 정보를 출력한다.
(4) 그 외 출력 메시지는 오른쪽 출력화면 아래부분에 출력되도록 작성한다.
*/

//-------------------------------------------------------------------------------
// 헤더파일 선언.
//-------------------------------------------------------------------------------
#include 
#include 
#include 
using namespace std;

//-------------------------------------------------------------------------------
// 매크로.
//-------------------------------------------------------------------------------
#define KEY_NONE	0
#define KEY_ARROW	224
#define KEY_UP		72
#define KEY_LEFT	75
#define KEY_RIGHT	77
#define KEY_DOWN	80
#define KEY_RETURN	13
#define KEY_SPACE	32
#define KEY_ESC		27
#define KEY_BACK	8

#define BOARD_SIZE	19
#define PLAYER_NUM	2
//-------------------------------------------------------------------------------
// 오목 클래스 선언.
//-------------------------------------------------------------------------------
class FiveRow
{
private:
	int pieceList[BOARD_SIZE][BOARD_SIZE];
	char pieceFigure[3][3];

	int player;					// 플레이어의 순서.(0 : 노 메시지, 1 : 플레이어1차례, 2 : 플레이어2차례, 3 : 플레이어1승리, 4 : 플레이어2승리)

	int posX;					// 사용자 입력 좌표.
	int posY;
	bool pressESC;

public:
	FiveRow()
	{
		strcpy_s(pieceFigure[0], _countof(pieceFigure[0]), "╋");
		strcpy_s(pieceFigure[1], _countof(pieceFigure[1]), "●");
		strcpy_s(pieceFigure[2], _countof(pieceFigure[2]), "○");
	}

private:
	void InitGame();
	void DisplayBoard(char* str = NULL);
	bool InputKey(int player);
	bool InputArrow();
	bool InputNumber();	
	bool CheckFiveRow(int player);

	bool Ask_Yes_or_No(char* query)
	{
		if(query) cout << query << " (Y/N)";
		char yes_or_no = _getch();
		if(yes_or_no == 'y' || yes_or_no == 'Y') return true;
		return false;
	}

	void ChangePlayer()
	{
		player++;
		if(player > PLAYER_NUM) player = 1;
	}

public:
	void SetStone(int num, char* figure);
	void Run();
};

void FiveRow::SetStone( int num, char* figure )
{
	if(num > 0 && num <= PLAYER_NUM)
		strcpy_s(pieceFigure[num], _countof(pieceFigure[num]), figure);
}

void FiveRow::InitGame()
{
	player = 1;
	posX = 1;
	posY = 1;
	pressESC = false;
	memset(pieceList, 0, sizeof(pieceList));
}

void FiveRow::DisplayBoard( char* str )
{
	// 화면을 지운다.
	system("cls");

	// 바둑판 위쪽 가장자리를 그린다.
	cout << endl << "┏"; for(int i=0;i < BOARD_SIZE;i++) cout << "┳"; cout << "┓" << endl;

	// 바둑판 내부를 그린다.
	// 바둑알이 있다면 바둑알을 그린다.
	for(int y=0; y < BOARD_SIZE; y++) 
	{ 
		// 바둑판 왼쪽 가장자리를 그린다.
		cout << "┣" ;
		// 바둑판 안쪽을 그려준다.
		for(int x=0; x < BOARD_SIZE; x++)
		{
			// 현재 커서부분은 손을 그려준다. && 게임이 진행중이라면,
			if( (x == posX-1 && y == posY-1) && (player <= PLAYER_NUM) ) 
				cout << "☞";
			else
				cout << pieceFigure[ pieceList[y][x] ];
		} 
		// 바둑판 오른쪽 가장자리를 그린다.
		cout << "┫";
		// 바둑판 Y좌표를 나타낸다.
		cout << setw(2) << y+1;

		// 안내문구를 출력시킨다.
		if(y == 0)			cout << "┌───────────────┐";
		else if(y == 1)				
		{
			cout << "│ Player 1 : " << pieceFigure[1];
			cout << "  Player 2 : " << pieceFigure[2] << " │";
		}
		else if(y == 2)		cout << "└───────────────┘";
		else if(y == 3)		cout << "┌───────────────┐";
		else if(y == 4)		cout << "│ >> 화살표키로 이동 후        │";
		else if(y == 5)		cout << "│    [SPACE BAR]를 누르세요!!  │";
		else if(y == 6)		cout << "│                              │";
		else if(y == 7)		cout << "│ >> 좌표입력을 원하시면       │";
		else if(y == 8)		cout << "│    [I]를 누르세요!!          │";
		else if(y == 9)		cout << "│                              │";
		else if(y == 10)	cout << "│ >> 프로그램을 종료하시려면   │";
		else if(y == 11)	cout << "│    [ESC]를 누르세요!!        │";
		else if(y == 12)	cout << "└───────────────┘";
		else if(y == 13)	cout << "┌───────────────┐";
		else if(y == 14)	cout << "│ Player " << (player <= PLAYER_NUM ? player : player-PLAYER_NUM) << (player <= PLAYER_NUM ? " 의 차례입니다.      │" : "이(가) 이겼습니다.   │");
		else if(y == 15)	cout << "└───────────────┘";
		else if(y == 16)	if(str != NULL) cout << str;

		// 다음 라인으로 바꾼다.
		cout << endl; 
	}

	// 바둑판 아랫쪽 가장자리를 그린다.
	cout << "┗"; for(int i=0; i < BOARD_SIZE; i++) cout << "┻"; cout << "┛" << endl;

	// 바둑판 X좌표를 나타낸다.
	cout << "  "; for(int x=0; x < BOARD_SIZE; x++) cout << setw(2) << x+1; cout << endl;		// setw(2) -> printf("%2d",y+1); 
}

bool FiveRow::InputArrow()
{
	// keyInput 변수를 초기화한다.
	int keyInput = KEY_NONE;

	// 화살표키로 입력받는다.
	while(true)
	{
		keyInput = _getch();

		// 화살표키를 눌렀을 경우,
		if(keyInput == KEY_ARROW)
		{
			// 확장코드를 읽어서 무슨 키인지 판별한다.
			keyInput = _getch();

			// 키에 따라 좌표를 제어한다.
			if(keyInput == KEY_UP) posY-1 < 1 ? posY : posY--;
			else if(keyInput == KEY_DOWN) posY+1 > BOARD_SIZE ? posY : posY++;
			else if(keyInput == KEY_LEFT) posX-1 < 1 ? posX : posX--;
			else if(keyInput == KEY_RIGHT) posX+1 >BOARD_SIZE ? posX :posX++;

			// 화면을 갱신한다.
			DisplayBoard();
		}
		// SpaceBar를 눌렀을 경우, 돌을 놓은 것으로 간주하고 함수를 종료한다.
		else if(keyInput == KEY_SPACE) return true;

		// ESC키를 눌렀을 경우, 프로그램을 종료한다.
		else if(keyInput == KEY_ESC) 
		{
			pressESC = true;
			return false;
		}

		// I를 눌렀을 경우, 좌표를 직접 입력할 수 있도록 루프를 벗어난다.
		else if(keyInput == 'I' || keyInput == 'i') return false;

		// 이외의 키를 눌렀을 경우, 안내메시지를 출력한다.
		else DisplayBoard(" >> 잘못 누르셨습니다.");
	}
}

bool FiveRow::InputNumber()
{
	int keyInput = KEY_NONE;

	for(int i=0; i < 2; i++)
	{
		int& pos = (i==0)?this->posX:this->posY;
		int backup = pos;
		pos = 0; // 좌표 초기화.
		while(true)
		{
			char msg[64];
			char coord = (i==0)?'X':'Y';
			sprintf_s(msg, _countof(msg), " >> %c좌표를 입력(1-%d) : ", coord, BOARD_SIZE);
			if(pos != 0) sprintf_s(msg, _countof(msg), "%s%d", msg, pos);
			if(i == 1) sprintf_s(msg, _countof(msg), "%s (X:%d)", msg, posX);

			DisplayBoard(msg);

			// 키 입력.
			keyInput = _getch();

			// ESC키를 눌렀을 경우, 프로그램을 종료한다.
			if(keyInput == KEY_ESC)
			{
				pressESC = true;
				pos = backup;
				return false;
			}

			// Return키를 입력했을 경우,
			else if(keyInput == KEY_RETURN)
			{
				// 좌표의 범위가 정상적일 경우,
				if(1 <= pos && pos <= BOARD_SIZE)
				{
					break;	// for()문을 한번 더 돌아야 한다.
				}
				else
				{
					DisplayBoard(" >> 잘못 입력하였습니다.");
					pos = 0;
					_getch();	// 화면을 잠시 멈춘다.
				}
			}

			// 숫자키를 눌렀을 경우, 자리수를 변경해가며 숫자를 맞춰나간다.
			// '0' -> 48, '1' -> 49, '9' ->57
			else if('0' <= keyInput && keyInput <= '9')
			{
				pos = (pos*10) + (keyInput-'0');
			}

			// <-키를 눌렀을 경우, 한자리씩 지운다.
			else if(keyInput == KEY_BACK)
			{
				pos /= 10;
			}

			else
			{
				DisplayBoard(" >> 잘못 입력하였습니다.");
				pos = 0;
				_getch();	// 화면을 잠시 멈춘다.
			}
		}
	}

	return true;
}

bool FiveRow::InputKey(int player)
{
	if(InputArrow() == false)
	{
		if(pressESC) return false;
		if(InputNumber() == false) return false;
	}	

	if(pieceList[posY-1][posX-1] == 0)				// 바둑알이 없을 경우,
	{ 
		pieceList[posY-1][posX-1] = player; 
		return true;
	}
	else
	{
		return false;
	}

}

void FiveRow::Run()
{
	InitGame();
	DisplayBoard();									// 바둑판을 보여준다.

	while(true) 
	{		
		if(InputKey(player))							// 키입력을 받는다.
		{
			if (CheckFiveRow(player))					// 오목이 성립되었는지를 체크한다. 성립되었다면,
			{
				player += PLAYER_NUM;					// 턴을 끝내고 승리메시지를 출력하기 위해 상태값을 바꾼다.

				while(true)
				{
					DisplayBoard(" >> Enter키를 누르세요.");
					int inputOK = _getch();
					if(inputOK == KEY_RETURN) break;
				}

				DisplayBoard(" >> 게임을 더 하시겠습니까? (Y/N)");

				if(Ask_Yes_or_No(NULL))
				{
					InitGame();
					DisplayBoard();
					continue;
				}
				else
				{
					break;
				}				
			}
			else											// 오목이 성립되지 않았다면,
			{
				ChangePlayer();
				DisplayBoard();							// 바둑판을 갱신한다.
			}
		}
		else
		{
			if(pressESC)
			{
				DisplayBoard(" >> 게임을 종료하시겠습니까? (Y/N)");

				if(Ask_Yes_or_No(NULL))	
				{
					break;
				}
				else
				{
					pressESC = false;
					DisplayBoard();
					continue;
				}
			}
			else 
			{
				DisplayBoard(" >> 돌이 놓여져 있습니다.");	// 바둑판을 갱신한다.
			}
		}
	} 
}

bool FiveRow::CheckFiveRow( int player )
{
	// 연속된 바둑알의 개수.
	// 현재 위치에 이미 돌이 놓여 있으므로 1을 초기값으로 준다.
	int sequenceNum = 1;

	// 현재 위치에서 가로, 세로, 대각선까지 총 4방향에 대해 오목성립을 체크한다.
	for(int check=1; check <= 8; check++)
	{
		int signX = 0;
		int signY = 0;

		if(check == 1)		 signX = 1, signY = 0;		// 가로 + 방향
		else if(check == 2) signX = -1, signY = 0;		// 가로 - 방향
		else if(check == 3) signX = 0, signY = 1;		// 세로 + 방향
		else if(check == 4) signX = 0, signY = -1;		// 세로 - 방향
		else if(check == 5) signX = 1, signY = 1;		// 대각선 315도 방향
		else if(check == 6) signX = -1, signY = -1;		// 대각선 135도 방향
		else if(check == 7) signX = 1, signY = -1;		// 대각선 45도 방향
		else if(check == 8) signX = -1, signY = 1;		// 대각선 225도 방향

		// 각 방향의 처음에만 시퀀스를 초기화 한다.
		if(check%2 == 1) sequenceNum = 1;

		// 체크할 위치의 오프셋.
		int offset = 0;

		while(true)
		{
			// 다음 위치의 돌을 체크한다.
			offset++;

			// 체크할 위치 계산.
			int checkPosX = posX + offset*signX;
			int checkPosY = posY + offset*signY;

			// 바둑판의 끝에 도달하면 현재 방향에 대해서는 더이상 체크하지 않는다.
			if( checkPosX < 1 || checkPosX > BOARD_SIZE ) break;
			if( checkPosY < 1 || checkPosY > BOARD_SIZE ) break;

			// 같은 바둑알이 있으면 1증가.
			if( pieceList[checkPosY-1][checkPosX-1] == player ) sequenceNum++;
			// 없으면 체크 종료.
			else break;

			// 오목이 성립하면 함수 종료.
			if(sequenceNum == 5) return true;
		}
	}

	return false; 
}

//-------------------------------------------------------------------------------
// 함수 선언.
//-------------------------------------------------------------------------------
void DisplayTitle();					// 타이틀을 보여준다.

//-------------------------------------------------------------------------------
// 메인 함수.
//-------------------------------------------------------------------------------
void main() 
{
 	DisplayTitle();
 
 	FiveRow game;
 	game.SetStone(1, "☆");
 	game.SetStone(2, "★");
 
 	game.Run();
}

//-------------------------------------------------------------------------------
// DisplayTitle() // 타이틀을 표시한다.
//-------------------------------------------------------------------------------
void DisplayTitle()
{
	system("cls");
	cout << endl;
	cout << " ┏★˚━━━━━━━━━━━━━━━━━━━━♡┓" << endl;
	cout << " ┃              오목 (Five Row)                 ┃" << endl;
	cout << " ┃                                              ┃" << endl;
	cout << " ┃ 제 작 일 : 2000-00-00                        ┃" << endl;
	cout << " ┃ 만 든 이 : 이항복                            ┃" << endl;
	cout << " ┃ 이 메 일 : master@uzoo.in                    ┃" << endl;
	cout << " ┃ 소    속 : MBC아카데미디지털교육원           ┃" << endl;
	cout << " ┃ 만든목적 : C/C++ 기초 활용 교육용            ┃" << endl;
	cout << " ┃                                              ┃" << endl;
	cout << " ┃                             ▼~~~~~  나는야~ ┃" << endl;
	cout << " ┃ *.┏┓    부디 저희를     ▶⊙◀~~ 천상천하!!┃" << endl;
	cout << " ┃ ┏┻┫    거둬주세요~!!     ▲~~~ 유아독존!! ┃" << endl;
	cout << " ┃ ┃━┫      ○    ●        \● 푸          ┃" << endl;
	cout << " ┃ ┃━┫    ┏■┛┏□┛        /> 하          ┃" << endl;
	cout << " ┃ ┗━┛      ┛┓  ┛┓      〈\ 하          ┃" << endl;
	cout << " ┃                                             ~★" << endl;
	cout << " ♡˚━○━━━━━━━━━━━━━━━━━━━━┛" << endl;

	cout << "  ┏*******┓" << endl;
	cout << "  ┃ こ ご ┃ \"게임을 시작하고 싶은가??\"" << endl;
	cout << "  ┃...^...┃ \"그럼 아무키나 눌러보게나...후훗..!!\"" << endl;
	cout << "  ~~~~~~~~~~~" << endl;

	system("pause");
	system("cls");
}

수정전 임시 코드
//-------------------------------------------------------------------------------
// 헤더파일 선언.
//-------------------------------------------------------------------------------
#include 
#include 
#include 
using namespace std;

//-------------------------------------------------------------------------------
// 매크로.
//-------------------------------------------------------------------------------
#define KEY_NONE	0
#define KEY_ARROW	224
#define KEY_UP		72
#define KEY_LEFT	75
#define KEY_RIGHT	77
#define KEY_DOWN	80
#define KEY_RETURN	13
#define KEY_SAPCE	32
#define KEY_ESC		27
#define KEY_BACK	8

//-------------------------------------------------------------------------------
// 오목 클래스 선언.
//-------------------------------------------------------------------------------
class FiveRow
{
private:
	const static int boardSize = 19;
	const static int eggSize = 3;

	int pieceList[boardSize][boardSize];		// 바둑알 배열.

	int playerNum;								// 플레이어 수.
	char** pieceFigure;							// 바둑알 모양.

	int posX;					// 사용자 입력 좌표.
	int posY;		
	int whoseTurn;				// 플레이어의 순서.(0 : 노 메시지, 1 : 플레이어1차례, 2 : 플레이어2차례, 3 : 플레이어1승리, 4 : 플레이어2승리)

	bool pressESC;

public:
	FiveRow(int playerNum): playerNum(playerNum), pieceFigure(NULL)
	{
		// 바둑알 배열 생성.(+1 : "╋"도 바둑알로 표현.)
		pieceFigure = new char*[playerNum+1];

		// 바둑알 모양 초기화.
		for(int i=0; i < playerNum+1; i++)
		{
			pieceFigure[i] = new char[eggSize];
		}

		strcpy_s(pieceFigure[0], eggSize, "╋");

		InitGame();
	}

	~FiveRow()
	{
		for(int i=0; i < playerNum+1; i++)
		{
			delete [] pieceFigure[i];
		}

		delete [] pieceFigure;
	}

private:
	void InitGame();
	bool InputKey(int player);
	bool InputArrow();
	bool InputNumber();
	void DisplayBoard(char* str);

	bool CheckFiveRow(int player);
	bool CheckPieceFigure();

public:
	void InitPiece(int num, char* figure);
	void Run();
};

void FiveRow::InitPiece( int num, char* figure )
{
	if(num > 0 && num <= playerNum)
	{
		strcpy_s(pieceFigure[num], eggSize, figure);
	}
}

void FiveRow::InitGame()
{
	posX = 1;
	posY = 1;	
	whoseTurn = 1;
	pressESC = false;

	// boardSize X boardSize 크기의 바둑판을 초기화한다.
	memset(pieceList, 0, sizeof(pieceList));
}

bool FiveRow::InputArrow()
{
	// keyInput 변수를 초기화한다.
	int keyInput = KEY_NONE;		

	// 화살표키로 입력받는다.
	while(true)
	{
		keyInput = _getch();

		// 화살표키를 눌렀을 경우,
		if(keyInput == KEY_ARROW) 
		{
			// 확장코드를 읽어서 무슨 키인지 판별한다.
			keyInput = _getch();

			// 키에 따라 좌표를 제어한다.
			if(keyInput == KEY_UP) posY-1 < 1 ? posY : posY--;
			else if(keyInput == KEY_DOWN) posY+1 > boardSize ? posY : posY++;
			else if(keyInput == KEY_LEFT) posX-1 < 1 ? posX : posX--;
			else if(keyInput == KEY_RIGHT) posX+1 >boardSize ? posX :posX++;

			// 화면을 갱신한다.
			DisplayBoard();
		}
		// SpaceBar를 눌렀을 경우, 돌을 놓은 것으로 간주하고 함수를 종료한다.
		else if(keyInput == KEY_SAPCE) return true;

		// ESC키를 눌렀을 경우, 프로그램을 종료한다.
		else if(keyInput == KEY_ESC) 
		{
			pressESC = true;
			return false;
		}

		// I를 눌렀을 경우, 좌표를 직접 입력할 수 있도록 루프를 벗어난다.
		else if(keyInput == 'I' || keyInput == 'i') return false;

		// 이외의 키를 눌렀을 경우, 안내메시지를 출력한다.
		else DisplayBoard(" >> 잘못 누르셨습니다.");
	}
}

bool FiveRow::InputNumber()
{
	int keyInput = KEY_NONE;	

	for(int i=0; i < 2; i++)
	{
		int& pos = (i==0)?this->posX:this->posY;
		int backup = pos;
		pos = 0; // 좌표 초기화.
		while(true)
		{
			char msg[32];
			char coord = (i==0)?'X':'Y';
			sprintf_s(msg, _countof(msg), " >> %c좌표를 입력(1-%d) : ", coord, boardSize);
			DisplayBoard(msg);

			// 키 입력.
			keyInput = _getch();

			// ESC키를 눌렀을 경우, 프로그램을 종료한다.
			if(keyInput == KEY_ESC)
			{
				pressESC = true;
				pos = backup;
				return false;
			}

			// Return키를 입력했을 경우,
			else if(keyInput == KEY_RETURN)
			{
				// 좌표의 범위가 벗어났을 경우,
				if(pos < 1 || pos > boardSize) 
				{
					DisplayBoard(" >> 잘못 입력하였습니다.");
					pos = 0;
					_getch();
				}
				// 좌표의 범위가 정상적일 경우,
				else
				{
					break;	// for()문을 한번 더 돌아야 한다.
				}
			}

			// 숫자키를 눌렀을 경우, 자리수를 변경해가며 숫자를 맞춰나간다.
			// temp-48 -> 1의 아스키코드 값이 49이므로...
			else if(keyInput >= 48 && keyInput <= 57)
			{
				pos = (pos*10) + (keyInput-48);
			}

			// <-키를 눌렀을 경우, 한자리씩 지운다.
			else if(keyInput == KEY_BACK)
			{
				pos /= 10;
			}

			else
			{
				DisplayBoard(" >> 잘못 입력하였습니다.");
				pos = 0;
				_getch();
			}
		}
	}

	return true;
}
bool FiveRow::InputKey(int player)
{
	if(InputArrow() == false)
	{
		if(pressESC) return false;
		if(InputNumber() == false) return false;
	}	

	if(pieceList[posY-1][posX-1] == 0)				// 바둑알이 없을 경우,
	{ 
		pieceList[posY-1][posX-1] = whoseTurn; return true;
	}
	else
	{
		return false;
	}

}

void FiveRow::DisplayBoard( char* str )
{
	// 화면을 지운다.
	system("cls");

	// 바둑판 위쪽 가장자리를 그린다.
	cout << endl << "┏"; for(int i=0;i < boardSize;i++) cout << "┳"; cout << "┓" << endl;

	// 바둑판 내부를 그린다.
	// 바둑알이 있다면 바둑알을 그린다.
	int printedPlayer = 1;
	for(int y=0; y < boardSize; y++) 
	{ 
		// 바둑판 왼쪽 가장자리를 그린다.
		cout << "┣" ;
		// 바둑판 안쪽을 그려준다.
		for(int x=0; x < boardSize; x++)
		{
			// 현재 커서부분은 손을 그려준다. && 게임이 진행중이라면,
			if( (x == posX-1 && y == posY-1) && (whoseTurn <= playerNum) ) cout << "☞";
			else
			{
				cout << pieceFigure[ pieceList[y][x] ];
			}
		} 
		// 바둑판 오른쪽 가장자리를 그린다.
		cout << "┫";
		// 바둑판 Y좌표를 나타낸다.
		cout << setw(2) << y+1;

		// 안내문구를 출력시킨다.
		// 0.5f를 더한 이유 : 플레이어 인원수가 홀수명일 경우 반올림 하기 위해서.
		int playerline = int(playerNum/2.0f + 0.5f);

		if(y == 0)					cout << "┌───────────────┐";
		else if(y <= playerline)				
		{
			cout << "│ Player " << printedPlayer << " : " << pieceFigure[printedPlayer];  
			printedPlayer++;

			if(printedPlayer <= playerNum)
			{
				cout << "  Player " << printedPlayer << " : " << pieceFigure[printedPlayer] << " │";
				printedPlayer++;
			}
			else
			{
				cout << "                │";
			}
		}
		else if(y == 1+playerline)		cout << "└───────────────┘";

		else if(y == 2+playerline)		cout << "┌───────────────┐";
		else if(y == 3+playerline)		cout << "│ >> 화살표키로 이동 후        │";
		else if(y == 4+playerline)		cout << "│    [SPACE BAR]를 누르세요!!  │";
		else if(y == 5+playerline)		cout << "│                              │";
		else if(y == 6+playerline)		cout << "│ >> 좌표입력을 원하시면       │";
		else if(y == 7+playerline)		cout << "│    [I]를 누르세요!!          │";
		else if(y == 8+playerline)		cout << "│                              │";
		else if(y == 9+playerline)		cout << "│ >> 프로그램을 종료하시려면   │";
		else if(y == 10+playerline)		cout << "│    [ESC]를 누르세요!!        │";
		else if(y == 11+playerline)		cout << "└───────────────┘";

		// 턴 또는 승리를 표시한다.
		else if(y == 12+playerline)		cout << "┌───────────────┐";
		else if(y == 13+playerline)		cout << "│ Player " << (whoseTurn <= playerNum ? whoseTurn : whoseTurn-playerNum) << (whoseTurn <= playerNum ? " 의 차례입니다.      │" : "이(가) 이겼습니다.   │");
		else if(y == 14+playerline)		cout << "└───────────────┘";

		// 인자로 들어온 문자열을 출력한다.
		else if(y == 15+playerline)		if(str != NULL) 
		{ 
			cout << str; 
			if( str[4] == 'X' ) if(posX != 0) cout << posX;
			if( *(str+4) == 'Y' ) {if(posY != 0) cout << posY; cout << " (X:" << posX << ")";}
		}

		// 다음 라인으로 바꾼다.
		cout << endl; 
	}

	// 바둑판 아랫쪽 가장자리를 그린다.
	cout << "┗"; for(int i=0; i < boardSize; i++) cout << "┻"; cout << "┛" << endl;

	// 바둑판 X좌표를 나타낸다.
	cout << "  "; for(int x=0; x < boardSize; x++) cout << setw(2) << x+1; cout << endl;		// setw(2) -> printf("%2d",y+1); 
}

bool FiveRow::CheckFiveRow( int player )
{
	// 연속된 바둑알의 개수.
	// 현재 위치에 이미 돌이 놓여 있으므로 1을 초기값으로 준다.
	int sequenceNum = 1;

	// 현재 위치에서 가로, 세로, 대각선까지 총 4방향에 대해 오목성립을 체크한다.
	for(int check=1; check <= 8; check++)
	{
		int signX = 0;
		int signY = 0;

		if(check == 1)		 signX = 1, signY = 0;		// 가로 + 방향
		else if(check == 2) signX = -1, signY = 0;		// 가로 - 방향
		else if(check == 3) signX = 0, signY = 1;		// 세로 + 방향
		else if(check == 4) signX = 0, signY = -1;		// 세로 - 방향
		else if(check == 5) signX = 1, signY = 1;		// 대각선 315도 방향
		else if(check == 6) signX = -1, signY = -1;		// 대각선 135도 방향
		else if(check == 7) signX = 1, signY = -1;		// 대각선 45도 방향
		else if(check == 8) signX = -1, signY = 1;		// 대각선 225도 방향

		// 각 방향의 처음에만 시퀀스를 초기화 한다.
		if(check%2 == 1) sequenceNum = 1;		

		// 체크할 위치의 오프셋.
		int offsetX = 0;
		int offsetY = 0;

		while(true)
		{
			// 다음 위치의 돌을 체크한다.
			offsetX++;
			offsetY++;

			// 체크할 위치 계산.
			int checkPosX = posX + offsetX*signX;
			int checkPosY = posY + offsetY*signY;

			// 바둑판의 끝에 도달하면 현재 방향에 대해서는 더이상 체크하지 않는다.
			if( checkPosX > boardSize || checkPosX < 1 ) break;
			if( checkPosY > boardSize || checkPosY < 1 ) break;

			// 같은 바둑알이 있으면 1증가.
			if( pieceList[checkPosY-1][checkPosX-1] == player ) sequenceNum++;
			// 없으면 체크 종료.
			else break;

			// 오목이 성립하면 함수 종료.
			if(sequenceNum == 5) return true;
		}
	}

	return false; 
}

bool FiveRow::CheckPieceFigure()
{
	bool hasAllFigure = true;

	for(int i=1; i <= playerNum; i++)
	{
		if(pieceFigure[i] == NULL)
		{
			cout << "플레이어 " << i << "의 바둑알이 정의되지 않았습니다." << endl;
			hasAllFigure = false;
		}
	}

	return hasAllFigure;
}

void FiveRow::Run()
{
	// 플레이어의 바둑알의 모양이 모두 설정되어있지 않으면 종료한다.
	if(CheckPieceFigure() == false) return;

	char moregame;

	DisplayBoard();										// 바둑판을 보여준다.

	while(true) 
	{		
		if(InputKey(whoseTurn))							// 키입력을 받는다.
		{
			if (CheckFiveRow(whoseTurn))					// 오목이 성립되었는지를 체크한다. 성립되었다면,
			{
				whoseTurn += playerNum;					// 턴을 끝내고 승리메시지를 출력하기 위해 상태값을 바꾼다.

				while(true)
				{
					DisplayBoard(" >> Enter키를 누르세요.");
					int inputOK = _getch();
					if(inputOK == KEY_RETURN) break;
				}

				DisplayBoard(" >> 게임을 더 하시겠습니까? (Y/N)");

				moregame = _getch();						// 게임을 더 할 것인지 입력을 받는다.
				if(moregame == 'y' || moregame == 'Y')		
				{
					InitGame();
					DisplayBoard();
					continue;
				}
				else
				{
					break;
				}
			}
			else											// 오목이 성립되지 않았다면,
			{
				whoseTurn++;								// 다음 플레이어에게 턴을 넘긴다.
				if(whoseTurn > playerNum) whoseTurn = 1;
				DisplayBoard();							// 바둑판을 갱신한다.
			}
		}
		else
		{
			if(pressESC)
			{
				DisplayBoard(" >> 게임을 종료하시겠습니까? (Y/N)");

				moregame = _getch();
				if(moregame == 'y' || moregame == 'Y')		
				{
					break;
				}
				else
				{
					pressESC = false;
					DisplayBoard();
					continue;
				}
			}
			else 
			{
				DisplayBoard(" >> 돌이 놓여져 있습니다.");	// 바둑판을 갱신한다.
			}
		}
	} 
}

//-------------------------------------------------------------------------------
// 함수 선언.
//-------------------------------------------------------------------------------
void DisplayTitle();					// 타이틀을 보여준다.

//-------------------------------------------------------------------------------
// 메인 함수.
//-------------------------------------------------------------------------------
void main() 
{
	DisplayTitle();

	FiveRow game(4);
	game.InitPiece(1, "●");
	game.InitPiece(2, "○");
	game.InitPiece(3, "★");
	game.InitPiece(4, "☆");

	game.Run();
}

//-------------------------------------------------------------------------------
// DisplayTitle() // 타이틀을 표시한다.
//-------------------------------------------------------------------------------
void DisplayTitle()
{
	system("cls");
	cout << endl;
	cout << " ┏★˚━━━━━━━━━━━━━━━━━━━━♡┓" << endl;
	cout << " ┃              오목 (Five Row)                 ┃" << endl;
	cout << " ┃                                              ┃" << endl;
	cout << " ┃ 제 작 일 : 2000-00-00                        ┃" << endl;
	cout << " ┃ 만 든 이 : 이항복                            ┃" << endl;
	cout << " ┃ 이 메 일 : master@uzoo.in                    ┃" << endl;
	cout << " ┃ 소    속 : MBC아카데미디지털교육원           ┃" << endl;
	cout << " ┃ 만든목적 : C/C++ 기초 활용 교육용            ┃" << endl;
	cout << " ┃                                              ┃" << endl;
	cout << " ┃                             ▼~~~~~  나는야~ ┃" << endl;
	cout << " ┃ *.┏┓    부디 저희를     ▶⊙◀~~ 천상천하!!┃" << endl;
	cout << " ┃ ┏┻┫    거둬주세요~!!     ▲~~~ 유아독존!! ┃" << endl;
	cout << " ┃ ┃━┫      ○    ●        \● 푸          ┃" << endl;
	cout << " ┃ ┃━┫    ┏■┛┏□┛        /> 하          ┃" << endl;
	cout << " ┃ ┗━┛      ┛┓  ┛┓      〈\ 하          ┃" << endl;
	cout << " ┃                                             ~★" << endl;
	cout << " ♡˚━○━━━━━━━━━━━━━━━━━━━━┛" << endl;

	cout << "  ┏*******┓" << endl;
	cout << "  ┃ こ ご ┃ \"게임을 시작하고 싶은가??\"" << endl;
	cout << "  ┃...^...┃ \"그럼 아무키나 눌러보게나...후훗..!!\"" << endl;
	cout << "  ~~~~~~~~~~~" << endl;

	system("pause");
	system("cls");
}