2019独角兽企业重金招聘Python工程师标准>>>

最近无聊,想知道一下玩斗地主的话我能有多大的概率拿到炸弹(4张同点数牌 或 集齐大小王)。但是我概率学学得不好,于是想到用统计学来试试,随手写了一个程序模拟一下斗地主的发牌过程

面向对象Card

首先依据OOP思想,我把牌看作是一个对象,点数与花色是其属性,为了处理大小王加入了Type属性

public class Card {Suit suit;Size size;Type type;Card(Suit suit, Size size) {this.suit = suit;this.size = size;this.type = Type.Ordinary;}Card(Type type) {if (type.equals(Type.Ordinary)) {throw new RuntimeException("非法参数");}this.type = type;}
}

三个属性我都用了枚举类来表示,纯粹是因为既然是面向对象,那么就纯粹一点

public enum Size {P3(0), P4(1), P5(2), P6(3), P7(4), P8(5), P9(6),P10(7), J(8), Q(9), K(10), A(11), P2(12);int sequence;Size(int sequence) {this.sequence =  sequence;}
}

Size表示点数的大小,按从小到大排序。加入sequence属性目的是为了在统计时方便处理

public enum Suit {Spade(4), Heart(3), Club(2), Diamond(1);// 权重int weight;Suit(int weight) {this.weight = weight;}
}

Suit花色,加入了weight属性作为大小权重,斗地主花色不分大小,不过有些牌会区分,所以随手加一下

public enum Type {Ordinary(0), LITTLE_JOKER(1), BIG_JOKER(2);int weight;Type(int weight) {this.weight = weight;}
}

Type牌类型,主要是为了特殊处理大小王,根据权重值,小王比大王小~

计算过程

首先抽象一下玩牌的几个步骤,第一步:拿出一副牌;第二步:洗牌(随机打乱);第三步:发牌;第四步:Play(计算是否有炸弹);我简化了发牌方法,放进主程序中,其他步骤具体实现如下

