본문 바로가기

강의자료/C/C++

022. 카드게임 - 블랙잭.

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


블랙잭을 작성하기 전에 간단한 규칙의 카드게임을 만들어보자.
/*
- 크기가 2인 배열 player와 computer을 생성하세요.(각각 카드 2장을 가집니다.)
- player와 computer배열에 각각 1~11사이의 숫자를 랜덤하게 저장하고 출력하시오.
- player와 computer배열의 각각의 총합을 출력하고 합이 더 큰 쪽이 게임에 승리하도록 메시지를 출력하세요. 
  만약 총합이 서로 같다면 무승부로 출력하세요.

Player	Computer
4		10
4		7
Result	Result
8		17

The winner is Player

- 두 카드의 합계가 더 작더라도 두 카드가 같은 수 일 경우에는 두 카드가 같지 않은 경우보다 
  무조건 승리하도록 작성하세요.
- player와 computer 모두 두 카드가 같은 카드가 나왔을 경우에는 합계가 더 큰 쪽이 승리하도록 작성하세요.
- 둘 다 같은 카드이고 합계도 같을 경우에는 무승부로 출력하세요.
*/

#include 
#include 
using namespace std;

int ArraySum( int num[], int counts );
void ShowResult( int playerSum, int computerSum );

void main()
{
	int player[2] = {0, 0};
	int computer[2] = {0, 0};

	srand((unsigned)time(NULL));   //random 초기화 
	for(int i=0; i < 2; i++)
	{
		player[i]= (rand() % 11) + 1;
		computer[i]= (rand() % 11) + 1;
	}

	cout << "Player" << "\t" << "Computer" << endl;
	for(int i=0; i < 2; i++)
	{
		cout << player[i] << "\t" << computer[i] << endl;
	}

	int playerSum = ArraySum(player, sizeof(player)/sizeof(int));
	int computerSum = ArraySum(computer, sizeof(computer)/sizeof(int));

	cout << "Result" << "\t" << "Result" << endl;
	cout << playerSum << "\t" << computerSum << endl;
	cout << endl;

	if(player[0] == player[1])
	{
		if(computer[0] == computer[1])
		{
			ShowResult(playerSum, computerSum);
		}
		else
		{
			ShowResult(1, 0);
		}
	}
	else if(computer[0] == computer[1])
	{
		ShowResult(0, 1);
	}
	else
	{
		ShowResult(playerSum, computerSum);
	}

	cout << endl;
}
int ArraySum( int num[], int counts ){
	int sum = 0;
	for(int i=0; i < counts; i++)
	{
		sum += num[i];
	}
	return sum;
}
void ShowResult( int playerSum, int computerSum )
{
	if(playerSum > computerSum) cout << "The winner is Player" << endl;
	else if(playerSum < computerSum) cout << "The winner is Computer" << endl;
	else cout << "This game is draw" << endl;
}
# 블랙잭 게임 : 난이도를 낮추기 위해서 1번카드(Ace)가 1과 11로 사용된다는 규칙을 바꿔서 무조건 1로만 사용되도록 하고, 대신에 K를 모두 11로 사용하도록 한다.
/***********************************************************************************************
과제 : 다음 규칙에 따라 블랙잭 게임을 작성하세요.
	- 52장의 카드를 담을 int형 배열 card를 생성하세요.
	- card배열에 {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 10, 10, 11}를 4번 반복해서 저장하세요.
	- card가 제대로 생성되었는지 화면에 순서대로 출력하세요.
	- 플레이이어의 카드를 담을 int형 배열 player를 생성하세요.(크기는 게임규칙에 맞게)
	- 컴퓨터의 카드를 담을 int형 배열 computer을 생성하세요.(크기는 게임규칙에 맞게)
	- 기타 변수는 게임규칙에 따라 필요한 만큼 선언하여 사용하세요.

# 게임 규칙.
	- 기본 규칙.
		○ 카드의 합이 21에 가까울수록 승리한다. 단, 21보다 커지게 되면 패한다.
		○ 프로그램의 복잡성을 피하기 위해 기존 블랙잭 게임의 규칙을 수정 : 
		   기존에는 1을 1과 11로 원하는 대로 사용할 수 있지만 이 프로그램에서는 1과 11을 따로 존재하도록 한다.
	- 게임 시작 시,
		○ 스왑기법을 이용하여 52장의 카드를 섞는다.
		○ 플레이어와 컴퓨터에게 각각 2장의 카드를 반드시 1장씩 번갈아서 나눠준다.
	- 매 턴마다,
		○ 플레이어카드의 합이 21보다 작을 경우 플레이어에게 카드를 더 받을지 물어본다.
		   더 받겠다고 하면 player배열에 한 장의 카드를 추가하고 현재까지 받은 카드를 모두 순서대로 화면에 출력한다. 
		   더 받지 않겠다고 하거나 받은 카드의 합이 블랙잭(21)이면 더이상 카드를 추가하지 않는다.
		○ 컴퓨터카드의 합이 15보다 작을 경우, computer배열에 한 장의 카드를 추가한다.
		   받은 카드의 합이 15이상이면 더이상 카드를 추가하지 않는다.
		○ 추가되는 카드는 card배열에서 순서대로 꺼내어서 사용해야 한다. 
		   또한, 플레이어와 컴퓨터 모두 카드를 받지 않는 상태가 되기 전까지는 서로 카드를 번갈아 가며 받아야 한다.
		   (어느 한쪽에 연속2장이 들어가지 않도록 해야 한다.)
		○ 카드를 추가한 후 카드의 합이 21보다 커질 경우, 해당 플레이어 또는 컴퓨터는 자동으로 패하도록 한다.(게임오버)
		○ 플레이어와 컴퓨터 모두 카드를 받지 않는 상태가 될 때까지 매 턴을 반복 수행한다.
	- 플레이어와 컴퓨터 모두 카드를 더이상 받지 않겠다고 한 경우,
		○ 카드의 합이 더 큰 쪽을 승리자로 처리한다. 단, 같을 경우에는 무승부로 처리한다.
	- 승부가 났을 경우,
		○ 플레이어와 컴퓨터가 현재까지 받은 카드를 모두 순서대로 화면에 출력하고, 각각의 총합 역시 화면에 출력한다.
		○ 승리자를 화면에 출력한다. (무승부일 경우 무승부라고 출력한다.)
		○ 게임을 계속 진행할 것인지 물어보고 계속 하겠다고 할 경우, 게임을 다시 시작한다. 
		   계속 하지 않겠다고 할 경우, 종료 메시지를 출력하고 프로그램을 종료한다.
**********************************************************************************************/

