C#黑杰克(21点)扑克小游戏

本文为C#控制台应用程序,使用VS2019,.net framework 4.0,本测试程序只考虑一副52张的扑克牌。

黑杰克(21点)游戏规则如下:

点数计算:每张牌都有点数,2到10的牌的点数就是其牌面的数字;J、Q、K的点数是10分;A有两种算法,1或者11,如果A算为11时总和大于21,则A算为1。例如(A,8)是19点,(A,7,J)则为18点。

21点一般用到1-8副牌。庄家给每个玩家发两张明牌,牌面朝上面;给自己发两张牌,一张牌面朝上(叫明牌),一张牌面朝下(叫暗牌)。大家手中扑克点数的计算是:K、Q、J 和 10 牌都算作 10 点。A 牌既可算作1 点也可算作11 点。如果 A 算为 11 时总和大于 21 ,则 A 算为 1 。其余所有2 至9 牌均按其原面值计算。首先玩家开始要牌,如果玩家拿到的前两张牌是一张 A 和一张10点牌,就拥有黑杰克(Blackjack);没有黑杰克的玩家可以继续拿牌,可以随意要多少张。目的是尽量往21点靠,靠得越近越好,最好就是21点了。在要牌的过程中,如果所有的牌加起来超过21点,玩家就输了——叫爆掉(Bust),游戏也就结束了。假如玩家没爆掉,又决定不再要牌了,这时庄家就把他的那张暗牌打开来。一般到17点或17点以上不再拿牌,但也有可能15到16点甚至12到13点就不再拿牌或者18到19点继续拿牌。假如庄家爆掉了,那他就输了。假如他没爆掉,那么你就与他比点数大小,大为赢。

一、新建控制台程序DemoBlackJack。注意选择.net framework版本为4.0。

二、新建公共类 CommonUtil.cs,输入代码:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace DemoBlackJack
{
    ///


    /// 公共资源类,主要有黑杰克点数常量,52张扑克牌集合,以及计算当前玩家的点数
    ///

    public class CommonUtil
    {
        ///
        /// 最大点【极值】,21点代表黑杰克
        ///

        public const int BlackJack = 21;
        ///
        /// 定义52张牌,暂定A代表的值为11,如果玩家手上存在A,则要对A进行11或1进行处理,尽量小于等于21点
        /// 键:牌的花色点数  值:点数
        ///

        public static Dictionary Dict = new Dictionary()
        {
            //庄家dealer 玩家player
            //四种花色:♠黑桃(Spade)、♥红心(Heart)、♦方块(Diamond)、♣梅花(Club),每种花色有13种点数
            {"♠A黑桃",11},{"♠2黑桃",2},{"♠3黑桃",3},{"♠4黑桃",4},{"♠5黑桃",5},{"♠6黑桃",6},{"♠7黑桃",7},{"♠8黑桃",8},{"♠9黑桃",9},{"♠10黑桃",10},{"♠J黑桃",10},{"♠Q黑桃",10},{"♠K黑桃",10},
            {"♥A红心",11},{"♥2红心",2},{"♥3红心",3},{"♥4红心",4},{"♥5红心",5},{"♥6红心",6},{"♥7红心",7},{"♥8红心",8},{"♥9红心",9},{"♥10红心",10},{"♥J红心",10},{"♥Q红心",10},{"♥K红心",10},
            {"♣A梅花",11},{"♣2梅花",2},{"♣3梅花",3},{"♣4梅花",4},{"♣5梅花",5},{"♣6梅花",6},{"♣7梅花",7},{"♣8梅花",8},{"♣9梅花",9},{"♣10梅花",10},{"♣J梅花",10},{"♣Q梅花",10},{"♣K梅花",10},
            {"♦A方块",11},{"♦2方块",2},{"♦3方块",3},{"♦4方块",4},{"♦5方块",5},{"♦6方块",6},{"♦7方块",7},{"♦8方块",8},{"♦9方块",9},{"♦10方块",10},{"♦J方块",10},{"♦Q方块",10},{"♦K方块",10}
        };

        ///


        /// 获取玩家 或者 庄家 手上所有牌的点数
        /// 当手上的牌存在A时,需要对A进行11 或 1特殊处理【如果存在两个或以上的A,则最多只有一个A可以当做11来计算】
        ///

        ///
        ///
        public static int GetCurrentPoints(params string[] poker)
        {
            if (poker == null || poker.Length < 2)
            {
                Console.WriteLine("参与玩家至少需要有两张牌...");
                return 0;
            }
            //从集合中筛选出含有A的牌
            List listAIndex = new List();
            for (int i = 0; i < poker.Length; i++)
            {
                if (poker[i].Length < 2)
                {
                    Console.WriteLine("传入的扑克牌参数非法,请检查:{0}", poker[i]);
                    return -1;
                }
                if ('A' == poker[i][1])
                {
                    //将A所在的数组索引放入集合中
                    listAIndex.Add(i);
                }
            }

            int sum = 0;
            //如果存在A,则 按照 11 和 1 分别特殊处理,获取最接近 21点的
            if (listAIndex.Count > 0)
            {
                //如果存在两个或以上的A,则最多只有一个A可以当做11来计算【因:两个A按11计算为22点,爆点】
                //先将所有非A的进行求和
                for (int i = 0; i < poker.Length; i++)
                {
                    if (!listAIndex.Contains(i))
                    {
                        sum += Dict[poker[i]];
                    }
                }
                //此时 sum值为 所有非A的牌之和
                //sum+listAIndex.Count,21,sum+listAIndex.Count+10 三个数 进行比较,即 oneSum,elevenSum=oneSum+10,21 这三个数进行比较
                //最多只有一个A作为11进行计算,其它A按照1处理
                int elevenSum = sum + 11 + (listAIndex.Count - 1);//按照11进行计算
                int oneSum = sum + 1 + (listAIndex.Count - 1);//按照1进行计算
                if (oneSum >= BlackJack)
                {
                    //21 小于或等于 oneSum
                    return oneSum;
                }
                else if (oneSum < BlackJack && BlackJack < elevenSum)
                {
                    //21 在oneSum和 elevenSum之间
                    return oneSum;
                }
                else
                {
                    //21 大于或等于 elevenSum
                    return elevenSum;
                }
            }
            else
            {
                //如果不存在A,直接累加器求和
                for (int i = 0; i < poker.Length; i++)
                {
                    sum += Dict[poker[i]];
                }
                return sum;
            }
        }
    }
}

