ArrayList | 简单的洗牌算法

news2025/1/15 13:11:31

一个洗牌程序需要包含:

  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()
    @Override
    public 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存放Poker
        List<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.java

import 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.java

import 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.java

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()
    @Override
    public String toString() {
        return "{" + suit + " " + rank + "}";
    }
}

 

//Game.java

import 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.coloradmin.cn/o/149019.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

R 语言 4.2.2安装 WGCNA

文章目录1 WGCNA库介绍2 安装踩坑还得是官方文档这样安装我出现的问题参考AppendixA. 安装RB. 配置环境C. 修改镜像1 WGCNA库介绍 WGCNA是用于加权相关网络分析的R包&#xff0c; 相关网络越来越多地用于生物信息学应用 加权基因共表达网络分析是一种系统生物学方法&#xff0…

按键控制电源通断,实现各种设备/电脑开关机低功耗IC

前言 今天记录一下一些硬件开关电的低功耗控制ic&#xff0c;代替物理机械开关&#xff0c;后续有新的更好用的芯片会继续更新此博。 环境 every machine 参考文档 正文 一版我们选择ic&#xff0c;除了功能之外还要看一些性能&#xff0c;这里我暂时录入的功能就是一个按…

SpringCloud从入门到精通(九)

bus bus-概述 • Spring Cloud Bus 是用轻量的消息中间件将分布式的节点连接起来&#xff0c;可以用于广播配置文件的更改或 者服务的监控管理。关键的思想就是&#xff0c;消息总线可以为微服务做监控&#xff0c;也可以实现应用程序之间相通信。 • Spring Cloud Bus 可选的…

【MySQL】为什么使用B+树做索引

【MySQL】为什么使用B树做索引? 索引这个词&#xff0c;相信大多数人已经相当熟悉了&#xff0c;很多人都知道MySQL的索引主要以B树为主&#xff0c;但是要问到为什么用B树&#xff0c;恐怕很少有人能把前因后果讲述的很完整。本文就来从头到尾介绍下数据库的索引。 索引是一…

linux系统中QT控件的操作的基本方法

大家好&#xff0c;今天主要和大家聊一聊&#xff0c;如何学习QT中的控件使用方法。 目录 第一&#xff1a;QT控件基本简介 第二&#xff1a;QPushButton使用方法 第三&#xff1a;QTableWidget简介 第四&#xff1a;最终运行效果 第一&#xff1a;QT控件基本简介 老子曾说…

Rad Studio 11.2 安装 OrangeUI 组件教程

官方文档&#xff1a;http://www.orangeui.cn/components/install 本文参考官方文档进行 11 版本的安装 开始 打开 Rad Studio 11&#xff0c;点击 FIle–Open Project… 找到解压的目录下的 .groupproj 文件 出现移动端提示弹窗&#xff0c;关掉 即可 右键 点击右侧第一个程序…

大数取余公式

ab)modP[(amodP)(bmodP)]modP (ab)modP[(amodP)(bmodP)]modP欢迎使用Markdown编辑器 你好&#xff01; 这是你第一次使用 Markdown编辑器 所展示的欢迎页。如果你想学习如何使用Markdown编辑器, 可以仔细阅读这篇文章&#xff0c;了解一下Markdown的基本语法知识。 新的改变 …

数据结构-随机化快速排序

一、概念及其介绍 快速排序由 C. A. R. Hoare 在 1960 年提出。 随机化快速排序基本思想&#xff1a;通过一趟排序将要排序的数据分割成独立的两部分&#xff0c;其中一部分的所有数据都比另外一部分的所有数据都要小&#xff0c;然后再按此方法对这两部分数据分别进行快速排…

Jenkins凭证/凭据管理详解

文章目录一、Jenkins中的凭证凭证类型凭证范围系统全局用户凭证域凭证提供者系统凭证提供者 &#xff08;Jenkins 凭证提供者&#xff0c;常用&#xff09;用户凭证提供者文件夹凭证提供者BlueOcean 凭证插件凭证存储二、管理凭证选择凭证提供者选择凭证类型通过提供者指定凭证…

JavaScript---DOM---DOM重点核心---1.8