//// 포인터 변수에 넣을 수 있는 유일한 숫자 NULL.
//// int* num = NULL; 의 의미에 대해서 알려주자.

#include 
#include   //
#include 
using namespace std;

// 최대 11장을 가질 수 있도록 한다.
// 최소한의 숫자만을 가진다고 하더라도 1*4 + 2*4 + 3*3 = 21이 되기때문이다.
#define BLACKJACK	21
#define COM_LIMIT	15
#define MAX_CARD	11

void PrintTitle(char* title);						// 제목출력.
void PrintCard(int* card, int counts);				// 카드출력.
void ShuffleCard(int* card, int counts);			// 카드섞기.
void InitReceivedCard(int* card);					// 소유한 카드 초기화.
void ShowReceivedCard(int* player, int* computer);	// 소유한 카드 보여주기.
void ShowResult(int playerSum, int computerSum);	// 결과 출력.
bool IsYesOrNo(char* str);							// Y or N 입력 확인.
int  GetCardSum(int* card);							// 카드의 합.

void main()
{
	srand((unsigned)time(NULL));   // random 초기화.

	int card[52] = {0};		// 카드를 담을 배열 생성.
	int counts = sizeof(card)/sizeof(int);

	// 카드 초기화.
	for(int row = 0; row < 4; row++)
	{
		for(int column = 0; column < 13; column++)
		{
			int cardNum = column + row*13;

			if(column < 10) card[cardNum] = column + 1;			// 1~10 입력.
			else if(column < 12) card[cardNum] = 10;			// 10 두장 입력.
			else card[cardNum] = 11;							// 마지막에 11 입력.
		}
	}

	// 카드 출력.
	PrintTitle("카드 출력");
	PrintCard(card, counts);

	cout << endl << "게임을 시작하려면 Enter키를 누르세요." << endl;
	_getch();

	// 플레이어와 컴퓨터 카드 생성.
	int player[MAX_CARD] = {0};
	int computer[MAX_CARD] = {0};

	bool isGameStart = true;	// 게임시작 여부.
	bool isGameEnd;				// 게임종료 여부.(승부가 났을 경우에 true)
	bool stayPlayer;			// 카드를 더 받을지 말지 여부.	
	bool stayComputer;

	int nowCardNum = 0;			// 현재 카드 번호, 카드더미에서 꺼낸 카드의 개수.
	int receivedCounts = 0;		// 플레이어와 컴퓨터가 카드를 받은 횟수.

	// 게임 루프.
	while(true)
	{
		system("cls");

		/*************************************************************************
		/* 의사코드.
		/*************************************************************************

		// 초기화 코드.
		if(isGameStart)
		{
			// 게임에 필요한 초기화 작업 수행..
			isGameStart = false;
		}

		// 승부내기 코드.
		if(isGameEnd)
		{
			// 승자를 화면에 표시.
			// 유저에게 게임을 계속 할 것인지 물어본다.
			// 유저가 게임을 계속할 경우, 초기화 -> isGameStart = true;
			// 유저가 게임을 중지할 경우, 루프 탈출 -> break;
		}

		// 매 턴마다 수행할 코드.
		// 1. 플레이어의 카드를 화면에 출력.
		// 2. 플레이어에게 카드를 더 받을지 물어본다.
		//    플레이어의 카드의 합이 블랙잭이거나 그 이상이면, -> isGameEnd = true;
		// 3. 컴퓨터에게 카드를 더 받을지 물어본다.
		//    컴퓨터의 카드의 합이 블랙잭이거나 그 이상이면, -> isGameEnd = true;
		// 4. 플레이어와 컴퓨터가 모두 카드를 받지 않겠다고 한 경우, 
		//    승부를 낸다. -> isGameEnd = true;


		// 코드가 여기까지 내려오면, 아직 누군가가 카드를 더 받을 의사가 있으므로,
		// 카드를 받은 횟수를 증가시킨다.
		receivedCounts++;
		*************************************************************************/

		// 게임 초기화 : 게임시작시에만 수행되어야 한다.
		if(isGameStart)
		{
			// 게임이 시작했음을 알린다.
			isGameStart = false;
			isGameEnd = false;
			stayPlayer = false;
			stayComputer = false;

			// 카드를 처음부터 받도록 한다.
			receivedCounts = 0;
			nowCardNum = 0;

			// 카드 초기화.			
			InitReceivedCard(player);
			InitReceivedCard(computer);

			// 카드를 섞는다.
			ShuffleCard(card, counts);

			// 플레이어와 컴퓨터에게 카드를 2장씩 나눠준다.
			for(int i=0; i < 2; i++)
			{
				player[receivedCounts] = card[nowCardNum++];
				computer[receivedCounts] = card[nowCardNum++];

				// 카드를 받은 횟수를 증가시킨다.
				receivedCounts++;
			}
		}

		// 승부 내기 코드.
		if(isGameEnd)
		{
			// 승자를 화면에 표시.
			system("cls");
			PrintTitle("승부가 났습니다.");
			ShowReceivedCard(player, computer);
			ShowResult(GetCardSum(player), GetCardSum(computer));

			// 유저에게 다시 게임을 할 것인지 물어본다.
			if(IsYesOrNo("게임을 계속 하시겠습니까?"))
			{
				// Yes를 선택하면 게임초기화.
				isGameStart = true;
				continue;
			}
			else
			{
				// No를 선택하면 게임종료.
				break;
			}
		}

		// 매턴마다 수행할 코드.

		// 플레이어의 카드를 화면에 출력한다.
		PrintTitle("플레이어의 카드");
		ShowReceivedCard(player, NULL);

		// 플레이어 : 추가 카드를 받는다.
		if(stayPlayer == false)
		{
			int player_sum = GetCardSum(player);

			if(player_sum > BLACKJACK)
			{
				isGameEnd = true;
				continue;
			}
			else if(player_sum == BLACKJACK)
			{
				stayPlayer = true;
			}
			else
			{
				if(IsYesOrNo("추가 카드를 받으시겠습니까?"))
				{
					player[receivedCounts] = card[nowCardNum++];
				}
				else
				{
					stayPlayer = true;
				}
			}
		}

		// 컴퓨터 : 추가 카드를 받는다.
		if(stayComputer == false)
		{
			int computer_sum = GetCardSum(computer);

			if(computer_sum > BLACKJACK)
			{
				isGameEnd = true;
				continue;
			}
			else if(computer_sum >= COM_LIMIT)	// BLACKJACK 포함.
			{
				stayComputer = true;
			}
			else
			{
				computer[receivedCounts] = card[nowCardNum++];
			}
		}

		// 플레이어와 컴퓨터 모두 카드를 더이상 받지 않겠다고 한 경우, 승부를 낸다.
		if(stayPlayer && stayComputer) isGameEnd = true;

		// 코드가 여기까지 내려오면, 아직 누군가가 카드를 더 받을 의사가 있으므로,
		// 카드를 받은 횟수를 증가시킨다.
		receivedCounts++;
	}

	PrintTitle("게임이 종료되었습니다.");
	system("PAUSE");
}
void PrintTitle(char* title)
{
	cout << "〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓" << endl;
	cout << "> " << title << endl;
	cout << "〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓" << endl;
}
void PrintCard(int* card, int counts)
{
	for(int i=0; i < counts; i++)
	{
		cout << card[i] << "\t";
	}
	cout << endl;
}
void ShuffleCard(int* card, int counts)
{
	for(int i=0; i < counts; i++)
	{
		int rnd		= (rand() % counts);
		int temp	= card[i];       
		card[i]		= card[rnd];
		card[rnd]	= temp;
	}
}
void InitReceivedCard(int* card)
{
	for(int i=0; i < MAX_CARD; i++)
	{
		card[i] = 0;
	}
}
void ShowReceivedCard(int* player, int* computer)
{
	if(player == NULL && computer == NULL) return;

	bool showPlayer = (player==NULL)?false:true;
	bool showComputer = (computer==NULL)?false:true;

	if(showPlayer) cout << "플레이어";
	cout << "\t";
	if(showComputer) cout << "컴퓨터";
	cout << endl;

	for(int i=0; i < MAX_CARD; i++)
	{
		if(showPlayer == false && showComputer == false) break;

		if(showPlayer)
		{
			if(player[i] != 0) cout << player[i];
			else showPlayer = false;
		}		

		cout << "\t\t";

		if(showComputer)
		{
			if(computer[i] != 0) cout << computer[i];
			else showComputer = false;
		}

		cout << endl;
	}
}

