📚 目录
1. 定义牌的类
首先根据扑克牌的规则定义出扑克牌的类:定义一张扑克牌的属性:花色,面值
java
//一张扑克牌
public class Card {
//花色:红桃、黑桃、方块、梅花
public String suit;
//面值:A,2...10,j,Q,k
public String rank;
@Override
public String toString() {
return String.format("[%s %s]",suit,rank);//格式化进行输出花色+面值
}
}
我们需要重写toString方法,方便后续的打印。
[🔙 返回目录](#🔙 返回目录)
2. 初始化牌
我们买到一副扑克牌,这副扑克牌的顺序都是一样的,相同的在一起,没有经过任何的 洗牌操作,我们需要对其进行模拟。
我们使用顺序表进行模拟:
对每一张排进行构造然后添加到顺序表当中-》完成初始化。
我们先要定义一一个刚买到牌的方法 和 牌的属性 :buyDeck
通过双重循环进行链表的添加,循环生成 4 种花色 × 13 种点数,刚好 52 张牌。。
java
package demo1;
import java.util.ArrayList;
import java.util.List;
public class PokerGame {
//牌的面值:初始化的时候我们不希望这个顺序能够修改,可按照个人习惯进行初始化
public static final String[] rank = {"A", "2", "3", "4", "5",
"6", "7", "8", "9", "10", "J", "Q", "K"};
//牌的花色:
public static final String[] suit = {"♥红桃", "♠黑桃", "♦方块", "♣梅花"};
public static List<Card> buyDeck() {
//定义一个顺序表:大小为52
ArrayList<Card> pokerList = new ArrayList<>(52);
for (int i = 0; i < suit.length; i++) {
for (int j = 0; j < rank.length; j++) {
String getSuit = suit[i];
String getRank = rank[j];
Card card = new Card();
card.rank = getRank;
card.suit = getSuit;
pokerList.add(card);
}
}
return pokerList;//返回初始化完成的扑克牌。
}
//通过打印看我们的扑克牌是否完成了初始化:
public static void main(String[] args) {
List<Card> cards = buyDeck();
for (int i = 0; i < cards.size(); i++) {
System.out.print(cards.get(i));
if((i+1)%13==0) {
System.out.println();
}
}
}
}
此时,我们能观察到,扑克牌成功进行初始化了。

[🔙 返回目录](#🔙 返回目录)
3. Fisher-Yates 洗牌算法
进行初始化之后,我们需要对扑克牌进行洗牌。
** 我们用经典的「Fisher-Yates 洗牌算法」,遍历牌组,把当前牌和随机位置的牌交换,实现打乱顺序。**
Fisher-Yates 洗牌算法是目前最经典、最高效、最公平的洗牌算法,专门用于把一个数组 / 列表随机打乱,保证每张牌出现在任何位置的概率完全相等。
首先我们需要生成0-52之间的随机数:我们可以使用Random来进行生成。
洗牌方法:
java
//洗牌:shuffle
public static void shuffle(List<Card> pokerList) {
Random random = new Random();
// 从后往前遍历,避免重复交换,保证每张牌只被打乱一次
for (int i = pokerList.size()-1; i >0 ; i--) {
// 生成0~i的随机索引,保证每张牌被抽到的概率相同
int a = random.nextInt(i+1);//生成范围是[0,53)Java中大部分范围都是左闭右开
swap(pokerList,i,a);
}
System.out.println("洗牌完成");
}
为什么从后面遍历?
为了避免重复打乱,已经确定好位置的牌不再参与交换,逻辑更清晰、效率更高,
交换方法:让i下标与生成的随机数进行交换。
java
public static void swap(List<Card> pokerList,int i ,int a) {
Card card = pokerList.get(i);
pokerList.set(i,pokerList.get(a));
pokerList.set(a,card);
}
结果:每次结果都不相同说明我们的洗牌成功了。


[🔙 返回目录](#🔙 返回目录)
4. 抓牌
** 我们实现一个给 3 个玩家各发 5 张牌的逻辑,从洗好的牌组里按顺序取牌。
抓牌的时候都是从上面开始抓牌:抓一张,牌库里面就少一张牌:我们知道remove方法实现了重载,删除后返回删除掉的值。
每一个人一次抓5张牌:**
首先我们得先检查牌是否够发,然后通过循环让每一个用户抓牌:
java
public static List<List<Card>> dealCards (List<Card>
pokerList,int playerCount,int cardPerPlayer) {
List<List<Card>> players = new ArrayList<>();
if(playerCount*cardPerPlayer>pokerList.size()) {
//检查牌的合法性
System.out.println("牌不够发啦");
return players;
}
//循环让每一个玩家抓牌,一次抓5张
for (int i = 0; i < playerCount; i++) {
List<Card> playerCards = new ArrayList<>();
for (int j = 0; j < cardPerPlayer; j++) {
//从头部开始抓牌。
playerCards.add(pokerList.remove(0));//巧妙使用remove特性。
}
players.add(playerCards);//每一个人一次次抓到的牌添加进去
}
return players;
}

** 这里用 List<List> 表示多个玩家的牌,本质上是一个 "二维顺序表":外层 List 存所有玩家,内层每个 List 存一个玩家的牌,和二维数组的逻辑是一样的,但比数组更灵活。**
我们可以知道结果:抓一次牌的结果,剩余37张牌。

合集:
java
//扑克牌
public class Card {
//花色:红桃、黑桃、方块、梅花
public String suit;
//面值:A,2...10,j,Q,k
public String rank;
@Override
public String toString() {
return String.format("[%s %s]",suit,rank);
}
}
java
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
public class PokerGame {
//牌的顺序:初始化的时候我们不希望这个顺序能够修改,可按照个人习惯进行初始化
public static final String[] rank = {"A", "2", "3", "4", "5",
"6", "7", "8", "9", "10", "J", "Q", "K"};
//牌的面值:
public static final String[] suit = {"♥红桃", "♠黑桃", "♦方块", "♣梅花"};
public static List<Card> buyDeck() {
//定义一个顺序表:大小为52
ArrayList<Card> pokerList = new ArrayList<>(52);
for (int i = 0; i < suit.length; i++) {
for (int j = 0; j < rank.length; j++) {
String getSuit = suit[i];
String getRank = rank[j];
Card card = new Card();
card.rank = getRank;
card.suit = getSuit;
pokerList.add(card);
}
}
return pokerList;
}
public static void swap(List<Card> pokerList,int i ,int a) {
Card card = pokerList.get(i);
pokerList.set(i,pokerList.get(a));
pokerList.set(a,card);
}
//洗牌:shuffle
public static void shuffle(List<Card> pokerList) {
Random random = new Random();
for (int i = pokerList.size()-1; i >0 ; i--) {
//随机生成0-i的数值:避免重复洗牌
int a = random.nextInt(i+1);
swap(pokerList,i,a);
}
System.out.println("洗牌完成");
}
//抓牌
public static List<List<Card>> dealCards (List<Card> pokerList
,int playerCount,int cardPerPlayer) {
List<List<Card>> players = new ArrayList<>();
if(playerCount*cardPerPlayer>pokerList.size()) {
System.out.println("牌不够发啦");
return players;
}
for (int i = 0; i < playerCount; i++) {
List<Card> playerCards = new ArrayList<>();
for (int j = 0; j < cardPerPlayer; j++) {
//从头部开始抓牌。
playerCards.add(pokerList.remove(0));
}
players.add(playerCards);
}
return players;
}
public static void main(String[] args) {
List<Card> cards = buyDeck();
shuffle(cards);//洗牌
List<List<Card>> players = dealCards(cards,3,5);
for (int i = 0; i < players.size(); i++) {
System.out.println("玩家" + (i+1) + "的牌:" + players.get(i));
}
//剩余排数:
System.out.println(cards.size());
}
}
[🔙 返回目录](#🔙 返回目录)