강께르의 개발일지

[C++] 빙고 게임_미완성 본문

연습

[C++] 빙고 게임_미완성

강께르 2021. 6. 13. 17:58

1. 이것은 무엇인가?

- 컴퓨터가 무작위로 중복되지 않은 일정 범위의 숫자를 5x5 게임판에 배열하고 플레이어는 특정 숫자를 지정하여 체크한 후, 가로나 세로 혹은 대각선이든 숫자 5개를 연속하여 1줄을 완성한다면 1 빙고로 인정하고 이 빙고를 3개 달성하는 것이 목표인 빙고 게임이다.

- 사실 구조체화한 일대일 턴제 게임보다 더 먼저 만들었으나 시간이 지난 뒤, 수정하려 했으나 일정상 어려움과 시간이 얼마 지나지 않았음에도 내 코드를 내가 다시 익히기 위해 읽어야하는 불상사가 발생하여 일단은 코드만 올리려고 한다.

 

2. 주요 게임 동작 설명

 2-1. 게임 시작 전 숫자 섞기

- 컴퓨터는 2차원 배열 5x5의 첫번째 인덱스에 1부터 25까지의 숫자 중 무작위로 하나를 넣는다. 그리고 그 다음 두번째 인덱스부터 무작위 숫자를 하나 다시 넣고 그 이전의 모든 인덱스의 숫자와 비교를 하여 중복되었는지 검사한다. 이를 25번 반복해 무작위로 숫자를 채운다.

 2-2. 플레이어가 선택한 숫자를 게임판에서 찾기

- 플레이어로부터 숫자 하나를 입력받고 입력한 숫자가 2차원 배열에 있는지 첫번째 인덱스부터 순서대로 확인한다.

 2-3. 빙고인지 확인하기

- 체크되는 숫자가 확인될 때마다 빙고가 달성되어 있는지 확인한다. 특정 배열이 모두 체크인지 and 연산자로 조건이 부합하면 빙고 카운트를 따로 하나 추가한다. 이 빙고 카운트는 체크되는 숫자가 있을 때마다 0으로 초기화하고 조건이 부합하는 배열 모음이 있을 때마다 카운트를 증가시킨다.

 

3. 새로 알게 된 점

- inline 키워드를 사용해 많이 호출하는 함수를 인라인화해봤다. 함수 호출하는 비용을 없애고 컴파일 단계에서 코드를 옮겨놓은 효과라고 해서 썼다. 프로그래밍한 내 입장해선 엄청난 차이가 있는지 체감할 수는 없지만 이렇게 사용하는 방법을 익혀두는 것도 좋을 것 같다.

- 개발을 대강 마치고 나서 다른 거 개발하러 갔다가 오니 다시 시작하기 너무 어려웠다. 포스팅하기 위해 대강 정리하고 다시 파악하는 수고를 들였는데 이래서 처음부터 짜임새 있는 코드를 짜라고 하는 것을 느꼈다.

 

4. 코드

 4-1. header.h

#ifndef __BINGO_H__
#define __BINGO_H__

#include<iostream>
#include<Windows.h>
#include<ctime>

using namespace std;

enum class MENU
{
	SINGLE = 1,
	COMPUTER
};
struct Bingo
{
	int m_table[5][5] = { 0, };
	bool m_isCheck[5][5] = { false, };
	int m_bingoCnt = 0;
	bool m_bingoShow[3] = { true, true, true };
};

void Gotoxy(int, int);
void SetConsoleView(void);

void ShowReadyGameTable(void);
void ShowEmptyArr(void);
void ShowEmptyBottom(void);
void ShowMenu(void);
MENU GetInput(void);
void ShowWrongMenu(void);

void RandomChooseNum(int(*)[5]);
bool CheckOverlap(int(*)[5], int, int);

int ShowPressNum(void);

bool CheckNumInArr(Bingo&, int);

void DrawGameTable(Bingo);
inline void DrawNumOrChar(Bingo, int, int);
void ShowCheckNum(int);

int CheckBingoLine(const Bingo);
void ShowBingoCnt(int);

void ShowNotCheckNum(int);
void ShowGameover(void);

const int horizon = 5;
const int vertical = 5;

#endif

 4-2. function.cpp

#include "header.h"

