本文为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();
        }
    }
}

六、程序运行截图:

C#黑杰克(21点)扑克小游戏相关推荐

  1. 用php开发扑克小游戏网页版,开发日记:KBEngine+Unity+php做个扑克小游戏(一)

    下面给大家介绍的是使用KBEngine+Unity+php做的一个扑克小游戏,php 部分和unity 部分有经验的开发人员都能看明白 ,但对于KBEngine(简称kbe)可能有些人没接触过,但其实 ...

  2. 【基于Java+Swing的“21点扑克牌小游戏”的设计与实现(效果+源代码)】

    目录 效果 源代码示例 说明 效果 下面是游戏运行的部分效果,我玩儿的菜哈,见谅~

  3. 【纯干货】用Python写30种小游戏给男朋友玩,谈恋爱我是认真的

    目录 1.21点数字小游戏展示: 2.保卫森林大作战啦啦 3.超级大的迷宫 总结 正在学Python中的我,自我感觉学的还不错的亚子~想做点什么来练练手,然后我疯狂的找各种小游戏的教程源码什么的,于是 ...

  4. 21点 小游戏 java代码_基于Java的21点扑克游戏的实现

    在上次写的比较牌点的扑克游戏上Java扑克游戏(多人多牌数比较游戏)的实现中,添加21点游戏规则,实现21点牌类游戏.具体实现步骤如下:[需要源代码的留QQ,大家一起探讨探讨哈,谢谢啦!] 抽象出规则 ...

  5. 《魔兽世界插件》教程---21点扑克游戏 Blackjack

    1.效果图 因为我是新手,只能做一个非常简单的插件,21点扑克游戏.比较有趣吧,插件也可以做一个游戏?游戏中的游戏! 2.编写魔兽世界插件准备 首先你要一个最新的魔兽世界客户端,我的有26G大小.记得 ...

  6. 黑杰克blackjack 游戏的简化版(第一个游戏程序)

    学完了python的基础篇,大概很多东西都是可以做了,不过一般来说第一个项目都是飞机大战,由于之前学习C 的时候也做过飞机大战,于是我想尝试一下别的项目,就从最简单的黑杰克开始执行吧.感觉德州扑克和黑 ...

  7. 《魔兽世界插件》教程—21点扑克游戏 Blackjack

    1.效果图 因为我是新手,只能做一个非常简单的插件,21点扑克游戏.比较有趣吧,插件也可以做一个游戏?游戏中的游戏! 2.编写魔兽世界插件准备 首先你要一个最新的魔兽世界客户端,我的有26G大小.记得 ...

  8. 游戏开发攻略—黑杰克扑克牌

    欢迎来到:http://observer.blog.51cto.com 21点黑杰克扑克牌为一款极具趣味性的牌类游戏,最早出现在十六世纪,起源于法国.同时,发现在网络上流传着的各种版本的21点黑杰克扑 ...

  9. C语言实现扫雷小游戏 纯小白 非黑窗口

    C语言实现一个普通的扫雷小游戏 纯小白所编(含代码非黑窗口!) 扫雷 主要功能 1.创建一个图形界面 2.了解扫雷游戏的原理 3.随机生成雷的位置 4.为整个数组加密,并在雷周围的位置加一 5.导入图 ...

最新文章

  1. Linux下Tomcat与Apache Web服务器的整合
  2. dataloader 源码_pytorch :: Dataloader中的迭代器和生成器应用
  3. gitlab介绍、安装及gitlab CI、与jenkins的对比
  4. 什么是alpha测试_什么是ALPHA?
  5. 软件外包项目管理3点体会
  6. 为什么把钱花在别人身上更幸福?
  7. NYNU_省赛选拔题(10)
  8. SimpleDateFormat 线程不安全及解决方案
  9. 使用element-ui中的container布局容器
  10. 【论文阅读】xgboost
  11. 从Intel 80386讲讲操作系统的内存管理机制
  12. 如何软著办理,软著申请步骤,软著办理流程
  13. 【C语言】||(或) (且)
  14. 求最长递增子序列个数——C++
  15. 车管所服务器维护还能考科目四吗,车管所可以预约科目四吗
  16. html初学者对相对地址,绝对地址的理解
  17. 基于C语言编写的超市管理系统
  18. 六款好用的视频编辑软件推荐
  19. mxnet dropout 层阅读和测试
  20. C++练习11:计算a+aa+aaa+aa…a+…

热门文章

  1. JavaScript基本运算符
  2. 信息论的产生与发展概况
  3. 三星s7android7,三星S7刷安卓7.0后,传承了Note7的一个卖点
  4. AI设计彭罗斯悖论三角教程
  5. Hyperledger Fabric 超级账本实战项目(一、二)
  6. 如何获取标准网络服务的端口号,协议名等
  7. linux下查看pid namespace的方法
  8. 显示器屏幕偏色原因及解决方案
  9. Android 下拉刷新上拉加载 多种应用场景 超级大放送(上)
  10. Java中enum的使用