三、新建玩家类:Player.cs,代码如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace DemoBlackJack
{
    ///


    /// 玩家,庄家
    ///

    public class Player
    {
        ///
        /// 使用姓名和是否庄家来初始化一个玩家
        ///

        ///
        ///
        public Player(string playerName, bool isDealer = false)
        {
            PlayerName = playerName;
            IsDealer = isDealer;
            ListCard = new List();
        }
        ///
        /// 玩家姓名或ID
        ///

        public string PlayerName { get; set; }
        ///
        /// 是否是庄家 true为庄家,false为玩家
        ///

        public bool IsDealer { get; set; }
        ///
        /// 手上已有的牌
        ///

        public List ListCard { get; set; }
        ///
        /// 当前点数【由手上的扑克牌组合决定】
        ///

        public int CurrentPoint
        {
            get
            {
                if (ListCard == null)
                {
                    return 0;
                }
                return CommonUtil.GetCurrentPoints(ListCard.ToArray());
            }
        }

        ///


        /// 重写类的ToString方法,用于直接打印对象,用于Console.WriteLine(对象)
        ///

        ///
        public override string ToString()
        {
            return string.Format("{0}【{1}】--手上的牌:【{2}】,当前点数:【{3}】",
                IsDealer ? "庄家" : "玩家", PlayerName, string.Join(",", ListCard), CurrentPoint);
        }
    }
}