void ShowResult(int playerSum, int computerSum)
{
	enum WINNER {NONE, PLAYER, COMPUTER, DRAW};

	cout << "결과" << "\t\t" << "결과" << endl;
	cout << playerSum << "\t\t" << computerSum << endl;

	WINNER winner = NONE;

	if(playerSum > 21) winner = COMPUTER;
	else if(computerSum > 21) winner = PLAYER;
	else
	{
		if(playerSum > computerSum) winner = PLAYER;
		else if(playerSum < computerSum) winner = COMPUTER;
		else winner = DRAW;
	}

	switch(winner)
	{
	case PLAYER:	cout << "축하합니다. 당신이 이겼습니다."; break;
	case COMPUTER:	cout << "이런, 컴퓨터가 이겼군요."; break;
	case DRAW:		cout << "컴퓨터와 서로 비겼습니다."; break;
	}

	cout << endl << endl;
}
bool IsYesOrNo(char* str)
{
	char yesorno = ' ';
	cout << str << " (Y/N) : ";
	cin >> yesorno;
	cout << endl;

	if(yesorno == 'y' || yesorno == 'Y')
	{
		return true;
	}
	else
	{
		return false;
	}
}

int GetCardSum(int* card)
{
	int sum = 0;
	for(int i=0; i < MAX_CARD; i++)
	{
		if(card[i] == 0) break;

		sum += card[i];
	}

	return sum;
}