본문 바로가기

강의자료/C/C++

054. 오목 프로그램을 작성하자 - 좌표 입력 방식.


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


>> 보드출력.
(1) 출력에는 ┏, ┳, ┓, ┣, ╋, ┫, ┗, ┻, ┛문자를 적절히 활용한다.
(2) 해당 문자들은 'ㅂ'에서 한자키를 누르면 나온다.
┏┳┳┳┳┳┳┳┳┳┳┳┳┳┳┳┳┳┳┳┓
┣╋╋╋╋╋╋╋╋╋╋╋╋╋╋╋╋╋╋╋┫1
┣╋╋╋╋╋╋╋╋╋╋╋╋╋╋╋╋╋╋╋┫2
┣╋╋╋╋╋╋╋╋╋╋╋╋╋╋╋╋╋╋╋┫3
┣╋╋╋╋╋╋╋╋╋╋╋╋╋╋╋╋╋╋╋┫4
┣╋╋╋╋╋╋╋╋╋╋╋╋╋╋╋╋╋╋╋┫5
┣╋╋╋╋╋╋╋╋╋╋╋╋╋╋╋╋╋╋╋┫6
┣╋╋╋╋╋╋╋╋╋╋╋╋╋╋╋╋╋╋╋┫7
┣╋╋╋╋╋╋╋╋╋╋╋╋╋╋╋╋╋╋╋┫8
┣╋╋╋╋╋╋╋╋╋╋╋╋╋╋╋╋╋╋╋┫9
┣╋╋╋╋╋╋╋╋╋╋╋╋╋╋╋╋╋╋╋┫10
┣╋╋╋╋╋╋╋╋╋╋╋╋╋╋╋╋╋╋╋┫11
┣╋╋╋╋╋╋╋╋╋╋╋╋╋╋╋╋╋╋╋┫12
┣╋╋╋╋╋╋╋╋╋╋╋╋╋╋╋╋╋╋╋┫13
┣╋╋╋╋╋╋╋╋╋╋╋╋╋╋╋╋╋╋╋┫14
┣╋╋╋╋╋╋╋╋╋╋╋╋╋╋╋╋╋╋╋┫15
┣╋╋╋╋╋╋╋╋╋╋╋╋╋╋╋╋╋╋╋┫16
┣╋╋╋╋╋╋╋╋╋╋╋╋╋╋╋╋╋╋╋┫17
┣╋╋╋╋╋╋╋╋╋╋╋╋╋╋╋╋╋╋╋┫18
┣╋╋╋╋╋╋╋╋╋╋╋╋╋╋╋╋╋╋╋┫19
┗┻┻┻┻┻┻┻┻┻┻┻┻┻┻┻┻┻┻┻┛
1 2 3 4 5 6 7 8 910111213141516171819

>> 게임제작.
(1) 바둑판의 크기를 의미하는 상수 BOARD_SIZE를 19로 선언한다.
(2) 바둑알의 위치를 저장할 2차원 배열 pieceList를 19x19크기만큼 선언한다
(3) 사용자로부터 입력받은 좌표값을 저장할 inputX, inputY를 선언한다.
(4) 현재 플레이어를 의미하는 player변수를 선언하고 1로 초기화 한다.
(5) 게임이 시작하면 타이틀 화면을 보여주고 키를 누르면 게임화면으로 넘어간다.
(6) 게임화면에 들어오면 우선 바둑판을 보여주고 바둑판 아래에 누구 차례인지 보여준다.
(7) 사용자로부터 x, y좌표를 inputX, inputY에 입력받고 바둑알 배열의 해당 위치에 플레이어 번호를 저장한 후, 바둑판을 다시 그린다.
(8) 바둑판을 다시 그릴때는 바둑알 배열을 참고하여 ╋문자대신 해당 플레이어의 바둑알을 그린다. (플레이어1 : ●, 플레이어2 : ○)
(9) 바둑알의 좌표를 입력받고 바둑판을 다시 그렸다면, 다른 플레이어에게 턴을 넘겨 6~8번 과정을 반복한다.
(10) 위의 과정을 수행하면서 좌표를 입력받을 때마다 해당 좌표가 바둑판 범위를 벗어나지는 않았는지, 다른 돌이 놓여있지는 않는지 체크하여 다시 입력받도록 한다.
(11) 또한 정상적으로 바둑알이 입력되었다면, 오목이 성립되었는지 체크하여 승자를 화면에 표시한다.
(12) 승자가 결정나면, 게임을 더 할것인지 물어보고 대답여부에 따라 게임을 다시 진행한다.

2011/01/18 - [강의자료/C/C++] - 055. 오목 프로그램을 확장하자 - 화살표 이동 방식.