/*** 生成一套有序牌数组*/static Card[] newCards() {// 牌组用数组表示Card[] cards = new Card[54];// 游标iint i = 0;// 循环放牌 13种大小 * 4种花色 = 52for (Size point : Size.values()) {for (Suit suit : Suit.values()) {cards[i++] = new Card(suit, point);}}// 插入大小王cards[52] = new Card(Type.LITTLE_JOKER);cards[53] = new Card(Type.BIG_JOKER);return cards;}/*** 洗牌* @param cards 打乱的牌组*/static Card[] shuffle(Card[] cards) {Random random = new Random();int len = cards.length;// 复杂的 O(n)// 遍历一副牌,每次循环随机取一张当前牌后面的一张牌(含当前牌)与当前牌交换// 在完全随机的情况下,每张牌在每个位置的概率应该一致,共有 n! 种情况for (int i = 0;i < len; i++) {int r = random.nextInt(len - i);change(i, r + i, cards);}return cards;}// 简单的交互位置方法static void change(int a, int b, Card[] cards) {Card temp = cards[a];cards[a] = cards[b];cards[b] = temp;}static final int DOUBLE_JOKER = 3;static final int FULL_SUIT = 10;/*** 判断是否有炸弹* @param cards 牌组* @return true 有炸弹 false 无炸弹*/static boolean hasBoom(Card[] cards) {// 构造一个与Size数量等长的初始为0的数组int[] counter = new int[Size.values().length]; //初始化为0// 特殊处理大小王int weightOfJoker = 0;for (Card card: cards) {// 特殊处理大小王if (!card.type.equals(Type.Ordinary)) {weightOfJoker += card.type.weight;// 大小王权重和为3时即王炸if (weightOfJoker == DOUBLE_JOKER) {return true;}continue;}// 利用点数序列值为下标,加上权重值,和为10时即凑足4张牌counter[card.size.sequence] += card.suit.weight;if (counter[card.size.sequence] == FULL_SUIT) {return true;}}return false;}

游戏主方法,来算算地主和农民各有多少概率吧

public static void main(String[] args) {long gameStart = System.currentTimeMillis();int gameTime = 100000;// 农民17张牌计数器int nongHasBoom = 0;// 地主20张牌计数器int diHasBoom = 0;// 运行游戏for (int i = 0;i < gameTime; i++) {// 拿到一副新牌Card[] poker = newCards();// 洗牌poker = shuffle(poker);// 发牌 在随机的情况下,连续发和分开发理论上不影响你拿牌的概率,简化Card[] nong = Arrays.copyOf(poker, 17);Card[] di = Arrays.copyOfRange(poker, 17, 17 + 20);nongHasBoom += hasBoom(nong)? 1 : 0;diHasBoom += hasBoom(di)? 1 : 0;}long gameEnd = System.currentTimeMillis();System.out.println(String.format("地主炸弹概率 %f , 农民炸弹概率 %f", diHasBoom * 1.0 / gameTime, nongHasBoom * 0.1 / gameTime));System.out.println(String.format("运行时 %f s", (gameEnd - gameStart)/1000.0));}

运行一次程序,发现运行速度还挺快,反正10万次不足半秒,运行才发现,地主三张牌对拿炸弹的概率影响竟然这么大,可以提升将近一倍的概率。当然程序是我随便写的,可能存在不严谨导致数据错误的地方,如果发现还请斧正。其次在枚举类的书写规范上,我偷了一些懒,没有全部大写~

地主炸弹概率 0.302310 , 农民炸弹概率 0.186460
运行时 0.217000 s

转载于:https://my.oschina.net/u/3491123/blog/1621647

你的斗地主能拿多少炸?相关推荐

  1. java斗地主游戏开发 算法思路讲解

    上学期刚开学的时候我特别沉迷于斗地主 充了6块钱赢了30万豆 然后一夜之间破产 越想越气 然后我就有一个大胆的想法开发一个斗地主现在这个斗地主能在控制台上运行 本文主要讲解我在开发斗地主时研究的算法思 ...

  2. 时间类及数组,集合 7-14

    1.设计一个敏感词过滤程序     WordFilter类         属性:数组类型[]存放敏感词 设计一个方法,调用这个方法(传参,可能会包含敏感词的字符串),返回过滤后的新的字符串      ...

  3. 机器学习、计算机视觉面经整理(持续完善整理中……)

    算法岗计算机视觉方向求职经验总结 进入11月份,楼主找工作也基本进入尾声了,从7月份开始关注牛客网,在求职的过程中学到了不少,感谢牛客提供这样一个平台,让自己的求职历程不再孤单. 先说一下楼主教育背景 ...

  4. 对于斗地主自己视角断王,且出现王炸概率的分析

    一副扑克牌(54张)出现王炸的概率根据其他人计算为32.29%,但是我们往往感觉概率比这个数字大得多,这是因为出现这个感觉的前提是自己的视角还断王.所以,分析一下如果叫分之后,自己手上断王且外面出现王 ...

  5. 用命令行在控制台里玩斗地主,试过没?

    点击蓝色"程序猿DD"关注我 回复"资源"获取独家整理的学习资料! 来源:http://1t.click/4z8 这是什么? 这是Ratel,它可以在命令行内进 ...

  6. hdu4930 模拟斗地主

    题意:        模拟斗地主,出牌有一下规则,1张,1对,3张,3带1,3带2,炸弹(包括两个猫),4带2,这写规则,没有其他的,然后给你两幅牌,只要第一个人出了一次牌对方管不上,那么或者第一个人 ...

  7. 玩斗地主明白的7个道理

    玩斗地主后明白的7个道理 1.没有一张大牌开路再顺的小牌都出不去,说明领导很重要. 2.小王一出基本都会被大王打,说明老大在老二最好不要发话. 3.无论你多会记牌都抵不过人家手中一副好牌,说明实力更重 ...

  8. jdk解压版_命令行版的斗地主你玩过没?

    相信大家都玩过斗地主游戏,或在现实中斗地主或在电脑和手机上斗地主,但你想过用命令行界面进行斗地主吗? 先来张图体验一下: 是不是觉得挺有意思,下面就带大家一起玩一下吧~部署命令行版斗地主 1 环境准备 ...

  9. 斗地主AI算法——第十六章の样例分析

    上一章,我们已经完成了测试模块的开发.至此我们已经可以进行整体测试了.本章主要内容就是对随机生成的对局情况进行简单的分析. 实际上整个开发过程绝大部分时间都是用在样例分析上,通过样例给出的返回操作分析 ...

最新文章

  1. 智能车竞赛中视觉AI组别的打把问题
  2. 人的一生为什么要努力 1
  3. 管理员必备的Linux系统监控工具
  4. win10无法装载重装系统iso文件_windows10系统如何安装iso镜像文件
  5. lisp6 暖通cad_(完整版)暖通CAD设计技巧1
  6. Java Throwable initCause()方法与示例
  7. C++11新特性探索:原始字符串字面值(raw string literal)
  8. Python培训的基础知识
  9. dataframe在最下面新增一行
  10. 真正优秀的人,都有这3种习惯
  11. 【通过操作指针,与指针做函数參数#39;实现字串在主串中出现的次数,然后将出现的部分依照要求进行替换 】...
  12. Spark utils —— 设置日志级别
  13. 自学python能干些什么副业-用Python赚钱的5个方法,教你业余时间赚外快!
  14. Moss 2007 升级到 Moss2010 成功但界面仍然保持07?
  15. android绑定服务空指针,android aidl问题空指针的问题
  16. 商业分析方法与工具总结
  17. Win7纯净版系统Windows未能启动,文件Winload.exe的解决方法
  18. RTX2.02 tiny中文手册
  19. 魔兽顶级装备如何打造各个职业最强装备包括宝石和全身附魔
  20. 怎样修改一篇简历 简历怎么写

热门文章

  1. Android中的防缓冲区溢出技术
  2. Hanoi塔(分治法的应用)
  3. SpringIOC注解的学习笔记(一)
  4. SQL Server 2005 查询处理器未能为执行并行查询启动必要的线程资源。
  5. WPF xaml中列表依赖属性的定义
  6. Registry Release Traces 版本功能迭代和 issue bugfix
  7. Flask之WTForms验证
  8. Mysql性能优化二
  9. 一个硬中断的完整处理过程【转】
  10. Java实现SSH模式加密