void Gotoxy(int x, int y)
{
	COORD position;
	position.X = 2 * x;
	position.Y = y;
	SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), position);
}

void SetConsoleView(void)
{
	system("mode con:cols=55 lines=25");

}

void ShowReadyGameTable(void)
{
	ShowEmptyArr();
	ShowEmptyBottom();
	system("cls");

	ShowEmptyArr();
	cout << " 메세지\t|\t엔터를 눌러주세요.\t\t|" << endl;
	cout << "======================================================" << endl;
	cout << "  입력\t|" << endl;
	cout << "======================================================" << endl;
	Gotoxy(5, 17);
	cin.get();
	system("cls");

	ShowEmptyArr();
	ShowMenu();
}

void ShowEmptyArr(void)
{
	cout << "======================================================" << endl;
	cout << "=====B===I===N===G===O==============G===A===M===E=====" << endl;
	cout << "======================================================" << endl;
	cout << "\t|  [1]\t|  [2]\t|  [3]\t|  [4]\t|  [5]\t|" << endl;
	cout << "--------+-------+-------+-------+-------+-------+-----" << endl;
	cout << "   [1]\t|\t|\t|\t|\t|\t|" << endl;
	cout << "--------+-------+-------+-------+-------+-------|" << endl;
	cout << "   [2]\t|\t|\t|\t|\t|\t|" << endl;
	cout << "--------+-------+-------+-------+-------+-------|" << endl;
	cout << "   [3]\t|\t|\t|\t|\t|\t|" << endl;
	cout << "--------+-------+-------+-------+-------+-------|" << endl;
	cout << "   [4]\t|\t|\t|\t|\t|\t|" << endl;
	cout << "--------+-------+-------+-------+-------+-------|" << endl;
	cout << "   [5]\t|\t|\t|\t|\t|\t|" << endl;
	cout << "--------+---------------------------------------+-----" << endl;
}

void ShowEmptyBottom(void)
{
	cout << " 메세지\t|\t\t\t\t\t|" << endl;
	cout << "======================================================" << endl;
	cout << "  입력\t|" << endl;
	cout << "======================================================" << endl;
	Sleep(1000);
}

void ShowMenu(void)
{
	cout << " 메세지\t|1. 혼자 빙고\t\t2.컴퓨터와 빙고\t|" << endl;
	cout << "======================================================" << endl;
	cout << "  입력\t|" << endl;
	cout << "======================================================" << endl;
}

MENU GetInput(void)
{
	int inputNum;
	Gotoxy(5, 17);
	cin >> inputNum;
	while (((MENU)inputNum < MENU::SINGLE) || ((MENU)inputNum > MENU::COMPUTER))
	{
		system("cls");
		ShowWrongMenu();
		Gotoxy(5, 17);
		cin >> inputNum;
	}
	return (MENU)inputNum;
}

void ShowWrongMenu(void)
{
	ShowEmptyArr();
	cout << " 메세지\t|\t다시 입력해주세요.\t\t|" << endl;
	cout << "======================================================" << endl;
	cout << "  입력\t|" << endl;
	cout << "======================================================" << endl;
	Gotoxy(5, 17);
	cin.get();
	cin.get();
	system("cls");

	ShowEmptyArr();
	ShowMenu();
}

void RandomChooseNum(int(*arr)[5])
{
	bool isOverlap = false;
	srand((unsigned int)time(NULL));
	for (int i = 0; i < horizon; i++)
	{
		for (int j = 0; j < vertical; j++)
		{
			arr[i][j] = (rand() % 25) + 1;

			// 컴퓨터가 비교 연산하는 모습 보고 싶으면 주석처리 풀기
			/*system("cls");
			DrawGameTable(arr);*/

			if ((i == 0) && (j == 0))
			{
				continue;
			}
			else
			{
				isOverlap = CheckOverlap(arr, i, j);

				if (isOverlap)
				{
					if (j == 0)
					{
						i--;
						j = vertical - 1;
					}
					else
						j = j - 1;
				}
			}
		}

	}
}

bool CheckOverlap(int(*arr)[5], int horizonIdx, int verticalIdx)
{
	bool result = false;
	int vertIdx = vertical;
	for (int i = 0; i <= horizonIdx; i++)
	{
		if (i == horizonIdx)
			vertIdx = verticalIdx;
		for (int j = 0; j < vertIdx; j++)
		{
			if (arr[horizonIdx][verticalIdx] == arr[i][j])
			{
				result = true;
				break;
			}
		}
		if (result == true)
			break;
	}
	return result;
}

