오늘은 스파르타 코딩 클럽 unity 게임 개발 과정 8일차!(블랙잭 만들기)

2023. 11. 8. 23:44스파르타코딩클럽 게임개발

반응형

C# 문법 3주차 숙제 2번째 과제 블랙잭 만들기

 

 

 블랙잭 만들기

블랙잭 게임은 카지노에서 흔히 볼 수 있는 카드 게임 중 하나입니다. 이번 과제에서는 간단한 콘솔 기반의 블랙잭 게임을 C#으로 구현해 보도록 하겠습니다.
요구사항:
  • 블랙잭 게임은 1명의 플레이어와 1명의 딜러가 참여합니다.
  • 게임 시작 시, 플레이어와 딜러는 각각 두 장의 카드를 받습니다.
  • 플레이어는 21점이 넘지 않는 한 계속해서 카드를 더 받을 수 있습니다.
  • 딜러는 카드 합이 17점이 되거나 넘을 때까지 계속해서 카드를 받아야 합니다.
  • 카드를 더 이상 받지 않는 플레이어와 딜러 중 카드 합이 21점에 더 가까운 쪽이 승리합니다. 21점을 초과하면 패배합니다.
  • Card, Deck, Hand, Player, Dealer, Blackjack 등의 클래스를 활용해 구현해야 합니다.

 

 

블랙잭은 클래스의 구현이 다양하다.

그래서 클래스를 사용하는 방법을 정확히 알아야 객체를 잘 만들 수 있다.

 

1.클래스란?

  • 클래스는 객체를 생성하기 위한 템플릿 또는 설계도 역할을 한다.
  • 클래스는 속성과 동작을 가진다. 속성은 필드로, 동작은 메서드로 표현된다.
  • 객체를 생성하기 위해서는 클래스를 사용하여 인스턴스를 만들어야 한다.
  • 붕어빵틀로 비유하면, 클래스는 붕어빵을 만들기 위한 틀이라고 할 수 있다.

2.클래스의 구성요소

  • 필드 (Fields): 클래스에서 사용되는 변수를 말한다. 객체의 상태를 나타내는 데이터를 저장하기 위해 사용된다.
  • 메서드 (Methods): 클래스에서 수행되는 동작이 정의된다. 객체의 동작을 구현하기 위해 사용된다.
  • 생성자 (Constructors): 객체를 초기화하는 역할을 한다. 객체가 생성될 때 자동으로 호출되며, 필드를 초기화하는 등의 작업을 수행한다.
  • 소멸자 (Destructors): 객체가 소멸될 때 호출되는 메서드로, 메모리나 리소스의 해제 등의 작업을 수행한다.

 

3.클래스 규칙

  • 동일 네임스페이스에 클래스명이 중복되면 안된다. 
  • 상속은 하나만, 인터페이스 구현은 여러개 가능하다. 

4.클래스를 구성하는 항목들

  • 생성자    멤버변수    속성상수    메서드이벤트    인덱서    중첩클래스    종료자

5.예시

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
public class Class2 { // 클래스 선언과 클래스명
 
        // 멤버 : 클래스 내에 선언 가능한 구성항목
        private string _firstName;
        private string _lastName;
 
        // 속성
        public string Name => $"{_firstName} {_lastName}";
        private int _age;
        public int Age {
            get => _age;
            set => _age = value;
        }
 
        // 상수
        public const int month = 12, weeks = 52
 
        // 생성자1
        public Class2() : this("default""kim") {
        }
        // 생성자2
        public Class2(string firstName, string lastName) {
            _firstName = firstName;
            _lastName = lastName;
        }
 
        // 함수
        public void setAge(int age) {
        }
        public string getName() {
            return this.Name;
        }
        public Func<string> getName2 = () => "Jason";
    }
cs

 

 

6.블랙잭 코드 전문

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
 
public enum Suit { 하트, 다이아몬드, 클로버, 스페이스 }
public enum Rank { Two = 2, Three, Four, Five, Six, Seven, Eight, Nine, Ten, Jack, Queen, King, Ace }
// 카드 한 장을 표현하는 클래스
public class Card
{
        public Suit Suit { get; private set; }
        public Rank Rank { get; private set; }
 
        public Card(Suit s, Rank r)
        {
                Suit = s;
                Rank = r;
        }
 
        public int GetValue()
        {
                if ((int)Rank <= 10)
                {
                        return (int)Rank;
                }
                else if ((int)Rank <= 13)
                {
                        return 10;
                }
                else
                {
                        return 11;
                }
        }
 
 
        public override string ToString()
        {
                return $"{Rank} of {Suit} ";
        }
}
 
// 덱을 표현하는 클래스
public class Deck
{
        private List<Card> cards;
 