/*
>> 보드출력.
(1) 출력에는 ┏, ┳, ┓, ┣, ╋, ┫, ┗, ┻, ┛문자를 적절히 활용한다.
(2) 해당 문자들은 'ㅂ'에서 한자키를 누르면 나온다.
┏┳┳┳┳┳┳┳┳┳┳┳┳┳┳┳┳┳┳┳┓
┣╋╋╋╋╋╋╋╋╋╋╋╋╋╋╋╋╋╋╋┫1
┣╋╋╋╋╋╋╋╋╋╋╋╋╋╋╋╋╋╋╋┫2
┣╋╋╋╋╋╋╋╋╋╋╋╋╋╋╋╋╋╋╋┫3
┣╋╋╋╋╋╋╋╋╋╋╋╋╋╋╋╋╋╋╋┫4
┣╋╋╋╋╋╋╋╋╋╋╋╋╋╋╋╋╋╋╋┫5
┣╋╋╋╋╋╋╋╋╋╋╋╋╋╋╋╋╋╋╋┫6
┣╋╋╋╋╋╋╋╋╋╋╋╋╋╋╋╋╋╋╋┫7
┣╋╋╋╋╋╋╋╋╋╋╋╋╋╋╋╋╋╋╋┫8
┣╋╋╋╋╋╋╋╋╋╋╋╋╋╋╋╋╋╋╋┫9
┣╋╋╋╋╋╋╋╋╋╋╋╋╋╋╋╋╋╋╋┫10
┣╋╋╋╋╋╋╋╋╋╋╋╋╋╋╋╋╋╋╋┫11
┣╋╋╋╋╋╋╋╋╋╋╋╋╋╋╋╋╋╋╋┫12
┣╋╋╋╋╋╋╋╋╋╋╋╋╋╋╋╋╋╋╋┫13
┣╋╋╋╋╋╋╋╋╋╋╋╋╋╋╋╋╋╋╋┫14
┣╋╋╋╋╋╋╋╋╋╋╋╋╋╋╋╋╋╋╋┫15
┣╋╋╋╋╋╋╋╋╋╋╋╋╋╋╋╋╋╋╋┫16
┣╋╋╋╋╋╋╋╋╋╋╋╋╋╋╋╋╋╋╋┫17
┣╋╋╋╋╋╋╋╋╋╋╋╋╋╋╋╋╋╋╋┫18
┣╋╋╋╋╋╋╋╋╋╋╋╋╋╋╋╋╋╋╋┫19
┗┻┻┻┻┻┻┻┻┻┻┻┻┻┻┻┻┻┻┻┛
   1 2 3 4 5 6 7 8 910111213141516171819

>> 게임제작.
(1) 바둑판의 크기를 의미하는 상수 BOARD_SIZE를 19로 선언한다.
(2) 바둑알의 위치를 저장할 2차원 배열 pieceList를 19x19크기만큼 선언한다
(3) 사용자로부터 입력받은 좌표값을 저장할 inputX, inputY를 선언한다.
(4) 현재 플레이어를 의미하는 player변수를 선언하고 1로 초기화 한다.
(5) 게임이 시작하면 타이틀 화면을 보여주고 키를 누르면 게임화면으로 넘어간다.
(6) 게임화면에 들어오면 우선 바둑판을 보여주고 바둑판 아래에 누구 차례인지 보여준다.
(7) 사용자로부터 x, y좌표를 inputX, inputY에 입력받고 바둑알 배열의 해당 위치에 플레이어 번호를 저장한 후, 바둑판을 다시 그린다.
(8) 바둑판을 다시 그릴때는 바둑알 배열을 참고하여 ╋문자대신 해당 플레이어의 바둑알을 그린다. (플레이어1 : ●, 플레이어2 : ○)
(9) 바둑알의 좌표를 입력받고 바둑판을 다시 그렸다면, 다른 플레이어에게 턴을 넘겨 6~8번 과정을 반복한다.
(10) 위의 과정을 수행하면서 좌표를 입력받을 때마다 해당 좌표가 바둑판 범위를 벗어나지는 않았는지, 다른 돌이 놓여있지는 않는지 체크하여 다시 입력받도록 한다.
(11) 또한 정상적으로 바둑알이 입력되었다면, 오목이 성립되었는지 체크하여 승자를 화면에 표시한다.
(12) 승자가 결정나면, 게임을 더 할것인지 물어보고 대답여부에 따라 게임을 다시 진행한다.
*/


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

#define BOARD_SIZE 19
#define PLAYER_NUM 2

class FiveRow
{
	int pieceList[BOARD_SIZE][BOARD_SIZE];
	int player;

	char pieceFigure[3][3];

public:
	FiveRow()
	{
		// 바둑알 모양 초기화.
		strcpy_s(pieceFigure[0], _countof(pieceFigure[0]), "╋");
		strcpy_s(pieceFigure[1], _countof(pieceFigure[1]), "●");
		strcpy_s(pieceFigure[2], _countof(pieceFigure[2]), "○");
	
		InitGame();
	}

	void InitGame()
	{
		player = 1;
		memset(pieceList, 0, sizeof(pieceList));
	} 

