類別設計
// 撲克牌
public class Card {
public Suit Suit { get; }
public Rank Rank { get; }
public int Value => Rank switch {
Rank.Ace => 11, // 或 1,邏輯在 Hand 計算
Rank.King or Rank.Queen or Rank.Jack => 10,
_ => (int)Rank
};
public Card(Suit s, Rank r) { Suit = s; Rank = r; }
public override string ToString() => $"{Rank} of {Suit}";
}
public enum Suit { Clubs, Diamonds, Hearts, Spades }
public enum Rank { Two=2, Three, Four, Five, Six, Seven, Eight, Nine, Ten, Jack, Queen, King, Ace }
// 牌堆
public class Deck {
private readonly List cards = new();
private readonly Random rng = new();
public Deck() { Reset(); }
public void Reset() { cards.Clear(); foreach (Suit s in Enum.GetValues()) foreach (Rank r in Enum.GetValues()) cards.Add(new Card(s, r)); }
public Card Draw() { if (cards.Count == 0) return null; int i = rng.Next(cards.Count); var c = cards[i]; cards.RemoveAt(i); return c; }
public void Shuffle() { /* Fisher-Yates */ }
}
// 手牌 (自動計算點數、處理 Ace 1/11)
public class Hand {
private readonly List cards = new();
public IReadOnlyList Cards => cards;
public void Add(Card c) => cards.Add(c);
public int Score {
get {
int sum = cards.Sum(c => c.Value);
int aces = cards.Count(c => c.Rank == Rank.Ace);
while (sum > 21 && aces > 0) { sum -= 10; aces--; } // Ace 11→1
return sum;
}
}
public bool IsBlackjack => cards.Count == 2 && Score == 21;
public bool IsBust => Score > 21;
public override string ToString() => string.Join(", ", cards) + $" (點數: {Score})";
}
// 玩家基類
public abstract class Player {
public string Name { get; }
public Hand Hand { get; } = new Hand();
public int Chips { get; private set; }
public Player(string name, int chips) { Name = name; Chips = chips; }
public void Win(int amount) => Chips += amount;
public bool Bet(int amount) { if (Chips >= amount) { Chips -= amount; return true; } return false; }
public abstract bool WantHit(Hand dealerUpCard); // 策略由子類實作
}
// 人類玩家
public class HumanPlayer : Player {
public HumanPlayer(string name, int chips) : base(name, chips) {}
public override bool WantHit(Hand dealerUpCard) {
Console.Write($"{Name} 目前點數 {Hand.Score},要牌? (y/n): ");
return Console.ReadLine()?.Trim().ToLower() == "y";
}
}
// 莊家 (固定策略: <17 要牌)
public class Dealer : Player {
public Dealer() : base("莊家", int.MaxValue) {}
public override bool WantHit(Hand dealerUpCard) => Hand.Score < 17;
}
主遊戲迴圈
public class BlackjackGame {
private readonly Deck deck = new Deck();
private readonly List players = new();
private readonly Dealer dealer = new Dealer();
public void Run() {
Console.WriteLine("=== 歡迎來到 21 點 ===");
InitPlayers();
while (true) {
PlayRound();
Console.Write("再玩一局? (y/n): ");
if (Console.ReadLine()?.Trim().ToLower() != "y") break;
ResetRound();
}
Console.WriteLine("謝謝遊玩,再見!");
}
private void InitPlayers() {
Console.Write("玩家人數 (1-5): ");
int n = int.Parse(Console.ReadLine() ?? "1");
for (int i = 1; i <= n; i++) {
Console.Write($"玩家 {i} 姓名: ");
string name = Console.ReadLine() ?? $"Player{i}";
Console.Write($"{name} 起始籌碼: ");
int chips = int.Parse(Console.ReadLine() ?? "1000");
players.Add(new HumanPlayer(name, chips));
}
}
private void PlayRound() {
deck.Reset(); deck.Shuffle();
// 下注
foreach (var p in players) {
Console.Write($"{p.Name} (籌碼:{p.Chips}) 下注: ");
int bet = int.Parse(Console.ReadLine() ?? "0");
p.Bet(bet);
p.Hand.Add(deck.Draw());
p.Hand.Add(deck.Draw());
}
dealer.Hand.Add(deck.Draw());
dealer.Hand.Add(deck.Draw());
// 玩家回合
foreach (var p in players) {
Console.WriteLine($"\n--- {p.Name} 回合 ---");
while (!p.Hand.IsBust && p.WantHit(dealer.Hand)) {
p.Hand.Add(deck.Draw());
Console.WriteLine($" 抽到: {p.Hand.Cards.Last()}, 點數: {p.Hand.Score}");
}
if (p.Hand.IsBust) Console.WriteLine($" {p.Name} 爆牌!");
}
// 莊家回合
Console.WriteLine("\n--- 莊家回合 ---");
while (dealer.WantHit(null)) {
dealer.Hand.Add(deck.Draw());
Console.WriteLine($" 莊家抽到: {dealer.Hand.Cards.Last()}, 點數: {dealer.Hand.Score}");
}
// 結算
Console.WriteLine("\n=== 結算 ===");
foreach (var p in players) {
int result = Compare(p.Hand, dealer.Hand);
if (result > 0) { p.Win(p.CurrentBet * 2); Console.WriteLine($"{p.Name} 贏! 籌碼: {p.Chips}"); }
else if (result < 0) Console.WriteLine($"{p.Name} 輸! 籌碼: {p.Chips}");
else Console.WriteLine($"{p.Name} 平手! 籌碼: {p.Chips}");
}
}
private int Compare(Hand player, Hand dealer) {
if (player.IsBust) return -1;
if (dealer.IsBust) return 1;
return player.Score.CompareTo(dealer.Score);
}
private void ResetRound() {
foreach (var p in players) p.Hand = new Hand();
dealer.Hand = new Hand();
}
}
// Program.cs
class Program {
static void Main() => new BlackjackGame().Run();
}
執行畫面示意
=== 歡迎來到 21 點 ===
玩家人數 (1-5): 2
玩家 1 姓名: Alice
玩家 1 起始籌碼: 1000
玩家 2 姓名: Bob
玩家 2 起始籌碼: 1000
--- Alice 回合 ---
Alice 目前點數 18,要牌? (y/n): n
--- Bob 回合 ---
Bob 目前點數 14,要牌? (y/n): y
抽到: 7 of Hearts, 點數: 21
--- 莊家回合 ---
莊家抽到: King of Spades, 點數: 17
=== 結算 ===
Alice 平手! 籌碼: 1000
Bob 贏! 籌碼: 1100
再玩一局? (y/n): n
謝謝遊玩,再見!