Unity/Unity 스파르타
3주차, 콘솔창으로 블랙젝 만들기
휘게31
2024. 1. 3. 21:16
728x90
콘솔창을 사용해 블랙젝 게임 만들기.
게임 설명
블랙젝이란 카드를 뽑아 카드의 합으로 딜러를 이기는 게임입니다.
카드의 합은 21을 넘길 수 없으며 21을 넘기게 되면 Bust로 게임에서 지게됩니다.
카드의 합이 21이 되면 블랙젝으로 게임에서 승리하게됩니다.
플레이어는 현재 자기 카드의 합을 계산하고 다음에 나올 카드를 예측해 카드를 더 받을지(Hit) 아니면 여기서 카드를 그만 받고(Stand)
딜러의 카드를 볼지 정할 수 있습니다. 딜러와 카드의 합이 똑같은 경우는 무승부로 게임이 종료됩니다.
현재 만드는 블랙젝 콘솔창 게임은 딜러와 플레이어의 1:1 을 기준으로 만들 것 입니다.
순서
1. 게임의 상태를 만듭니다.
2. 간단한 카드매니저를 만들어 줍니다.
3. 플레이어 클래스를 만들어줍니다. 이 클래스를 사용해 플레이어와 딜러로 재사용 할 것 입니다.
4. 게임 로직을 만들어 줍니다.
5. 딜러 로직을 만들어 줍니다.
6. 마무리 Console.Write 정리
1. 게임의 상태를 만듭니다.
- 두가지의 상태를 만들 것입니다. 먼저 하나는 게임의 상태로 플레이어가 이겼는지, 딜러가 이겼는지, 무승부가 났는지, 게임이 진행중인지에 대한 상태 입니다.
- 다른 하나는 플레이어의 상태로, 카드를 더 받을 것인지(Hit), 그만 받을 것인지(Stand), 카드의 합이 21을 넘겼는지(Bust), 카드의 합이 21인지(Black Jack),플레이어가 이겼는지 졌는지 무승부인지. 플레이어가 콘솔창에 입력을 잘못했을 경우도 생각해 상태 하나를(Wrong)를 넣어줍니다.
enum GameState
{
Playing,
PlayerWin,
DealerWin,
Tie
}
enum PlayerState
{
Hit,
Stand,
Bust,
BlackJack,
Win,
Lose,
Tie,
Wrong
}
2. 간단한 카드매니저를 만들어줍니다.
- 카드매니저는 카드팩이라는 클래스를 만들고 카드를 드로우 할때마다 카드팩 클래스를 사용해 카드를 가지고 올 것입니다.
class CardPack
{
string[] cards = { "A","2","3","4","5","6","7","8","9","Q","K","J" };
Random random = new Random();
public string CardDraw()
{
int randomIdx = random.Next(0, cards.Length);
return cards[randomIdx];
}
}
3.플레이어 클래스를 만들어줍니다.
- 플레이어 클래스를 재사용 할 것을 생각해 클래스를 만들어 줍니다.
class Player
{
public PlayerState playerState;
public List<string> playerHand;
public int playerHaveCard;
public int playerHaveACard;
public int playerScore;
public Player()
{
playerState = PlayerState.Hit;
playerHand = new List<string>();
playerHaveCard = 0;
playerScore = 0;
playerHaveACard = 0;
}
public void SetCard(string card)
{
playerHand.Add(card);
playerHaveCard++;
ScoreCalculation();
}
}
- 플레이어 클래스에는 플레이어가 기본 적으로 카드를 받으면 카드를 저장할 것이고, 카드를 저장하면 자동적으로 카드의 합을 계산할 것입니다. A 카드는 1 또는 11로 바꿔서 사용할 수 있기 때문에 단순 계산 로직에서는 현재 플레이어의 점수가 11점 보다 낮다면, 점수에 반영하지 않고 변환 사용 가능한 A카드 변수(playerHaveACard)에 추가해 줄 것입니다. 플레이어가 카드 받는걸 멈추고(Stand) 최종 점수를 계산할때 플레이어에게 A카드를 어떻게 사용할지 물어봐서 점수를 계산할 것 입니다.
void ScoreCalculation()
{
string card = playerHand[playerHaveCard - 1];
if (card == "A")
{
if(playerScore < 11)
{
playerHaveACard++;
}
else
{
playerScore++;
}
}else if(card == "K" | card == "Q" || card == "J")
{
playerScore += 10;
}
else
{
playerScore += int.Parse(card);
}
}
- 카드 A 의 경우에는 1 또는 11로 사용 할 수 있기 때문에 간단하게 플레이어의 점수를 예측하는 로직도 만들어 줍니다. 계산을 할때마다 기존의 점수를 참고해, 예측 점수를 계산하고 확인해 플레이어의 상태를 바꿔줍니다.
- 예측하는 로직의 경우 딜러로 새로운 클래스를 만들었을 때 플레이어의 점수와 비교하면서 예측 시킬 것 이기 때문에 나중에 오버로딩을 해줘서 사용할 것 입니다.
- 위 계산 로직에서는 11점보다 점수가 낮다면 A 카드를 전환사용 가능한 변수(plyaerHaveACard)에 카운트 하고 점수를 반영해주지 않기 때문에 예측 로직에서 A 카드를 제외한 플레이어의 점수를 참고해 A 카드를 1점으로 쓸지 11점으로 쓸지 정해 줄 것입니다.
public void PredictScore()
{
int predictScore = 0;
for (int i = 0; i < playerHaveCard; i++)
{
string card = playerHand[i];
if(card == "A")
{
if(playerScore >= 11 || predictScore >=11)
{
predictScore++;
}
else
{
predictScore += 11;
}
}else if(card == "Q" || card == "K" || card == "J")
{
predictScore += 10;
}
else
{
predictScore += int.Parse(card);
}
if(predictScore == 21)
{
Console.WriteLine("Black Jack!");
break;
}
else if(predictScore > 21)
{
playerState = PlayerState.Bust;
break;
}
}
}
4.게임 로직 만들기
- 게임을 시작하는 함수를 만들 것 입니다. 게임이 종료됐을 때 다시 게임을 할지 플레이어에게 물어보고 다시 게임을 시작할때 마다 게임 시작 함수를 불러올 것 입니다.
- 게임 시작시 기본적인 정보를 초기화 시켜주고 게임을 시작합니다.
- 새로운 플레이어를 생성해주고, 게임상태를 초기화 시켜줍니다. gameEndText에 경우 게임이 종료됐을 때 게임의 결과를 써줄 것 입니다.
void StartGame()
{
player = new Player();
gameState = GameState.None;
gameEndText = "";
}
- 본격적으로 게임을 시작하는 로직을 만들어 줍니다.
- 와일문 안에 두가지 영역을 나눠서 작업할 것입니다.
- 플레이어가 Hit 으로 새로운 카드를 받고 플레이어가 게임을 계속 진행할 수 있는 상태인지 확인하는 영역
- 플레이어가 카드를 받을지(Hit) 카드를 그만 받을지(Stand) 정하는 영역,
while (gameState == GameState.Playing)
{
Console.Clear();
if (player.playerState == PlayerState.Hit)
{
}
if (player.playerState == PlayerState.Hit || player.playerState == PlayerState.Wrong)
{
}
}
1. 플레이어가 Hit 으로 새로운 카드를 받고 플레이어가 게임을 계속 진행할 수 있는 상태인지 확인하는 영역
- 플레이어가 새로운 카드를 받습니다.
- 무슨 카드를 받았는지 콘솔창에 찍어줍니다.
- 점수 예측 함수를 실행해 줍니다.
- 플레이어의 상태를 확인해 줍니다.
- 주의 할점 * 플레이어의 점수가 21점 블랙젝이 됐을때 플레이어의 승리로 게임을 종료 시키면 안됩니다. 딜러 또한 21점으로 블랙젝이 될 확률이 있기때문에 딜러의 점수 까지 확인해줘야 합니다.
if (player.playerState == PlayerState.Hit)
{
player.SetCard(cardManager.CardDraw());
ShowMyCard(player.playerHand);
Console.WriteLine();
player.PredictScore();
if(player.playerState == PlayerState.Bust)
{
PlayerLose("Bust!! Player Lose!");
break;
}
}
2 .플레이어가 카드를 받을지(Hit) 카드를 그만 받을지(Stand) 정하는 영역,
- 플레이어의 상태가 게임을 계속 진행할 수 있는 경우와 혹여나 선택을 잘 못했을 경우에 다음 로직을 진행해 줍니다.
- 플레이어의 편의성을 위해 블랙젝인경우 바로 Stand를 선택하게 해줍니다.
- Hit을 고른 경우에는 와일문 처음으로 돌아가 다시 반복 시켜줍니다.
- Stand를 고른 경우에는 플레이어의 최종 점수를 계산해주고 딜러의 카드드로우 로직을 진행해 줍니다.
- 플레이어가 최종 점수 계산 로직에 A카드의 점수 계산을 잘못해 21점을 초과해 버릴 경우 Bust 시켜줍니다.
if (player.playerState == PlayerState.Hit || player.playerState == PlayerState.Wrong)
{
Console.WriteLine("1). Hit 2). Stand");
if (player.playerScore == 21)
{
option = "2";
}
else
{
option = Console.ReadLine();
}
if (option == "1")
{
player.playerState = PlayerState.Hit;
}
else if (option == "2")
{
player.playerState = PlayerState.Stand;
Final_PlayerScore_Calculation();
if (player.playerScore > 21)
{
PlayerLose("Player Bust! Player Lose!");
gameState = GameState.DealerWin;
}
else
{
StartDealer();
}
}
else
{
Console.WriteLine("다시 입력하시오");
player.playerState = PlayerState.Wrong;
}
}
5. 딜러 로직 만들기
- 위에 게임 로직과 비슷하지만 여러가지 적절하게 조건들을 잘 넣어 줘야 합니다.
- 먼저 만들어논 플레이어 클래스로 딜러를 만들어 줍니다.
- 콘솔창을 깨끗하게 만들어주고 상단에는 플레이어가 최종적으로 가지고 있는 카드들을 보여줍니다.
- 딜러가 카드를 뽑고 딜러의 카드 점수를 예측해 줍니다.
- 플레이어 클래스에 만들어 놓은 예측 함수를 오버로딩 해줄 것 입니다.
- 예측 방법은 똑같지만 여러 조건들을 붙이고 바로바로 딜러점수에 적용 시켜 줄 것 입니다.
- 주의 할점* 조건들을 적절한 위치에 걸어두는 것이 중요합니다.
- 먼저 4가지 영역으로 나눌 것 입니다.
- 딜러가 Stand 했을 경우
- 딜러가 Stand 하는 경우는 오버로딩한 예측함수에서 예측 점수가 21이 아니고, 21이 넘지 않고, 플레이어 점수보다 높은 경우 Stand 하게 됩니다.
- 딜러가 Bust 됐을 경우
- 딜러의 점수가 21점을 초과하했을때
- 플레이어가 블랙젝을 달성 했을 경우, 게임 결과에 블랙젝으로 플레이어의 승리 처리 해줍니다.
- 아닌 경우 딜러의 Bust로 플레이어의 승리 입니다.
- 딜러의 점수가 21점을 초과하했을때
- 딜러와 플레이어의 점수가 똑같을 경우
- 무승부 처리 해줍니다.
- 딜러가 블랙젝을 달성했을 경우
- 플레이어도 블랙젝인 경우, 결과에 둘다 블랙젝으로 무승부 처리 해줍니다.
- 아닌 경우 딜러의 블랙젝으로 딜러의 승리 입니다.
- 딜러가 Stand 했을 경우
- 먼저 4가지 영역으로 나눌 것 입니다.
void StartDealer()
{
Player dealer = new Player();
while (gameState == GameState.Playing)
{
Console.Clear();
//------------------------------------------------------------------------------------Show Player Score
Console.Write("Player ");
ShowMyCard(player.playerHand);
Console.WriteLine("\t<Socre: "+player.playerScore+">");
//------------------------------------------------------------------------------------Show Player Score
dealer.SetCard(cardManager.CardDraw());
Console.Write("Dealer ");
dealer.PredictScore(player.playerScore);
//------------------------------------------------------------------------------------Show Dealer Score
ShowMyCard(dealer.playerHand);
Console.WriteLine("\t<Socre: " + dealer.playerScore + ">");
//------------------------------------------------------------------------------------Show Dealer Score
if (dealer.playerState == PlayerState.Stand)
{
gameState = GameState.DealerWin;
gameEndText = "Dealer Stand! Player Lose!";
}else if(dealer.playerState == PlayerState.Bust)
{
if(player.playerScore == 21)
{
gameState = GameState.PlayerWin;
PlayerWin("Dealer Bust!! Player Black Jack!! Player Win!!");
}
else
{
gameState = GameState.PlayerWin;
PlayerWin("Dealer Bust! Player Win!!");
}
}else if(dealer.playerState == PlayerState.Tie)
{
gameState = GameState.Tie;
gameEndText = "Game is Tie!! ";
}else if(dealer.playerState == PlayerState.BlackJack)
{
if(player.playerScore == 21)
{
gameState = GameState.Tie;
gameEndText = "Black Jack Tie!!!";
}
else
{
gameState = GameState.DealerWin;
gameEndText = "Dealer Black Jack!! Dealer Win!!";
}
}
}
}
6. 마무리 Console.Write 정리
콘솔 창을 이용한 블랙젝 이기 때문에 콘솔창에 기본적인 문구들과, 카드들을 어떻게 보여줄지, 결과 창은 어떻게 보여줄지, 등등 정리 합니다.
완성
728x90