227 lines
6.8 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

本案例要求编写一个**斗地主的洗牌发牌**程序,要求按照斗地主的规则完成洗牌发牌的过程。
## 任务描述
一副扑克总共有54张牌牌面由花色和数字组成包括J、Q、K、A字母组成花色有♠、♥、♦、♣ 四种,分别表示黑桃、红桃、方块、梅花,小☺、大☻分别表示小王和大王。
斗地主游戏共有3位玩家参与首先将这54张牌的顺序打乱每人轮流摸一次牌剩余3张留作底牌然后在控制台打印3位玩家的牌和3张底牌。
## 运行结果
![](https://static.seahi.me/2024/12/202412030938880.png)
## 实现思路
### 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查找对应的牌面
- 最后打印每个玩家的牌和底牌
## 关键技术点
1. 集合的使用:
- ArrayList存储花色、点数和牌组
- HashMap建立编号和牌面的对应关系
2. 工具类的应用:
- Collections.shuffle():用于洗牌
- Collections.sort():用于整理手牌
3. 循环的应用:
- 两层循环生成牌组
- 取余操作(%)实现轮流发牌
## 示例代码
```java
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-10JQKA
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);
}
}
```
## 进阶任务
利用面向对象思想改造程序
### 类的设计级要求
#### 1. Card类扑克牌
**职责**:表示一张扑克牌
- 属性:
- suit花色字符串类型
- rank点数字符串类型
- index编号整型
- 功能:
- 构造方法:初始化一张牌
- toString方法返回牌面字符串
- 实现Comparable接口用于排序
#### 2. Deck类牌组
**职责**:管理一副完整的扑克牌
- 属性:
- cardsCard类型的ArrayList
- 花色和点数的常量数组
- 功能:
- 初始化54张牌
- 洗牌方法
- 发牌方法
#### 3. Player类玩家
**职责**:管理玩家信息和手牌
- 属性:
- name玩家名称
- hand存储手牌的ArrayList
- 功能:
- 接收牌
- 整理手牌
- 显示手牌
#### 4. Game类游戏管理
**职责**:控制游戏流程
- 属性:
- deck牌组对象
- 三个玩家对象
- bottomCards底牌列表
- 功能:
- 初始化游戏
- 执行游戏流程
- 显示游戏结果
### 改造要点
#### 1. 封装性要求
- 所有类的属性都应该是私有的
- 必要的属性提供getter/setter方法
- 对外只暴露必要的方法
#### 2. 类之间的关系
- Game类包含Deck类和Player类的对象
- Player类包含Card类的对象
- Deck类负责Card对象的创建和管理
#### 3. 功能性要求
- 保持原有程序的所有功能
- 洗牌和发牌的逻辑不变
- 结果显示格式保持一致