四、新建扑克流程逻辑类:BlackjackUtil.cs,输入代码:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace DemoBlackJack
{
    ///


    /// 黑杰克,或叫21点【扑克牌】,无大小王。 游戏者的目标是使手中的牌的点数之和不超过21点且尽量大。【小于等于21】
    /// 算法如下:2,3,4,5,6,7,8,9,10分别代表各自原来的点数
    /// A(Ace 一流)代表11或者1,J(Jack 贵族,骑士,侍卫),Q(Queen 王后),K(King 国王)代表10。A牌(Ace)根据需要选择数字11或者数字1,确保点数之和 【小于等于21】 即可
    /// 玩家手上的所有牌之和为21为黑杰克【无敌】,超过21(大于等于22)则为爆点【输掉】
    /// 如A+4+8:如果A为11,则总和为23点,爆掉,如果A为1,则为13点,因此 A+4+8=13
    /// 如A+K+10,则为21点,黑杰克。 A+J 也是黑杰克=21
    /// 如A+5+A=17点,A+A=12点
    ///

    public class BlackjackUtil
    {        
        ///
        /// 已选中的扑克牌所在的索引集合,已随机到的扑克牌,下次不能随机到
        ///

        private static List listSelect = new List();
        ///
        /// 庄家
        ///

        private static Player dealer = null;
        ///
        /// 玩家
        ///

        private static Player player = null;
        ///
        /// 开始21点游戏【黑杰克】
        ///

        public static void StartPlay()
        {
            Init();
            //开始时 庄家、玩家都发两张牌
            Console.WriteLine("庄家随机发两张扑克牌...");
            DealCard(dealer);
            DealCard(dealer);
            Console.WriteLine(dealer);

            Console.WriteLine();
            Console.WriteLine("玩家随机获取两张扑克牌...");
            DealCard(player);
            DealCard(player);
            Console.WriteLine(player);

            while (true)
            {
                Console.WriteLine();
                Console.WriteLine("庄家选择:继续要牌(Y),不要牌(N),开牌(R或其他字符)...");
                string input = Console.ReadLine();
                if ("Y".Equals(input, StringComparison.CurrentCultureIgnoreCase))
                {
                    bool isContinue = DealCard(dealer);
                    if (!isContinue)
                    {
                        Console.WriteLine(dealer);
                        Console.WriteLine(player);
                        JudgeResult();
                        break;
                    }
                }
                else if ("N".Equals(input, StringComparison.CurrentCultureIgnoreCase))
                {
                    //不要牌
                }
                else
                {
                    //直接开牌,结束
                    Console.WriteLine(dealer);
                    Console.WriteLine(player);
                    JudgeResult();
                    break;
                }

                Console.WriteLine();
                Console.WriteLine("玩家选择:继续要牌(Y),不要牌(N),开牌(R或其他字符)...");
                input = Console.ReadLine();
                if ("Y".Equals(input, StringComparison.CurrentCultureIgnoreCase))
                {
                    bool isContinue = DealCard(player);
                    if (!isContinue)
                    {
                        Console.WriteLine(dealer);
                        Console.WriteLine(player);
                        JudgeResult();
                        break;
                    }
                }
                else if ("N".Equals(input, StringComparison.CurrentCultureIgnoreCase))
                {
                    //不要牌
                }
                else
                {
                    //直接开牌,结束
                    Console.WriteLine(dealer);
                    Console.WriteLine(player);
                    JudgeResult();
                    break;
                }

                Console.WriteLine();
                Console.WriteLine("此时,系统双方点数情况...");
                Console.WriteLine(dealer);
                Console.WriteLine(player);
            }
        }

        ///


        /// 判定结果:根据双方当前点数进行判定,如果 点数一致 或者 同时爆点(大于21) 则和局,否则进行输赢判定
        /// 庄家有【小于21、等于21、大于21】三种可能,玩家也有【小于21、等于21、大于21】三种可能。因此共用九种判定
        /// 该逻辑也可简化判定为【点数一致、庄家黑杰克、玩家黑杰克、庄家玩家都小于黑杰克、庄家玩家都大于黑杰克、庄家小于黑杰克 且 玩家大于黑杰克、庄家大于黑杰克 且 玩家小于黑杰克】
        ///

        public static void JudgeResult()
        {
            if (dealer.CurrentPoint == player.CurrentPoint)
            {
                Console.WriteLine("和局!庄家和玩家点数一样:{0}{1}", dealer.CurrentPoint, dealer.CurrentPoint == CommonUtil.BlackJack ? "【黑杰克】" : "");
                return;
            }
            if (dealer.CurrentPoint < CommonUtil.BlackJack && player.CurrentPoint < CommonUtil.BlackJack)
            {
                Console.WriteLine("{0}!庄家点数:{1},玩家点数:{2}", dealer.CurrentPoint > player.CurrentPoint ? "庄家胜利" : "玩家胜利", dealer.CurrentPoint, player.CurrentPoint);
            }
            else if (dealer.CurrentPoint < CommonUtil.BlackJack && player.CurrentPoint == CommonUtil.BlackJack)
            {
                Console.WriteLine("{0}!庄家点数:{1},玩家点数:{2}", "玩家胜利【黑杰克】", dealer.CurrentPoint, player.CurrentPoint);
            }
            else if (dealer.CurrentPoint < CommonUtil.BlackJack && player.CurrentPoint > CommonUtil.BlackJack)
            {
                Console.WriteLine("{0}!庄家点数:{1},玩家点数:{2}", "庄家胜利【玩家爆点】", dealer.CurrentPoint, player.CurrentPoint);
            }

            else if (dealer.CurrentPoint == CommonUtil.BlackJack && player.CurrentPoint < CommonUtil.BlackJack)
            {
                Console.WriteLine("{0}!庄家点数:{1},玩家点数:{2}", "庄家胜利【黑杰克】", dealer.CurrentPoint, player.CurrentPoint);
            }
            //else if (dealer.CurrentPoint == CommonUtil.BlackJack && player.CurrentPoint == CommonUtil.BlackJack)
            //{
            //}
            else if (dealer.CurrentPoint == CommonUtil.BlackJack && player.CurrentPoint > CommonUtil.BlackJack)
            {
                Console.WriteLine("{0}!庄家点数:{1},玩家点数:{2}", "庄家胜利【黑杰克】", dealer.CurrentPoint, player.CurrentPoint);
            }

            else if (dealer.CurrentPoint > CommonUtil.BlackJack && player.CurrentPoint < CommonUtil.BlackJack)
            {
                Console.WriteLine("{0}!庄家点数:{1},玩家点数:{2}", "玩家胜利【庄家爆点】", dealer.CurrentPoint, player.CurrentPoint);
            }
            else if (dealer.CurrentPoint > CommonUtil.BlackJack && player.CurrentPoint == CommonUtil.BlackJack)
            {
                Console.WriteLine("{0}!庄家点数:{1},玩家点数:{2}", "玩家胜利【黑杰克】", dealer.CurrentPoint, player.CurrentPoint);
            }
            else //if (dealer.CurrentPoint > BlackJack && player.CurrentPoint > BlackJack)
            {
                Console.WriteLine("{0}!庄家点数:{1},玩家点数:{2}", "和局【庄家和玩家都已爆点】", dealer.CurrentPoint, player.CurrentPoint);
            }
        }

        ///


        /// 发一张牌,当超过11张牌时,强行结束
        /// 假设一个人最多拥有11张牌:2+2+2+2+3+3+3+A+A+A+A=21
        ///

        ///
        ///
        public static bool DealCard(Player p)
        {
            int selectedIndex = GetRandomPokerIndex();
            p.ListCard.Add(CommonUtil.Dict.ElementAt(selectedIndex).Key);
            if (p.ListCard.Count >= 11)
            {
                Console.WriteLine("已有牌已超过11张,强行结束,开牌计算...");
                return false;
            }
            return true;
        }

        ///


        /// 获得一张扑克牌索引,发牌一张
        ///

        ///
        public static int GetRandomPokerIndex()
        {
            //注意:共52张牌,因此随机数索引为[0,51]
            int index = new Random(Guid.NewGuid().GetHashCode()).Next(0, 52);
            //如果在集合中存在该索引,则重新随机一张牌
            while (listSelect.Contains(index))
            {
                index = new Random(Guid.NewGuid().GetHashCode()).Next(0, 52);
            }
            listSelect.Add(index);
            return index;
        }

        ///


        /// 初始化重新开始
        ///

        public static void Init()
        {
            dealer = new Player("张三", true);
            player = new Player("李四", false);
            listSelect.Clear();
        }        
    }
}


五、在默认的Program.cs 输入测试代码:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace DemoBlackJack
{
    class Program
    {
        static void Main(string[] args)
        {
            string input;
            do
            {
                BlackjackUtil.StartPlay();
                Console.WriteLine("游戏已结束,是否继续游戏(继续:Y,结束:N)...");
                input = Console.ReadLine();
            } while ("Y".Equals(input, StringComparison.CurrentCultureIgnoreCase));
            Console.ReadLine();
        }
    }
}


六、程序运行截图:

C#黑杰克(21点)扑克小游戏_第1张图片

你可能感兴趣的:(C#,21点,黑杰克,二十一点)