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
{
    /// <summary>
    /// 公共资源类,主要有黑杰克点数常量,52张扑克牌集合,以及计算当前玩家的点数
    /// </summary>
    public class CommonUtil
    {
        /// <summary>
        /// 最大点【极值】,21点代表黑杰克
        /// </summary>
        public const int BlackJack = 21;
        /// <summary>
        /// 定义52张牌,暂定A代表的值为11,如果玩家手上存在A,则要对A进行11或1进行处理,尽量小于等于21点
        /// 键:牌的花色点数  值:点数
        /// </summary>
        public static Dictionary<string, int> Dict = new Dictionary<string, int>()
        {
            //庄家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}
        };

        /// <summary>
        /// 获取玩家 或者 庄家 手上所有牌的点数
        /// 当手上的牌存在A时,需要对A进行11 或 1特殊处理【如果存在两个或以上的A,则最多只有一个A可以当做11来计算】
        /// </summary>
        /// <param name="poker"></param>
        /// <returns></returns>
        public static int GetCurrentPoints(params string[] poker)
        {
            if (poker == null || poker.Length < 2)
            {
                Console.WriteLine("参与玩家至少需要有两张牌...");
                return 0;
            }
            //从集合中筛选出含有A的牌
            List<int> listAIndex = new List<int>();
            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
{
    /// <summary>
    /// 玩家,庄家
    /// </summary>
    public class Player
    {
        /// <summary>
        /// 使用姓名和是否庄家来初始化一个玩家
        /// </summary>
        /// <param name="playerName"></param>
        /// <param name="isDealer"></param>
        public Player(string playerName, bool isDealer = false)
        {
            PlayerName = playerName;
            IsDealer = isDealer;
            ListCard = new List<string>();
        }
        /// <summary>
        /// 玩家姓名或ID
        /// </summary>
        public string PlayerName { get; set; }
        /// <summary>
        /// 是否是庄家 true为庄家,false为玩家
        /// </summary>
        public bool IsDealer { get; set; }
        /// <summary>
        /// 手上已有的牌
        /// </summary>
        public List<string> ListCard { get; set; }
        /// <summary>
        /// 当前点数【由手上的扑克牌组合决定】
        /// </summary>
        public int CurrentPoint
        {
            get
            {
                if (ListCard == null)
                {
                    return 0;
                }
                return CommonUtil.GetCurrentPoints(ListCard.ToArray());
            }
        }

        /// <summary>
        /// 重写类的ToString方法,用于直接打印对象,用于Console.WriteLine(对象)
        /// </summary>
        /// <returns></returns>
        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
{
    /// <summary>
    /// 黑杰克,或叫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点
    /// </summary>
    public class BlackjackUtil
    {        
        /// <summary>
        /// 已选中的扑克牌所在的索引集合,已随机到的扑克牌,下次不能随机到
        /// </summary>
        private static List<int> listSelect = new List<int>();
        /// <summary>
        /// 庄家
        /// </summary>
        private static Player dealer = null;
        /// <summary>
        /// 玩家
        /// </summary>
        private static Player player = null;
        /// <summary>
        /// 开始21点游戏【黑杰克】
        /// </summary>
        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);
            }
        }

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

        /// <summary>
        /// 发一张牌,当超过11张牌时,强行结束
        /// 假设一个人最多拥有11张牌:2+2+2+2+3+3+3+A+A+A+A=21
        /// </summary>
        /// <param name="p"></param>
        /// <returns></returns>
        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;
        }

        /// <summary>
        /// 获得一张扑克牌索引,发牌一张
        /// </summary>
        /// <returns></returns>
        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;
        }

        /// <summary>
        /// 初始化重新开始
        /// </summary>
        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();
        }
    }
}


六、程序运行截图:

  • 1
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
好的,我来为您解答。 21游戏,也叫黑杰克,是一种非常经典的纸牌游戏。玩家需要通过抽牌的方式,让自己的牌数尽量接近21,但不能超过21。其中,A牌可以看成1或11,J、Q、K牌都算10,其他牌按照牌面数算。下面是用Java写的21小游戏代码: ```java import java.util.Scanner; public class BlackJack { public static void main(String[] args) { Scanner input = new Scanner(System.in); int playerScore = 0; // 玩家得分 int dealerScore = 0; // 庄家得分 // 初始状态,玩家和庄家各发两张牌 for (int i = 0; i < 2; i++) { playerScore += drawCard(); dealerScore += drawCard(); } // 玩家开始抽牌 while (true) { System.out.println("你的得分是:" + playerScore); // 判断是否爆掉 if (playerScore > 21) { System.out.println("你爆了,游戏结束!"); break; } // 询问玩家是否继续抽牌 System.out.print("是否抽牌?(Y/N) "); String choice = input.nextLine(); if (choice.equalsIgnoreCase("Y")) { playerScore += drawCard(); } else if (choice.equalsIgnoreCase("N")) { break; } } // 庄家开始抽牌 while (dealerScore < 17) { System.out.println("庄家得分是:" + dealerScore); dealerScore += drawCard(); } // 判断输赢 if (dealerScore > 21) { System.out.println("庄家爆了,你赢了!"); } else if (playerScore > dealerScore) { System.out.println("你的得分是:" + playerScore); System.out.println("庄家的得分是:" + dealerScore); System.out.println("你赢了!"); } else if (playerScore == dealerScore) { System.out.println("你的得分是:" + playerScore); System.out.println("庄家的得分是:" + dealerScore); System.out.println("平局!"); } else { System.out.println("你的得分是:" + playerScore); System.out.println("庄家的得分是:" + dealerScore); System.out.println("你输了!"); } } // 抽一张牌,返回牌的数 public static int drawCard() { int[] cards = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 10, 10, 10}; int index = (int) (Math.random() * cards.length); return cards[index]; } } ``` 这个程序主要分为以下几个部分: 1.引入Scanner类,用于接收用户输入。 2.定义玩家得分和庄家得分的变量。 3.循环两次,让玩家和庄家各发两张牌,用drawCard()函数随机生成牌的数,并将数加到对应的得分变量中。 4.玩家开始抽牌,使用while循环实现。在循环中,先输出当前得分,然后判断是否爆掉。如果爆掉了,输出游戏结束,并跳出循环;否则提示玩家是否继续抽牌,如果选择抽牌,则继续调用drawCard()函数生成新牌的数,并加到玩家得分变量中;如果选择不抽牌,则跳出循环。 5.庄家开始抽牌,同样使用while循环实现。在循环中,先输出当前得分,然后判断是否小于17,如果小于17,则继续调用drawCard()函数生成新牌的数,并加到庄家得分变量中。 6.判断输赢。如果庄家的得分大于21,则玩家赢;如果玩家的得分大于庄家的得分,则玩家赢;如果两者得分相等,则平局;否则玩家输。 7.drawCard()函数,用于随机生成一张牌,返回该牌的数。 希望这个解答能够帮到您!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

斯内科

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值