C++기초
220318 - 빙고 게임 만들기
hyrule
2022. 3. 25. 16:28
////저번에 만든 빙고 게임에 AI를 추가해서 1:1 대전을 만들기. 이번에 추가한 주석은 // 두개를 추가하였음.
#include <iostream>
#include <time.h>
////AI의 난이도 설정
enum class AIType
{
None,
Easy,
Hard,
Max
//Easy와 Hard는 정상적인 값, None와 Max는 잘못 입력되었을때의 값.
};
int main()
{
srand((unsigned int)time(0));
int Random = rand();
////난이도 입력 받기
int AIState = 0;
while (true) ////잘못 선택되었을 떄를 대비한 while문
{
system("cls");
std::cout << "1. 쉬움" << std::endl;
std::cout << "2. 어려움" << std::endl;
std::cout << "난이도를 선택하세요 : ";
std::cin >> AIState;
if (AIState > (int)AIType::None &&
AIState < (int)AIType::Max)
break;
}
/*
* AI의 Easy와 Hard 모드
Easy 모드는 그냥 남아있는 숫자 중에 랜덤하게 고름
Hard 모드는 남아있는 숫자 중 빙고를 더 맞출 확률이 높은 숫자를 고름.
*/
// 1 ~ 25 까지의 숫자를 저장하기 위한 공간을 준비한다.
////여기에 추가적으로 인공지능용 숫자판을 추가.
int Number[25] = {};
int AINumber[25] = {};
// 1 ~ 25까지의 숫자를 배열에 넣어준다.
for (int i = 0; i < 25; ++i)
{
Number[i] = i + 1;
AINumber[i] = i + 1;
}
// 숫자를 랜덤하게 배치해준다.
////AI의 빙고판도 섞어준다. 물론 플레이어의 빙고판을 섞은 뒤
////난수를 새로 만들어야 개별적으로 셔플이 가능하다.
for (int i = 0; i < 100; ++i)
{
int Idx1 = rand() % 25;
int Idx2 = rand() % 25;
int Temp = Number[Idx1];
Number[Idx1] = Number[Idx2];
Number[Idx2] = Temp;
Idx1 = rand() % 25;
Idx2 = rand() % 25;
Temp = AINumber[Idx1];
AINumber[Idx1] = AINumber[Idx2];
AINumber[Idx2] = Temp;
}
////AI 빙고라인 저장용 AI 추가.
int Line = 0, AILine = 0;
////인공지능이 선택을 하기 위해서 현재 안바뀐 값을 저장할 배열을 만들어 준다.
int SelectArray[25] = {};
////AI가 현재 선택할 수 있는 숫자가 몇개인지를 저장할 변수를 만들어 준다.
int SelectCount = 0;
while (true)
{
system("cls");
std::cout << "============= Player ================================================== AI =================" << std::endl;
for (int i = 0; i < 5; ++i)
{
////플레이어 빙고판 한 줄 작성하고
for (int j = 0; j < 5; ++j)
{
if (Number[i * 5 + j] == INT_MAX) //지운 숫자를 INT_MAX값으로 저장해놓고, 이후 *로 표시
std::cout << "*\t";
else
std::cout << Number[i * 5 + j] << "\t";
}
////이후 AI의 빙고판을 한 줄 작성한다.
std::cout << "\t\t";
for (int j = 0; j < 5; ++j)
{
if (AINumber[i * 5 + j] == INT_MAX) //지운 숫자를 INT_MAX값으로 저장해놓고, 이후 *로 표시
std::cout << "*\t";
else
//std::cout << AINumber[i * 5 + j] << "\t"; //디버그용. 컴퓨터 숫자 다 보임.
std::cout << "*" << "\t";
}
std::cout << std::endl;
}
std::cout << "Bingo Line : " << Line << "\t\t\t\t\t\t";
std::cout << "AI Bingo Line : " << Line << std::endl;
////플레이어 체크 이후
if (Line >= 5)
{
std::cout << "Player Win" << std::endl;
break;
}
////AI 승리 체크 확인
else if (AILine >= 5)
{
std::cout << "AI Win" << std::endl;
break;
}
std::cout << "Input Number(0 : Exit) : ";
int CheckNumber = 0;
std::cin >> CheckNumber;
if (CheckNumber == 0)
break;
else if (CheckNumber < 0 || CheckNumber > 25)
continue;
// 배열의 각 요소와 체크값을 비교하여 해당 값이 있는지
// 판단한다.
bool Check = false;
for (int i = 0; i < 25; ++i)
{
if (Number[i] == CheckNumber)
{
// 숫자가 있다면 해당 숫자를 *로 바꿔준다.
Number[i] = INT_MAX;
Check = true;
break;
}
}
// 이미 입력한 숫자를 다시 입력했다면 Check 변수는
// false를 유지하고 있을 것이다.
// 즉 Check변수가 false일 경우 다시 입력받게 한다.
//if (Check == false)
//if (false == Check)
if (!Check)
continue;
////정상적인 숫자를 입력하여 플레이어의 숫자가 *로 바뀌었을 경우 AI의 숫자에서도 해당 값을 찾아서 *로 바꾸어 준다.
////-->> 두 빙고판을 모두 바꿔주어야 함.
for (int i = 0; i < 25; ++i)
{
if (AINumber[i] == CheckNumber)
{
AINumber[i] = INT_MAX;
break;
}
}
////플레이어가 선택한 숫자를 모두 바꾸었다면 인공지능이 선택할 수 있도록 한다.
switch ((AIType)AIState)
{
case AIType::Easy:
////*우리가 해야할 것
// 1.현재 입력 안된 값들을 찾아서 배열에 넣어준다
//
// */
SelectCount = 0;
for (int i = 0; i < 25; ++i)
{
//// '*'이 아닌 일반 값일 경우 --> 아직 입력받은 값이 아닌 경우 AI가 고를 수 있는 배열에 해당 값을 넣어준다
/*알고리즘 예시
1. 3 * 7 8 * * 2
2. 3 7 8 2 , SelectCount = 4
3-1. easy 모드일 경우
이후 random % SelectCount를 해서 랜덤한 값을 추출
*/
if (AINumber[i] != INT_MAX)
{
SelectArray[SelectCount] = AINumber[i];
++SelectCount;
}
}
CheckNumber = SelectArray[rand() % SelectCount];
break;
case AIType::Hard:
////Hard 모드의 경우 숫자가 제일 적게 남은 줄을 체크해서 해당 줄의 넘버만 뽑음
break;
} ////AI의 숫자 선택 완료.
//디버그
/*std::cout << "AI Select : " << CheckNumber << std::endl;
system("pause");*/
////AI가 선택한 숫자를 *로 바꿔주도록 한다.(플레이어와 AI의 빙고판 모두)
for (int i = 0; i < 25; ++i)
{
if (Number[i] == CheckNumber)
{
Number[i] = INT_MAX;
break;
}
}
for (int i = 0; i < 25; ++i)
{
if (AINumber[i] == CheckNumber)
{
AINumber[i] = INT_MAX;
break;
}
}
// 빙고 줄을 체크한다.
// 빙고 줄을 0으로 초기화를 하고 모든 줄을 체크해본다.
Line = 0;
AILine = 0;
for (int i = 0; i < 5; ++i)
{
int CheckCount = 0, CheckCount1 = 0;
int AICheckCount = 0, AICheckCount1 = 0;
for (int j = 0; j < 5; ++j)
{
////유저
// 가로 줄 체크
if (Number[i * 5 + j] == INT_MAX)
++CheckCount;
// 세로 줄 체크
if (Number[j * 5 + i] == INT_MAX)
++CheckCount1;
////AI
// 가로 줄 체크
if (AINumber[i * 5 + j] == INT_MAX)
++AICheckCount;
// 세로 줄 체크
if (AINumber[j * 5 + i] == INT_MAX)
++AICheckCount1;
}
// 가로 한 줄을 체크했는데 CheckCount 변수가
// 5라면 해당 줄은 모두 *로 변경되어 있다는 것이다.
////유저
if (CheckCount == 5)
++Line;
if (CheckCount1 == 5)
++Line;
////AI
if (AICheckCount == 5)
++AILine;
if (AICheckCount1 == 5)
++AILine;
}
////대각선 빙고체크. 마찬가지로 AI 체크카운트 추가
// 왼쪽 상단 -> 오른쪽 하단
int CheckCount2 = 0, AICheckCount2 = 0;
for (int i = 0; i < 25; i += 6)
{
if (Number[i] == INT_MAX)
++CheckCount2;
if (AINumber[i] == INT_MAX)
++AICheckCount2;
}
if (CheckCount2 == 5)
++Line;
if (AICheckCount2 == 5)
++AILine;
CheckCount2 = 0, AICheckCount2 = 0;
// 오른쪽 상단 -> 왼쪽 하단
for (int i = 4; i <= 20; i += 4)
{
if (Number[i] == INT_MAX)
++CheckCount2;
if (AINumber[i] == INT_MAX)
++AICheckCount2;
}
if (CheckCount2 == 5)
++Line;
if (AICheckCount2 == 5)
++AILine;
}
return 0;
}