int ShowPressNum(void)
{
	int input;

	cout << " 메세지\t|\t체크할 숫자를 입력하세요.\t|" << endl;
	cout << "======================================================" << endl;
	cout << "  입력\t|" << endl;
	cout << "======================================================" << endl;
	Gotoxy(5, 17);
	cin >> input;

	return input;
}

bool CheckNumInArr(Bingo& bingo, int checkNum)
{
	bool isFind = false;
	int i, j;

	for (i = 0; i < horizon; i++)
	{
		for (j = 0; j < vertical; j++)
		{
			if (bingo.m_table[i][j] == checkNum)
			{
				isFind = true;
				bingo.m_isCheck[i][j] = isFind;
				i = horizon;
				break;
			}
		}
	}

	return isFind;
}

void DrawGameTable(Bingo bingo)
{
	cout << "======================================================" << endl;
	cout << "=====B===I===N===G===O==============G===A===M===E=====" << endl;
	cout << "======================================================" << endl;
	cout << "\t|  [1]\t|  [2]\t|  [3]\t|  [4]\t|  [5]\t|" << endl;
	cout << "--------+-------+-------+-------+-------+-------+-----" << endl;
	cout << "   [1]\t|   "; DrawNumOrChar(bingo, 0, 0); cout << "\t|   ";
	DrawNumOrChar(bingo, 0, 1); cout << "\t|   ";
	DrawNumOrChar(bingo, 0, 2); cout << "\t|   ";
	DrawNumOrChar(bingo, 0, 3); cout << "\t|   ";
	DrawNumOrChar(bingo, 0, 4); cout << "\t|   ";
	cout << endl;
	cout << "--------+-------+-------+-------+-------+-------|" << endl;
	cout << "   [2]\t|   "; DrawNumOrChar(bingo, 1, 0); cout << "\t|   ";
	DrawNumOrChar(bingo, 1, 1); cout << "\t|   ";
	DrawNumOrChar(bingo, 1, 2); cout << "\t|   ";
	DrawNumOrChar(bingo, 1, 3); cout << "\t|   ";
	DrawNumOrChar(bingo, 1, 4); cout << "\t|   ";
	cout << endl;
	cout << "--------+-------+-------+-------+-------+-------|" << endl;
	cout << "   [3]\t|   "; DrawNumOrChar(bingo, 2, 0); cout << "\t|   ";
	DrawNumOrChar(bingo, 2, 1); cout << "\t|   ";
	DrawNumOrChar(bingo, 2, 2); cout << "\t|   ";
	DrawNumOrChar(bingo, 2, 3); cout << "\t|   ";
	DrawNumOrChar(bingo, 2, 4); cout << "\t|   ";
	cout << endl;
	cout << "--------+-------+-------+-------+-------+-------|" << endl;
	cout << "   [4]\t|   "; DrawNumOrChar(bingo, 3, 0); cout << "\t|   ";
	DrawNumOrChar(bingo, 3, 1); cout << "\t|   ";
	DrawNumOrChar(bingo, 3, 2); cout << "\t|   ";
	DrawNumOrChar(bingo, 3, 3); cout << "\t|   ";
	DrawNumOrChar(bingo, 3, 4); cout << "\t|   ";
	cout << endl;
	cout << "--------+-------+-------+-------+-------+-------|" << endl;
	cout << "   [5]\t|   "; DrawNumOrChar(bingo, 4, 0); cout << "\t|   ";
	DrawNumOrChar(bingo, 4, 1); cout << "\t|   ";
	DrawNumOrChar(bingo, 4, 2); cout << "\t|   ";
	DrawNumOrChar(bingo, 4, 3); cout << "\t|   ";
	DrawNumOrChar(bingo, 4, 4); cout << "\t|   ";
	cout << endl;
	cout << "--------+---------------------------------------+-----" << endl;
}

inline void DrawNumOrChar(Bingo bingo, int horiz, int verti)
{
	if (bingo.m_isCheck[horiz][verti] == false)
		cout << bingo.m_table[horiz][verti];
	else
		cout << "*";
}

