【java-集合 阶段小结】模拟斗地主洗牌发牌
内容导读
互联网集市收集整理的这篇技术教程文章主要介绍了【java-集合 阶段小结】模拟斗地主洗牌发牌,小编现在分享给大家,供广大互联网技能从业者学习和参考。文章包含4512字,纯文字阅读大概需要7分钟。
内容图文
之前在家里和妈妈姐姐一起玩了斗地主,玩的时候我妈突然问我“欢乐斗地主是怎么洗牌发牌的?”那个时候还不知道怎么解决,最近正好学完了集合,觉得里面有很多东西可以利用一下,就把这个过了大半年的问题翻出来解决一下
1.思路分析
思来想去这个案例的难点就难在洗牌上面,如果使用Random生成随机数来实现乱序,也可以实现这个案例,但是有没有更简便的方法呢。于是我向度娘发起了提问,然后得到了这样一个答案:
然后我在向帮助文档寻求帮助的时候又让我发现一个好东西:
只能说是瞌睡来了送枕头的程度。
2.生成一副牌并装进“牌盒”
上面可以看到这个方法的形参是List类型,点开这个形参List后我看到了两个熟悉的身影:
这不等价于已经给了我答案了嘛,说干就干!
ArrayList<String> box = new ArrayList<String>(); //把牌装进去 String[] colors = {"?", "?", "?", "?"}; String[] nums = {"2", "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K", "A"}; for (int i = 0; i < colors.length; ++i) { for (int j = 0; j < nums.length; ++j) { box.add(colors[i] + nums[j]); } } box.add("JOKER"); box.add("joker"); //输出看看效果for(String card:box){ System.out.print(card); }
实现效果如下:
效果还不错,但是因为用的是增强for进行遍历,不能控制换行看起来有点长,但是效果是对的
3.洗牌,打乱顺序
用刚刚说的shuffle方法进行打乱顺序试试看:
// 因为是静态方法所以直接使用方法名进行调用即可 Collections.shuffle(box); // 还是输出看看效果 for (String card:box){ System.out.print(card); }
实现效果如下:
可以看到在调用了shuffle方法之后顺序已经变了
4.发牌,一人一张
想要斗地主至少要有三个玩家,再者就是玩家拿到牌之后会存起来不是一次性的,所以要有一个地方用来存储玩家的牌,还是一脉相承的使用ArrayList来生成玩家的牌的序列吧:
// 生成玩家,hole是底牌(3张) ArrayList<String> player1 = new ArrayList<String>(); ArrayList<String> player2 = new ArrayList<String>(); ArrayList<String> player3 = new ArrayList<String>(); ArrayList<String> hole = new ArrayList<String>();
有了玩家现在来思考发牌的时候有什么讲究没有,想了一圈之后总结出两点:1.每人一张,轮着来 2.最后三张是底牌,没有抢地主之前不能翻,自然也就要留下来。
留底牌的操作很简单,当已经发出去box.size()-3张牌的时候就停止发牌,剩下的牌全部存到hole中作为底牌。
for (int i = 0; i < box.size(); ++i) { String card = box.get(i); if (i >= box.size() - 3) {//剩三张牌是底牌 hole.add(card); } }
这里有一个小难点就是怎么做到轮流发牌,用图表说明就是以下这样:
现在来找规律:可以看到玩家那一排是三个一循环,所以不难想到把索引为3的倍数的牌发给玩家三,索引为2的倍数的牌发给玩家2,索引为1的倍数的牌发给玩家一。但是这个办法肯定是行不通的,比如索引为6的牌既是3的倍数也是2的倍数又是1的倍数。那么顺着倍数的思路发散会发现%是个好东西,0%3==0,1%3==1,2%3==2,3%3==0,4%3==1,5%3==2 ...,所以最后用对3取余的操作来判断发牌发给谁。
for (int i = 0; i < box.size(); ++i) { String card = box.get(i); if (i >= box.size() - 3) { hole.add(card);//循环还在继续,最后三张牌会循环存入hole } else {//用余数来判断轮到谁拿牌if (i % 3 == 0) { player3.add(card); } elseif (i % 3 == 1) { player2.add(card); } elseif (i % 3 == 2) { player1.add(card); } } }
现在主体需求基本结束了,来看看最后大家拿到的牌都是什么:
// 每个玩家看牌时都会用到,所以单独提出一个方法 public static void check(String name,ArrayList<String> arr) { System.out.print(name+"‘s cards: "); for(String s : arr){ System.out.print(s+" "); } System.out.println(); } check("haystack",player1); check("bed",player2); check("boat",player3); System.out.print("the hole cards is:"+hole);
调用结果如下:
当然,每次运行调用结果肯定是不一样的。
5.改进升级
上面其实已经实现了洗牌发牌的功能了,但是也能看到结果输出是无序的,看起来很难受,如果能把拿到手的牌排好序再输出就好了。
既然有了想法,那就再进行一次分析吧。
要想遍历结果是有序的,也就是说在输出前要做好有序化,那么就要考虑两个问题:
1.洗牌之后所有的牌是无序的怎么在拿到各个玩家手里之后有序化
2.大小顺序由什么来定?
在集合的学习中总结的集合层级结构
在学集合的时候好像看到过TreeSet是有序的集合结构,所以我想到帮助文档中求证一下
其中TreeSet在帮助文档中的介绍是这样的:
这里提到元件的排序方法由构造方法决定,TreeSet的构造方法中,无参构造方法的描述中也提到了自然排序(natural ording)
那么上面提到的natural ording又是什么呢?继续点击跟进会发现跳转到了Comparable接口的界面:
也就是说TreeSet的无参构造方法会自动将元素按照自然排序的顺序进行整理。那么每个玩家都给一个TreeSet进行保存手里牌好了:
TreeSet<Integer> player1 = new TreeSet<Integer>(); TreeSet<Integer> player2 = new TreeSet<Integer>(); TreeSet<Integer> player3 = new TreeSet<Integer>(); TreeSet<Integer> hole = new TreeSet<Integer>();//底牌
TreeSet是按照自然顺序对元素进行排序,但是扑克牌的顺序并不是单纯地自然排序。
我最初想到的是Collections的sort方法,因为在初始版本的时候瞟过一眼有点印象
但是具体描述长这样:
也就说说如果我要用这个方法,我就要自己定义一个比较器,也不是说不行,就是想有没有更简单的方法呢。
所以最后还是要从TreeSet下手,自然排序指的是如果元素的值是1,2,3...10,11,12或者a,b,c...x,y,z,那么就会按照升序排列
但是扑克牌会先有一个特殊字符,再来才是数字。
那么怎么把扑克牌的序列内容和自然数字或字母联系在一起呢?
这里我能想到的最简单办法的就是索引,但是洗牌的时候只会打乱扑克牌但是不会打乱索引
虽然索引是按照自然排序排列的但是牌已经被打乱了,洗牌过后的索引对应的就是无序的牌,此时发牌给玩家就是初级版本里面的效果:
那么如果单独打乱索引呢?
如果需要单独洗索引,就要把索引单独拿出来放到ArrayList中单独操作。
// 单独创建一个List保存索引,这样不会影响到box中的索引和牌的顺序 ArrayList<Integer> indexs = new ArrayList<Integer>(); for (int i = 0; i < 54; ++i) { indexs.add(i); } Collections.shuffle(indexs);
这个时候玩家拿到手的无序索引在经过TreeSet排序后,再按照对应的索引去原来的box中找到对应的牌
说到一对一还有谁能比键值对更合适吗?所以这里就用键值对来实现索引和牌的对应
HashMap<Integer, String> box = new HashMap<Integer, String>(); String[] colors = {"?", "?", "?", "?"}; String[] nums = {"3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K", "A", "2"}; Integer order = 0; for (int i = 0; i < nums.length; ++i) { for (int j = 0; j < colors.length; ++j) { box.put(order, colors[j] + nums[i]); order++; } } box.put(53, "joker"); box.put(52, "JOKER");
到这里思路大概清晰了,那下面看一下运行效果吧。
check("haystack",player1,box); check("sheep",player2,box); check("cloud",player3,box);
运行结果如下:
?
?
是我想要的结果!
总结:帮助文档yyds
原文:https://www.cnblogs.com/haystack/p/15202258.html
内容总结
以上是互联网集市为您收集整理的【java-集合 阶段小结】模拟斗地主洗牌发牌全部内容,希望文章能够帮你解决【java-集合 阶段小结】模拟斗地主洗牌发牌所遇到的程序开发问题。 如果觉得互联网集市技术教程内容还不错,欢迎将互联网集市网站推荐给程序员好友。
内容备注
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 gblab@vip.qq.com 举报,一经查实,本站将立刻删除。
内容手机端
扫描二维码推送至手机访问。