关于DOM操作&#xff0c;我们主要针对于元素的操作。主要有创建、增、删、改、查、属性操作、事件操作。 创建 document.writeinnerHTMLcreateElement 增 appendChildinsertBefore 删 removeChild 改 主要修改dom的元素属性&#xff0c;dom元素的内容、属性、表单的值等 …

websocket的实现

websocket的实现 本文的websocket实现基于单线程Reactor网络模型的代码实现 初步了解websocket&#xff08;必读&#xff09;:参考连接 websocekt的实现基于http&#xff0c;数据传输与处理过程也很类似&#xff1a;基于reactor的http服务器 websocket握手 websocket基于T…

Python-123练习-02数值运算

文章目录1. 整数四则运算2. 除法运算3. 计算矩形面积4. 计算矩形面积结果保留两位小数5. 计算存款利息6. 计算多个垫片面积的和7. 换披萨8. 表达式求值9. 三角函数计算10. 三角形周长及面积1. 整数四则运算 描述 编写程序&#xff0c;计算2个正整数的和、差、积、商并输出。题…

2023春节祝福系列第一弹(放飞孔明灯,祝福大家身体健康)

2023年春节祝福第一弹 放飞孔明灯&#xff0c;祝福大家身体健康&#xff01; 目录 一、前言 二、一片星光闪烁的旋转星空 &#xff08;1&#xff09;、效果展示&#xff1a; &#xff08;2&#xff09;、相关源代码 &#xff08;3&#xff09;、语法解释 &#xff08;3.…

[ 数据结构 ] 堆排序--------思路、图解、代码

0 基本介绍 堆定义:首先是完全二叉树,分为大顶堆和小顶堆大顶堆:顾名思义,如果将父子节点看成一个堆(三个节点的组合),那么顶的值需要大于其两个子节点的值,即顶大;小顶堆即顶小升序排序使用大顶堆,降序使用小顶堆回顾顺序存储二叉树中,父子节点的关系为:下标为n的节点,它的左…

Java开发 - Spring框架初体验

目录 前言 了解框架的概念 Spring框架 关于Spring 在Maven中使用Spring Spring怎么管理对象 spring怎么创建对象 通过Bean注解创建对象 通过组件扫描创建对象 关于ComponentScan("xxxxxx") Spring Bean的作用域 自动装配技术 什么是自动装配 补充 Io…

MATLAB循环码编译码实验

标题循环码编译码实验一、实验目的1、掌握循环码编码原理和译码原理2、练习使用Matlab编程实现循环码编码和译码二、实验原理伴随式译码捕错译码三、实验要求1、编程实现码长n15的各种循环码的编码、译码&#xff0c;给出相应的码生成多项式、&#xff08;典型&#xff09;监督…

Java设计模式中装饰者模式/装饰者模式具体内容是什么/静态代理与装饰者模式联系与区别是什么

继续整理记录这段时间来的收获&#xff0c;详细代码可在我的Gitee仓库SpringBoot克隆下载学习使用&#xff01; 5.4 装饰者模式 5.4.1 概述 在不改变现有对象结构的情况下&#xff0c;动态给对象增加某些职责或功能的模式 5.4.2 结构 抽象构件(Component)&#xff1a;定义…

Javascript 中的堆、栈、引用和值

学透CSS-强烈推荐 Javascript 中的内存存储 栈-Stack&#xff1a; 这是当前 Javascript 线程的暂存空间。由于 Javascript 通常只有单线程&#xff0c;因此通常只有一个堆栈。堆栈的大小也是有限的。 堆-Heap &#xff0c;它是应用程序级别的动态内存存储。从堆中访问和检索…

java 手把手带你创建一个spring入门案例

查看本文 首先 您需要下载spring 如果没有安装 可以查看我的文章 java spring下载步骤 首先 我们打开idea开发工具 选择左上角 File > New > Project 如下图操作 勾选 然后点击下一步 然后我们选择项目目录 这里我直接用了个中文目录 最好不要跟我学哦 因为个人英文不…

微信语音转换成mp3文件保存的简单详细步骤

目录 读者手册 一、前言 二、操作步骤一 把语音转化为silk文件&#xff08;silk后缀的文件&#xff09; 1.长按语音收藏&#xff08;手机操作&#xff09; 2.找到主页收藏 3.找到收藏的语音 4.转存为笔记 5.点击笔记里面的语音&#xff08;下面全部电脑操作&#xff0…