	void DisplayBoard()
	{
		// 화면을 지운다.
		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++)
			{
				cout << pieceFigure[pieceList[y][x]];

				//// 바둑알이 없다면 체크무늬를...그린다.
				//if(pieceList[y][x] == 0) cout << "╋";
				//// Plaxer 1의 바둑알이 있다면 흑돌을...그린다.
				//else if(pieceList[y][x] == 1) cout << "●";
				//// Plaxer 2의 바둑알이 있다면 백돌을...그린다.
				//else if(pieceList[y][x] == 2) cout << "○";
			} 
			// 바둑판 오른쪽 가장자리를 그린다.
			cout << "┫";
			// 바둑판 x좌표를 나타낸다.
			cout << y+1 << endl; 
		}

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

		// 바둑판 X좌표를 나타낸다.
		cout << "  ";
		for(int x=0;x < BOARD_SIZE;x++) 
		{ 
			cout.width(2);
			cout << x+1;
		} 
		cout << endl; 
	} 

	bool InputKey(int player) 
	{
//REINPUT:
		cout << " ======== Player " << player << "의 차례입니다. ======== " << endl;

		int inputY, inputX;

		// X좌표를 입력받는다.
		cout << " >> X좌표를 입력하세요(1-" << BOARD_SIZE << ") : ";
		cin >> inputX;

		// 바둑판의 범위를 벗어났다면,
		while (inputX < 1 || inputX > BOARD_SIZE)
		{
			cout << " >> 좌표값을 확인하시고 다시 입력하세요" << endl;
			cout << " >> X좌표를 입력하세요(1-" << BOARD_SIZE << ") : ";
			cin >> inputX;		// 다시 입력받는다.
		}

		// Y좌표를 입력받는다.
		cout << " >> Y좌표를 입력하세요(1-" << BOARD_SIZE << ") : ";
		cin >> inputY;

		//바둑판의 범위를 벗어났다면,
		while (inputY < 1 || inputY > BOARD_SIZE)
		{
			cout << " >> 좌표값을 확인하시고 다시 입력하세요" << endl;
			cout << " >> Y좌표를 입력하세요(1-" << BOARD_SIZE << ") : ";
			cin >> inputY;		// 다시 입력받는다.
		}

		cout << endl;

		if(pieceList[inputY-1][inputX-1] == 0)
		{
			pieceList[inputY-1][inputX-1] = player;
			return true;
		}
		else
		{
// 			DisplayBoard();						// 바둑판을 새로 그린다.
// 			cout << " =>이미 돌이 놓여져 있습니다. 다른곳을 선택해 주세요." << endl;
// 			goto REINPUT;

			return false;
		}
	} 

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

	void Run()
	{
		InitGame();					// 바둑판을 초기화한다.
		DisplayBoard();				// 바둑판을 보여준다.

		while(true) 
		{
			bool input_ok = InputKey(player);
			DisplayBoard();						// 바둑판을 새로 그린다.

			if(input_ok)
			{
				if(CheckFiveRow(player))			// 오목이 성립되었는지를 체크한다. 성립되었다면,
				{ 
					cout << " >> ::: " << "Player " << player << "이(가) 승리하였습니다. :::" << endl;

					if(Ask_Yes_or_No(">> 게임을 더 하시겠습니까?"))
					{
						InitGame();
						DisplayBoard();
						continue;
					}
					else break;

				}else								// 오목이 성립되지 않았다면,
				{
					ChangePlayer();
				}
			}
			else
			{
				cout << " =>이미 돌이 놓여져 있습니다. 다른곳을 선택해 주세요." << endl;
			}

		} 
	}

	//-------------------------------------------------------------------------------
	// CheckFiveRow() // 오목이 성립되었는지를 체크한다.
	//-------------------------------------------------------------------------------
	bool CheckFiveRow(int player) 
	{
		for(int y=0; y < BOARD_SIZE; y++) 
		{ 
			for(int x=0; x < BOARD_SIZE; x++) 
			{
				// 가로(→) 방향 체크,
				if(pieceList[y][x]==player && pieceList[y][x+1]==player && 
					pieceList[y][x+2]==player && pieceList[y][x+3]==player && 
					pieceList[y][x+4]==player) return true;
				// 세로(↓) 방향 체크,
				else if(pieceList[y][x]==player && pieceList[y+1][x]==player && 
					pieceList[y+2][x]==player && pieceList[y+3][x]==player && 
					pieceList[y+4][x]==player) return true;
				// 대각선(↘) 방향 체크,
				else if(pieceList[y][x]==player && pieceList[y+1][x+1]==player && 
					pieceList[y+2][x+2]==player && pieceList[y+3][x+3]==player && 
					pieceList[y+4][x+4]==player) return true;
				// 대각선(↙) 방향 체크,
				else if(pieceList[y][x]==player && pieceList[y+1][x-1]==player && 
					pieceList[y+2][x-2]==player && pieceList[y+3][x-3]==player && 
					pieceList[y+4][x-4]==player) return true;
			} 
		}

		return false; 
	}

	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;
	}

};


//-------------------------------------------------------------------------------
// 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");
}

//-------------------------------------------------------------------------------
// 메인 함수.
//-------------------------------------------------------------------------------
void main() 
{
 	DisplayTitle();
 
 	FiveRow game;
 	game.Run();
}