본문 바로가기

Unity/Unity 스파르타

3주차, 콘솔창으로 블랙젝 만들기

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 = "";
         }
  • 본격적으로 게임을 시작하는 로직을 만들어 줍니다.
  • 와일문 안에 두가지 영역을 나눠서 작업할 것입니다.
    1. 플레이어가 Hit 으로 새로운 카드를 받고 플레이어가 게임을 계속 진행할 수 있는 상태인지 확인하는 영역
    2. 플레이어가 카드를 받을지(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가지 영역으로 나눌 것 입니다.
      1. 딜러가 Stand 했을 경우
        • 딜러가 Stand 하는 경우는 오버로딩한 예측함수에서 예측 점수가 21이 아니고, 21이 넘지 않고, 플레이어 점수보다 높은 경우 Stand 하게 됩니다.
      2. 딜러가 Bust 됐을 경우
        • 딜러의 점수가 21점을 초과하했을때
          • 플레이어가 블랙젝을 달성 했을 경우, 게임 결과에 블랙젝으로 플레이어의 승리 처리 해줍니다.
          • 아닌 경우 딜러의 Bust로 플레이어의 승리 입니다.
      3. 딜러와 플레이어의 점수가 똑같을 경우
        • 무승부 처리 해줍니다.
      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