        public Deck()
        {
                cards = new List<Card>();
 
                foreach (Suit s in Enum.GetValues(typeof(Suit)))
                {
                        foreach (Rank r in Enum.GetValues(typeof(Rank)))
                        {
                                cards.Add(new Card(s, r));
                        }
                }
 
                Shuffle();
        }
 
        public void Shuffle()
        {
                Random rand = new Random();
 
                for (int i = 0; i < cards.Count; i++)
                {
                        int j = rand.Next(i, cards.Count);
                        Card temp = cards[i];
                        cards[i] = cards[j];
                        cards[j] = temp;
                }
        }
 
        public Card DrawCard()
        {
                Card card = cards[0];
                cards.RemoveAt(0);
                return card;
        }
}
 
// 패를 표현하는 클래스
public class Hand
{
        private List<Card> cards;
 
        public Hand()
        {
                cards = new List<Card>();
        }
 
        public void AddCard(Card card)
        {
                cards.Add(card);
        }
 
        public int GetTotalValue()
        {
                int total = 0;
                int aceCount = 0;
 
                foreach (Card card in cards)
                {
                        if (card.Rank == Rank.Ace)
                        {
                                aceCount++;
                        }
                        total += card.GetValue();
                }
 
                while (total > 21 && aceCount > 0)
                {
                        total -= 10;
                        aceCount--;
                }
 
                return total;
        }
        public string OnCard()
        {
                StringBuilder sb = new StringBuilder();
                foreach (Card card in cards)
                {
                        sb.Append(card.ToString());
                }
                return sb.ToString(); ;
        }
        public override string ToString()
        {
                return base.ToString();
        }
}
 
// 플레이어를 표현하는 클래스
public class Player
{
        public Hand Hand { get; private set; }
 
        public Player()
        {
                Hand = new Hand();
        }
 
        public Card DrawCardFromDeck(Deck deck)
        {
                Card drawnCard = deck.DrawCard();
                Hand.AddCard(drawnCard);
                return drawnCard;
        }
}
 
// 여기부터는 학습자가 작성
// 딜러 클래스를 작성하고, 딜러의 행동 로직을 구현하세요.
public class Dealer : Player
{
        //17이상 까지 드로우해야됨
        public bool StandChecking(Deck deck)
        {
                return Hand.GetTotalValue() < 17;
        }
}
 
