-
3주차, 콘솔창으로 블랙젝 만들기Unity/Unity 스파르타 2024. 1. 3. 21:16728x90
콘솔창을 사용해 블랙젝 게임 만들기.
게임 설명
블랙젝이란 카드를 뽑아 카드의 합으로 딜러를 이기는 게임입니다.
카드의 합은 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'Unity > Unity 스파르타' 카테고리의 다른 글
리스트, 구조체 - '깊은복사' '얕은 복사'에 대한 고찰 (0) 2024.01.08 4주차, 플레이어의 데이터 저장하기, 불러오기 (2) 2024.01.04 3주차, 콘솔창으로 스네이크 게임 만들기 (2) 2024.01.02 2주차, 배열과 리스트 고찰 + 콘솔을 이용한 틱택토 게임 만들기 (0) 2023.12.29 2주차, 사용자 데이터를 보여주는 UI 만들기(InputField - TextMeshPro) (0) 2023.12.26