void ShowCheckNum(int CheckNum)
{
	cout << " 메세지\t|\t" << CheckNum << "이/가 체크됐습니다.\t\t| " << endl;
	cout << "======================================================" << endl;
	cout << "  입력\t|" << endl;
	cout << "======================================================" << endl;
	Sleep(1000);
}

int CheckBingoLine(const Bingo bingo)
{
	int cnt = 0;
	for (int horiz = 0; horiz < horizon; horiz++)
	{
		if (bingo.m_isCheck[horiz][0] && bingo.m_isCheck[horiz][1] && bingo.m_isCheck[horiz][2] && bingo.m_isCheck[horiz][3] && bingo.m_isCheck[horiz][4])
			cnt++;
	}
	for (int verti = 0; verti < vertical; verti++)
	{
		if (bingo.m_isCheck[0][verti] && bingo.m_isCheck[1][verti] && bingo.m_isCheck[2][verti] && bingo.m_isCheck[3][verti] && bingo.m_isCheck[4][verti])
			cnt++;
	}
	if (bingo.m_isCheck[0][0] && bingo.m_isCheck[1][1] && bingo.m_isCheck[2][2] && bingo.m_isCheck[3][3] && bingo.m_isCheck[4][4])
		cnt++;
	if (bingo.m_isCheck[0][4] && bingo.m_isCheck[1][3] && bingo.m_isCheck[2][2] && bingo.m_isCheck[3][1] && bingo.m_isCheck[4][0])
		cnt++;
	return cnt;
}

void ShowBingoCnt(int bingoCnt)
{
	cout << " 메세지\t|\t" << bingoCnt << " BINGO!\t\t\t| " << endl;
	cout << "======================================================" << endl;
	cout << "  입력\t|" << endl;
	cout << "======================================================" << endl;
	Sleep(1000);
}

void ShowNotCheckNum(int notCheckNum)
{
	cout << " 메세지\t|\t" << notCheckNum << "은/는 없습니다.\t\t| " << endl;
	cout << "======================================================" << endl;
	cout << "  입력\t|" << endl;
	cout << "======================================================" << endl;
	Sleep(1000);
}

void ShowGameover(void)
{
	cout << " 메세지\t|\t게임을 종료합니다.\t\t|" << endl;
	cout << "======================================================" << endl;
	cout << "  입력\t|" << endl;
	cout << "======================================================" << endl;
	Sleep(1000);
}

 4-3. main.cpp

#include"header.h"

int main(void)
{
	Bingo bingo;
	MENU menu;
	int inputNum;
	bool isCheck;

	SetConsoleView();
	ShowReadyGameTable();

	menu = GetInput();
	system("cls");
	switch (menu)
	{
	case MENU::SINGLE:
		RandomChooseNum(bingo.m_table);
		while (bingo.m_bingoCnt < 3)
		{
			DrawGameTable(bingo);
			inputNum = ShowPressNum();
			isCheck = CheckNumInArr(bingo, inputNum);
			system("cls");

			switch (isCheck)
			{
			case true:
				DrawGameTable(bingo);
				ShowCheckNum(inputNum);
				system("cls");

				DrawGameTable(bingo);
				bingo.m_bingoCnt = CheckBingoLine(bingo);
				if ((bingo.m_bingoCnt > 0) && (bingo.m_bingoShow[bingo.m_bingoCnt - 1]))
				{
					ShowBingoCnt(bingo.m_bingoCnt);
					bingo.m_bingoShow[bingo.m_bingoCnt - 1] = false;
				}
				break;
			case false:
				DrawGameTable(bingo);
				ShowNotCheckNum(inputNum);
				break;
			}
			system("cls");
		}
		break;
	case MENU::COMPUTER:
		ShowEmptyArr();
		ShowEmptyBottom();
		Gotoxy(5, 17);
		cout << "구현되지 않았습니다.";
		Sleep(3000);
		Gotoxy(5, 19);
		break;
	}

	ShowEmptyArr();
	ShowGameover();

	return 0;
}

5. 결과

2번 선택지는 아직 없다... 저것도 해야하는데...
가운데 숫자를 입력하면...
야호! 체크가 된다
이렇게 3개의 빙고를 달성하면 게임이 끝난다

- 미구현된 컴퓨터와의 대전과 배우고 있는 데이터를 클래스화하는 것을 하러 다시 오겠다..!