案例6-4 斗地主洗牌发牌

系列 - JAVA程序案例
目录
本案例要求编写一个斗地主的洗牌发牌程序,要求按照斗地主的规则完成洗牌发牌的过程。
任务描述
一副扑克总共有54张牌,牌面由花色和数字组成(包括J、Q、K、A字母)组成,花色有♠、♥、♦、♣ 四种,分别表示黑桃、红桃、方块、梅花,小☺、大☻分别表示小王和大王。
斗地主游戏共有3位玩家参与,首先将这54张牌的顺序打乱每人轮流摸一次牌,剩余3张留作底牌,然后在控制台打印3位玩家的牌和3张底牌。
运行结果
实现思路
1. 准备牌面元素
- 创建扑克牌的基本元素:花色和点数
- 花色:♠(黑桃)、♥(红桃)、♣(梅花)、♦(方块)
- 点数:2-10、J、Q、K、A
- 使用
ArrayList
分别存储花色和点数
2. 生成完整的牌组
- 使用HashMap建立牌的编号和具体牌面的对应关系
- 通过两层循环组合花色和点数,生成52张普通牌
- 额外加入大小王,总共54张牌
- 每张牌都有唯一的编号(0-53)
3. 洗牌准备
- 创建一个包含0-53数字的ArrayList,代表54张牌
- 使用
Collections.shuffle()
方法随机打乱这些数字的顺序 - 打乱后的顺序就是发牌的顺序
4. 发牌过程
- 创建4个ArrayList用于存储发牌结果:
- 3个玩家的牌(iPlayer1、iPlayer2、iPlayer3)
- 1个底牌(iSecretCards)
- 发牌规则:
- 前51张牌轮流发给3个玩家(i%3来分配)
- 最后3张作为底牌
5. 整理手牌
- 使用
Collections.sort()
方法对每个玩家手中的牌进行排序 - 排序是对牌的编号进行排序,方便后续显示
6. 转换和显示
- 创建新的ArrayList存储实际的牌面字符串
- 遍历每个玩家手中的牌号
- 通过HashMap查找对应的牌面
- 最后打印每个玩家的牌和底牌
关键技术点
- 集合的使用:
- ArrayList:存储花色、点数和牌组
- HashMap:建立编号和牌面的对应关系
- 工具类的应用:
- Collections.shuffle():用于洗牌
- Collections.sort():用于整理手牌
- 循环的应用:
- 两层循环生成牌组
- 取余操作(%)实现轮流发牌
示例代码
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
public class Main {
public static void main(String[] args) {
/* 第一步:准备扑克牌的基本元素 */
// 准备4种花色
ArrayList<String> colors = new ArrayList<String>();
colors.add("♠");
colors.add("♥");
colors.add("♣");
colors.add("♦");
// TODO 准备13种点数(2-10,J,Q,K,A)
ArrayList<String> point = new ArrayList<String>();
/* 第二步:组装54张扑克牌 */
// 用HashMap将每张牌的编号(0-53)与具体牌面对应起来
HashMap<Integer, String> map = new HashMap<Integer, String>();
int index = 0; // 牌的编号,从0开始
// TODO 两层循环,生成52张普通牌(13点数 × 4花色)
// 加入大小王,编号为52和53
map.put(index++, "小☺");
map.put(index++, "大☻");
/* 第三步:洗牌准备 */
// TOOD 准备一个数字序列,代表54张牌
ArrayList<Integer> cards = new ArrayList<Integer>();
// 使用shuffle方法打乱牌的顺序(洗牌)
Collections.shuffle(cards);
/* 第四步:发牌 */
// 创建4个集合,分别存储三个玩家的牌和底牌
ArrayList<Integer> iPlayer = new ArrayList<Integer>(); // 玩家1的牌
ArrayList<Integer> iPlayer2 = new ArrayList<Integer>(); // 玩家2的牌
ArrayList<Integer> iPlayer3 = new ArrayList<Integer>(); // 玩家3的牌
ArrayList<Integer> iSecretCards = new ArrayList<Integer>(); // 底牌
// TODO 发牌规则:留3张底牌,其余轮流发给3个玩家
for (int i = 0; i < cards.size(); i++) {
}
/* 第五步:整理手牌 */
// 对每个玩家手中的牌排序
Collections.sort(iPlayer);
Collections.sort(iPlayer2);
Collections.sort(iPlayer3);
/* 第六步:转换牌面并显示 */
// iPlayer 中的存储的是每个玩家拥有的牌的编号(0-53)
// 将玩家手中的牌号转换为具体的牌面
ArrayList<String> sPlayer = new ArrayList<String>();
ArrayList<String> sPlayer2 = new ArrayList<String>();
ArrayList<String> sPlayer3 = new ArrayList<String>();
ArrayList<String> sSecretCards = new ArrayList<String>();
// TODO 根据牌号,从map中找出对应的牌面
for (Integer key : iPlayer) {
sPlayer.add(map.get(key));
}
// 展示每个玩家的牌
System.out.println("玩家1:" + sPlayer);
System.out.println("玩家2:" + sPlayer2);
System.out.println("玩家3:" + sPlayer3);
System.out.println("底牌:" + sSecretCards);
}
}
进阶任务
当前的代码是面向过程的,其流程如下:
graph TD; A[开始] --> B[准备扑克牌基本元素] B --> B1[创建花色列表] B --> B2[创建点数列表] B1 --> C[组装54张扑克牌] B2 --> C C --> C1[创建HashMap存储牌面] C1 --> C2[生成52张普通牌] C2 --> C3[添加大小王] C3 --> D[洗牌准备] D --> D1[创建0-53的数字序列] D1 --> D2[使用shuffle方法打乱顺序] D2 --> E[发牌] E --> E1{是否是最后3张牌?} E1 -->|是| E2[加入底牌] E1 -->|否| E3{按照i%3分配给玩家} E3 -->|余0| E4[加入玩家1] E3 -->|余1| E5[加入玩家2] E3 -->|余2| E6[加入玩家3] E4 --> F[整理手牌] E5 --> F E6 --> F E2 --> F F --> F1[对玩家1手牌排序] F --> F2[对玩家2手牌排序] F --> F3[对玩家3手牌排序] F1 --> G[转换牌面并显示] F2 --> G F3 --> G G --> G1[将玩家1牌号转换为牌面] G --> G2[将玩家2牌号转换为牌面] G --> G3[将玩家3牌号转换为牌面] G --> G4[将底牌转换为牌面] G1 --> H[显示结果] G2 --> H G3 --> H G4 --> H H --> I[结束]
将原有的过程式代码重构为面向对象的设计,使程序结构更清晰,更易维护和扩展。
类的设计级要求
classDiagram Card --> Deck Deck --> Game Player --> Game
1. Card类(扑克牌)
职责:表示一张扑克牌
- 属性:
- color(花色):字符串类型
- point(点数):字符串类型
- index(编号):整型
- 功能:
- 构造方法:初始化一张牌
- toString方法:返回牌面字符串
- 实现Comparable接口:用于排序
2. Deck类(牌组)
职责:管理一副完整的扑克牌
- 属性:
- cards:Card类型的ArrayList
- 花色和点数的常量数组
- 功能:
- 初始化54张牌
- 洗牌方法
- 发牌方法
3. Player类(玩家)
职责:管理玩家信息和手牌
- 属性:
- name:玩家名称
- hand:存储手牌的ArrayList
- 功能:
- 接收牌
- 整理手牌
- 显示手牌
4. Game类(游戏管理)
职责:控制游戏流程
- 属性:
- deck:牌组对象
- 三个玩家对象
- bottomCards:底牌列表
- 功能:
- 初始化游戏
- 执行游戏流程
- 显示游戏结果
类图
classDiagram class Card { -String color -String point -int index +Card(String color, String point, int index) +String toString() +int compareTo(Card) +int getIndex() } class Deck { -ArrayList~Card~ cards -String[] COLORS -String[] POINTS +Deck() +void shuffle() +Card dealCard() } class Player { -String name -TreeSet~Card~ hand +Player(String name) +void receiveCard(Card card) +String showHand() } class Game { -Deck deck -Player player1 -Player player2 -Player player3 -ArrayList~Card~ bottomCards +Game() +void start() -void showResult() } Card ..|> Comparable : implements Game "1" *-- "1" Deck : contains Game "1" *-- "3" Player : contains Deck "1" *-- "*" Card : creates Player "1" o-- "*" Card : has