ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 3주차, 콘솔창으로 블랙젝 만들기
    Unity/Unity 스파르타 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 = "";
             }
    • 본격적으로 게임을 시작하는 로직을 만들어 줍니다.
    • 와일문 안에 두가지 영역을 나눠서 작업할 것입니다.
      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
Designed by Tistory.