지난번 과제인 블랙잭 게임의 풀이 및 복습.
기존 과제에서는 플레이어1,딜러1 의 1:1 구조였다면
이번 과제는 플레이어의 수를 입력받고 플레이어의 이름을 입력받아
딜러1 vs 플레이어 다수 의 구조가 되는 방식이다.
오늘 과제 풀이에 딜러와 플레이어가 동점일경우에도 플레이어의 패배 및 딜러의 승리로 추가 수정하였다.
오랜만에 동적할당 해제를 끝부분에 섰는데 사용법이 맞는지는 모르겠다..
어려웠고 몇번 복습해서 OOP 구조에대해 좀더 익숙해 져야 할것같다.
#include <iostream>
#include <time.h>
#include <string>
#include <vector>
#define SET 3
using namespace std;
enum Shape //모양 함수 4종류
{
DIA,
CLOVER,
HEART,
SPADE
};
enum Num //특정숫자는 문자출력을 위한 함수
{
A = 1,
J = 11,
Q,
K
};
struct Card // 구조체 카드 (숫자, 모양, 특정숫자는 문자변환출력)
{
int num;
string shape;
void Print()
{
switch (num)
{
case A:
cout << shape << "A" << "\t";
break;
case J:
cout << shape << "J" << "\t";
break;
case Q:
cout << shape << "Q" << "\t";
break;
case K:
cout << shape << "K" << "\t";
break;
default:
cout << shape << num << "\t";
break;
}
}
};
struct Player //플레이어 구조체 (이름 돈 카드 점수 승패 카드패출력)
{
string name;
int money;
vector<Card>card;
int jokbo = 0; //카드의합 초기화 = 처음상태는 0
bool win; //승패용 변수
void MakeJokbo(bool dealer = 0)
{
jokbo = 0;
int select; //플레이어의 패중에 A의카드가있을시 1또는 11점수 선택용 변수
for (int i = 0; i < card.size(); i++) //카드갯수만큼 반복시킬 반복문
{
if (card[i].num > 10) //카드의 넘버가 10이상인경우는 무조건 10만 더해지도록설정
{
jokbo += 10;
}
else if (card[i].num == 1) //카드가 1 즉,카드가 A패일 경우
{
if (!dealer) // 딜러가아닐때 = 즉, 플레이어일때
{
for (int i = 0; i < card.size(); i++) // 카드패만큼반복하면서 출력시킴
{
card[i].Print();
}
cout << "A카드획득. 카드점수선택. [1]=1점 / [2]=11점 "; //점수선택 출력
cin >> select; //선택 입력
if (select == 1) //1번선택
{
jokbo += 1; // 1번카드는 점수1점
}
else if (select == 2) // 2번선택
{
jokbo += 11; // 1번카드는 점수11점
}
}
else
{
jokbo += 1; //그외에는 그냥 A카드 1점더하기
}
}
else // a카드가 아니고 다른카드일경우 그냥 일반점수더하기
{
jokbo += card[i].num;
}
}
}
void Print(bool dealer = 0)
{
cout <<"["<< name<<"]" << "\t";
for (int i = 0; i < card.size(); i++) // 딜러도 플레이어도 점수는 출력된다
{
card[i].Print();
}
cout << "점수 : " << jokbo << "\t";
if (!dealer) //딜러가아니라면 = 플레이어라면 소지금 출력
{
cout << "소지금 : " << money << "\t";
}
cout << endl;
}
};
Card MakeDeck(int num, string shape) //카드덱 만들기, 구조체안에있는 숫자 모양 불러오기
{
Card temp; // 카드덱의 빈 인덱스 생성
temp.num = num; // 빈인덱스의 숫자생성
temp.shape = shape; // 빈인덱스의 모양생성
return temp; // 빈인덱스 반환
}
void Shuffle(vector<Card>& deck) //카드섞기(셔플) 벡터로할당된 카드구조체의 덱주소
{
for (int i = 0; i < 1000; i++) //대충 천번정도 셔플해주기
{
int sour = rand() % (52 * SET); //52개의 카드 총 SET갯수 전부 셔플해준다.
int dest = rand() % (52 * SET);
Card temp = deck[sour]; //기본셔플형식. 단 카드구조체셔플.
deck[sour] = deck[dest];
deck[dest] = temp;
}
}
//===============================================================================함수구성끝
int main() // 메인 시작
{
srand(time(NULL));
vector<Card>deck;
Player* player;
Player dealer;
int cardCount = 0; //카드의 합계산을위한 초기화
int input;
int size;
//덱만들기
for (int i = 0; i < 52*SET; i++) // 총카드는 52개가한묶음으로 define SET 갯수만큼 곱해진다.
{ // 52개의 묶음 *3 이기때문에 같은카드는 3개까지 나오게된다.
string temp;
int cut = i % 52; // 0~51까지 카운트후 다시 0부터 51까지만 카운트되도록
switch (cut / 13) // 52개의 카드는 4종류의 모양으로 나뉜다. 초 4종 각각 13장씩 52장
{
case DIA:
temp = "◆";
break;
case CLOVER:
temp = "♣";
break;
case HEART:
temp = "♥";
break;
case SPADE:
temp = "♠";
break;
}
deck.push_back(MakeDeck(i % 13 + 1, temp));
}
//========================================== 게임 시작전 기본세팅
cout <<"\t" << "[블랙잭 게임]"<<"\t" << endl;
cout << endl;
cout << "게임에 참가할 인원수를 입력해 주세요 : " << "\t"; cin >> size;
cout << endl;
player = new Player[size]; //플레이어의 인원수입력에따른 동적할당.
for (int i = 0; i < size; i++) //참가인원수 만큼 반복하며 이름 입력받기
{
cout << i + 1 << "번 참가자의 이름을 입력 : " << "\t";
cin >> player[i].name; // 구조체에 동적할당 받았기때문에 직접 palyer[i].name 에 접촉이 가능
player[i].money = 100000; // 플레이어들의 소지금은 단순히 통일시킴.
}
dealer.name = "딜러"; // 딜러의 이름은 단순히 딜러
dealer.money = 100000; // 딜러도 일단 금액설정해둔다.
//=========================================== 본게임 시작
while (true) //게임은 게속 반복 되도록 설정
{
cardCount = 0; //카드나누어줄때 같은 배열에있는 카드가 겹치지않도록 카운트초기화
//0번배열에있는 카드부터 순차대로 나눠준다.
//카드는 나눠줄때마다 배열순서대로 나눠준다 (배열은 셔플되어있음)
Shuffle(deck); // 게임시작전 덱셔플해주기
for (int i = 0; i < size; i++) //게임 인원수 설정만큼 반복
{
cout << endl;
cout << "=======================================" << player[i].name << "의 차례입니다." << endl;
cout << endl;
player[i].win = true; //게임플레이어의 상태는 기본 참값으로 하여 진행되도록한다.
player[i].money -= 1000; // 새게임마다 1천원씩 소지금 감소
player[i].card.clear(); //새게임시작시 기존의 카드패는 초기화
player[i].card.push_back(deck[cardCount]); //새로운 카드 벡터로 1장받는다
cardCount++; //카드배열 하나증가. (0번카드 받고 다음받을수있는카드는 1번카드)
player[i].card.push_back(deck[cardCount]); //새로운 카드 벡터로 1장받는다
cardCount++; //카드배열 하나증가. (1번카드 받고 다음받을수있는카드는 2번카드)
//카드를 받았다면 현재 카드의 합을 보여준뒤 더받을지 멈출지 확인하기
player[i].MakeJokbo(); //플레이어의 족보(카드의합)을 계산시킨다.
//그리고나서 출력
player[i].Print(); // 프린트 함수를 이용하여 소지카드 점수 소지금 등을 보이게한다.
//출력이되어 확인하였으면 추가카드 받기여부
while (true) //버스트하거나 그만받을때까지 반복한다
{
cout << "추가카드를 받으시겠습니까? [1]YES / [2]NO" << "\t"; cin >> input;
if (input == 2)
{
break; // 카드를 더안받는선택시 반복문 탈출한다.
}
// 2번선택이 아니라면 아래 코드진행
player[i].card.push_back(deck[cardCount]); //카드한장만 더받고
cardCount++; // 이후 제공될 카드 인덱스카운트 증가
player[i].MakeJokbo(); // 카드를 받아서 다시 점수 계산을하고
player[i].Print(); // 출력시킨다
if (player[i].jokbo > 21) //플레이어의 카드점수가 21점이 넘어갔을경우
{
cout << player[i].name << "참가자가 버스트 ! " << endl;
player[i].win = false; // 플레이어의 승리가 거짓값으로 바뀐다 = 패배.
break; //진행중인 반복문을 탈출한다.
}
else
{
player[i].win = true; // 카드합계가 21이넘지않는한 플레이어의 상태는 그대로이다.
}
}
}
//플레이어 설정후 딜러 설정
dealer.win = true; //딜러의 상태도 기본 참값이다.
dealer.card.clear(); //딜러도 마찬가지로 게임시작때마다 패는 초기화 시킨다.
dealer.card.push_back(deck[cardCount]);
cardCount++;
dealer.card.push_back(deck[cardCount]);
cardCount++; // 딜러도 매판마다 카드 2장을 받으며 분배할카드 인덱스는 줄때마다증가.
cout << endl;
cout << "=======================================" << dealer.name << "의 차례입니다." << endl;
cout << endl;
//딜러패의 합계산
dealer.MakeJokbo(true); // 함수의 매개변수가 참인이유는 함수는 플레이어 함수에 들어가지않게하기위해서
//딜러패의 출력
dealer.Print(true); // 매개변수가 참인이유는 위와 동일.
//딜러는 카드의합이 17미만인경우 자동적으로 카드를 더 받도록 설정한다.
while (dealer.jokbo < 17)
{
dealer.card.push_back(deck[cardCount]); //조건에일치하면 카드한장을 더받고
cardCount++; //카드인덱스 1증가
dealer.MakeJokbo(true); //딜러패의 점수 계산
dealer.Print(true); //게산후 출력
if (dealer.jokbo > 21) //딜러의 점수가 21점이 넘으면 버스트시키고
{
cout << dealer.name << " 의 버스트 ! " << endl;
dealer.win = false; //딜러의 상태는 패배가된다.
for (int i = 0; i < size; i++) //플레이어 인원수만큼 반복문을 돌려서
{
if (player[i].win) //만약 플레이어의 상태가 win 이라면
{
cout << player[i].name << " 승리 ! " << endl; //해당플레이어의 승리
player[i].money += 3000; //승리한 플레이어는 소지금이 3천원 추가된다.
}
}
break; // 반복문을 탈출한다.
}
else
{
dealer.win = true; // 점수의 합이 21만넘지않는다면 패배상태가 아니다.
}
}
//반복문 내에서 승패 비교까지 이루어져야한다.
for (int i = 0; i < size; i++) // 승패조건의검사는 플레이어의 수만큼 반복되서 검사된다
{
if (dealer.win && player[i].win) // 딜러와 플레이어 양쪽이 버스트가 아닌상태에서
{
if (dealer.jokbo < player[i].jokbo) // 딜러의 점수보다 플레이어의 점수가 높다면
{
cout << player[i].name << " 승리 ! " << endl; //해당플레이어의 승리
player[i].money += 3000; //승리한 플레이어는 소지금이 3천원 추가된다.
}
else if (dealer.jokbo = player[i].jokbo)
{
cout << player[i].name << " 패배 ! " << "\t";
cout << "동점은 딜러 승리 입니다. " << endl;
player[i].win = false;
}
else
{
cout << "딜러 승리 입니다 ! " << endl;
cout << player[i].name << " 패배 ! " << endl;
player[i].win = false;
}
}
}
}
for (int i = 0; i < size; i++)
{
delete[i] player;
}
delete[] player;
return 0;
}
'공부' 카테고리의 다른 글
C++ 다수 컴퓨터 가위 바위 보 게임 (0) | 2022.11.17 |
---|---|
C++ 이전과제 클래스구조로 변환시키기 (0) | 2022.11.16 |
C++ OOP 조사 (0) | 2022.11.15 |
블랙잭 과제 (진행중) (0) | 2022.11.15 |
C++ 블랙잭(1:1) 코드 복습 (0) | 2022.11.14 |
댓글