// 블랙잭 게임을 구현하세요. 
public class Blackjack
{
        public Deck Deck { get; private set; }
        public Player Player { get; private set; }
        public Dealer Dealer { get; private set; }
        public Blackjack()
        {
                Deck = new Deck();
                Player = new Player();
                Dealer = new Dealer();
        }
        public void StratGame()
        {
                foreach (var item in Enumerable.Range(02))
                {
                        PlayerDrawCard();
                        DealerDrawCard();
                }
        }
        public void PlayerDrawCard()
        {
                Player.DrawCardFromDeck((Deck)Deck);
        }
        public void DealerDrawCard()
        {
                Dealer.DrawCardFromDeck((Deck)Deck);
        }
        // 코드를 여기에 작성하세요
        public bool BlackjackChecking(Hand hand)
        {
                if (hand.GetTotalValue() == 21return true;
                return false;
        }
        public bool BustChecking(Hand hand)
        {
                if (hand.GetTotalValue() > 21return true;
                return false;
        }
        public override string ToString()
        {
                return base.ToString();
        }
        /*
       HIT (히트): 카드를 더 받는것
       STAND (스탠드): 카드를 그만 받고 멈추는 것
       BLACKJACK (블랙잭): 처음 받은 두 장의 카드의 합이 21일 경우 EX) A,10과 같은 조합
       BUST (버스트): 받은 카드의 합이 21이 넘어가는 경우 – 패배함
       DOUBLE DOWN (더블 다운): 두 장의 카드를 받고 한장만 더 받는 조건으로 판돈을 2배로 올려 배팅하는 것
       SPLIT (스플릿) : 처음 받은 두 장의 카드가 같을 경우 두 개로 나뉘어 한 판에 진행하는 것
       */
 
}
internal class BlackjackGame
{
        static void Main()
        {
                ConsoleKeyInfo key;
                Blackjack blackjack = new Blackjack();
                Deck deck = blackjack.Deck;
                int playerValue = 0;
                int dealerValue = 0;
                int currentPlayer = 0// Player 0 starts (플레이어 0이 시작)
                Console.WriteLine("게임을 시작합니다.");
                blackjack.StratGame();
                Console.WriteLine($"{blackjack.Player}의 카드는 {blackjack.Player.Hand.OnCard()} 점수는 {blackjack.Player.Hand.GetTotalValue()} ");
                Console.WriteLine($"{blackjack.Dealer}의 카드는 {blackjack.Dealer.Hand.OnCard()} 점수는 {blackjack.Dealer.Hand.GetTotalValue()} ");
                while (true)
                {
                        var turn = (currentPlayer == 0) ? blackjack.Player : blackjack.Dealer;
                        playerValue = blackjack.Player.Hand.GetTotalValue();
                        dealerValue = blackjack.Dealer.Hand.GetTotalValue();
                        if (currentPlayer == 0)
                        {
                                Console.WriteLine("카드를 더 받으시겠습니까? 더 받으시려면 엔터키를 눌러주세요. 그렇지 않다면 다른 아무 키나 누르세요.");
                                key = Console.ReadKey();
 
                                if (key.Key == ConsoleKey.Enter)
                                {
                                        turn.DrawCardFromDeck(deck);
                                }
                                else if (playerValue < dealerValue)
                                {
                                        Console.WriteLine("카드를 뽑지 않았습니다..");
                                        break;
                                }
                                else
                                {
                                        Console.WriteLine("카드를 뽑지 않았습니다. 딜러에게 턴이 넘어갑니다.");
                                        currentPlayer = 1// 플레이어가 카드를 더 이상 뽑지 않을 때, 딜러의 턴으로 전환합니다.
                                        turn = (currentPlayer == 0) ? blackjack.Player : blackjack.Dealer;
                                }
                        }
                        Console.WriteLine($"{turn}의 카드는 {turn.Hand.OnCard()} 점수는 {turn.Hand.GetTotalValue()} ");
 
                        if (currentPlayer == 1 && blackjack.Dealer.StandChecking(deck))
                        {
                                turn.DrawCardFromDeck(deck);
                                Console.WriteLine($"{turn}는 17이 안되어 한 번 더 뽑음 {turn}의 카드는 {turn.Hand.OnCard()} 점수는 {turn.Hand.GetTotalValue()} ");
                        }
 
                        if (blackjack.BlackjackChecking(turn.Hand))
                        {
                                Console.WriteLine($"{turn.ToString()}이 블랙잭!");
                                break;
                        }
                        else if (blackjack.BustChecking(turn.Hand))
                        {
                                Console.WriteLine($"{turn.ToString()}이 버스트되었습니다.");
                                break;
                        }
                        if (currentPlayer == 1 && blackjack.Dealer.Hand.GetTotalValue() <= blackjack.Player.Hand.GetTotalValue())
                        {
                                turn.DrawCardFromDeck(deck);
                                Console.WriteLine($"{turn}는 플레이어보다 점수가 작아 한 번 더 뽑음 {turn}의 카드는 {turn.Hand.OnCard()} 점수는 {turn.Hand.GetTotalValue()} ");
                        }
                        currentPlayer = (currentPlayer == 0) ? 1 : 0;
                }
                playerValue = blackjack.Player.Hand.GetTotalValue();
                dealerValue = blackjack.Dealer.Hand.GetTotalValue();
                Console.WriteLine($"{playerValue}{dealerValue}");
                // 무승부인 경우
                if (playerValue == dealerValue)
                {
                        Console.WriteLine("무승부입니다.");
                }
                // 플레이어가 이긴 경우
                if (playerValue > dealerValue && playerValue <= 21 || playerValue <= 21 && dealerValue > 21)
                {
                        Console.WriteLine($"{blackjack.Player}의 점수({playerValue})가 {blackjack.Dealer}의 점수({dealerValue})보다 블랙잭에 가깝습니다. 플레이어의 승리!");
                }
                // 딜러가 이긴 경우
                if (dealerValue > playerValue && dealerValue <= 21 || dealerValue <= 21 && playerValue > 21)
                {
                        Console.WriteLine($"{blackjack.Dealer}의 점수({dealerValue})가 {blackjack.Player}의 점수({playerValue})보다 블랙잭에 가깝습니다.딜러의 승리!");
                }
 
                Console.WriteLine("게임이 종료되었습니다.");
        }
 
cs

 

 

7.ConsoleKeyInfo 사용하기

 

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
 
ConsoleKeyInfo cki; // 구조체
Console.Clear(); // 화면을 지운다.
Console.SetCursorPosition(x, y); //커서 좌표값 재설정 (40, 12)
Console.Write('#'); // 커서가 있는 (40, 12) 위치에 #을 표시
cki = Console.ReadKey(true); //키 자체를 입력 받는다. true : 화면에 다시출력 안함
switch (cki.Key) //해당 키가 눌리면 실행
{
    case ConsoleKey.LeftArrow: // 열거형
    break;
    case ConsoleKey.RightArrow:
    break;
    case ConsoleKey.UpArrow:
    break;
    case ConsoleKey.DownArrow:
    break;
    case ConsoleKey.Q:
    return;
}
 
          
cs

 

방향키를 입력하여 움직임을 만들어 내거나 다음 턴으로 넘어가거나 하는 기능을 만들어 낼 수있다.

 

정리 


  • 더 익숙하게 클래스를 사용할 수 있다.
  • ConsoleKeyInfo 속성을 사용할 수 있다.

 

 

 

 

 

반응형