首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> 程式設計綜合問答

C# 控制台 21 點遊戲:物件導向設計與完整實作

     編輯:程式設計綜合問答

類別設計


// 撲克牌
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
謝謝遊玩,再見!
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved