diff --git a/src/chapter6/demo64/Card.java b/src/chapter6/demo64/Card.java new file mode 100644 index 0000000..ef92fa8 --- /dev/null +++ b/src/chapter6/demo64/Card.java @@ -0,0 +1,35 @@ +package chapter6.demo64; + +// Card.java - 扑克牌类 +public class Card implements Comparable { + private String color; // 花色 + private String point; // 点数 + private int index; // 编号 + + /** + * 构造一张扑克牌 + * @param color 花色 + * @param point 点数 + * @param index 编号 + */ + public Card(String color, String point, int index) { + this.color = color; + this.point = point; + this.index = index; + } + + @Override + public String toString() { + return color + point; + } + + @Override + public int compareTo(Card other) { + return this.index - other.index; + } + + // getter方法 + public int getIndex() { + return index; + } +} diff --git a/src/chapter6/demo64/Deck.java b/src/chapter6/demo64/Deck.java new file mode 100644 index 0000000..de19d28 --- /dev/null +++ b/src/chapter6/demo64/Deck.java @@ -0,0 +1,45 @@ +package chapter6.demo64; + +import java.util.ArrayList; +import java.util.Collections; + +// Deck.java - 牌组类 +public class Deck { + private ArrayList cards = new ArrayList<>(); + private static final String[] COLORS = {"♠", "♥", "♣", "♦"}; + private static final String[] POINTS = {"2", "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K", "A"}; + + /** + * 初始化一副扑克牌 + */ + public Deck() { + int index = 0; + // 生成52张普通牌 + for (String point : POINTS) { + for (String color : COLORS) { + cards.add(new Card(color, point, index++)); + } + } + // 添加大小王 + cards.add(new Card("", "小☺", index++)); + cards.add(new Card("", "大☻", index)); + } + + /** + * 洗牌 + */ + public void shuffle() { + Collections.shuffle(cards); + } + + /** + * 发牌 + * @return 发出的牌 + */ + public Card dealCard() { + if (!cards.isEmpty()) { + return cards.remove(0); + } + return null; + } +} \ No newline at end of file diff --git a/src/chapter6/demo64/Function.java b/src/chapter6/demo64/Function.java new file mode 100644 index 0000000..0a505bd --- /dev/null +++ b/src/chapter6/demo64/Function.java @@ -0,0 +1,170 @@ +package chapter6.demo64; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; + +public class Function { + // 存储牌号和牌面的对应关系 + private static HashMap cardMap = new HashMap<>(); + + public static void main(String[] args) { + // 1. 准备牌的基本元素 + ArrayList colors = prepareColors(); + ArrayList points = preparePoints(); + + // 2. 组装54张牌 + createCards(colors, points); + + // 3. 洗牌准备 + ArrayList cards = shuffleCards(); + + // 4. 发牌 + ArrayList> dealtCards = dealCards(cards); + ArrayList iPlayer = dealtCards.get(0); + ArrayList iPlayer2 = dealtCards.get(1); + ArrayList iPlayer3 = dealtCards.get(2); + ArrayList iSecretCards = dealtCards.get(3); + + // 5. 整理手牌 + sortCards(iPlayer, iPlayer2, iPlayer3); + + // 6. 转换并显示牌面 + showCards(iPlayer, iPlayer2, iPlayer3, iSecretCards); + } + + /** + * 准备扑克牌的4种花色 + * @return ArrayList 包含4种花色符号的列表 + */ + private static ArrayList prepareColors() { + ArrayList colors = new ArrayList<>(); + colors.add("♠"); + colors.add("♥"); + colors.add("♣"); + colors.add("♦"); + return colors; + } + + /** + * 准备扑克牌的13种点数 + * @return ArrayList 包含2-10,J,Q,K,A的点数列表 + */ + private static ArrayList preparePoints() { + ArrayList points = new ArrayList<>(); + for (int i = 2; i <= 10; i++) { + points.add(i + ""); + } + points.add("J"); + points.add("Q"); + points.add("K"); + points.add("A"); + return points; + } + + /** + * 创建54张扑克牌,并建立编号和牌面的映射关系 + * @param colors 花色列表 + * @param points 点数列表 + */ + private static void createCards(ArrayList colors, ArrayList points) { + int index = 0; + for (String number : points) { + for (String color : colors) { + cardMap.put(index++, color + number); + } + } + cardMap.put(index++, "小☺"); + cardMap.put(index++, "大☻"); + } + + /** + * 生成54张牌的编号并随机打乱顺序 + * @return ArrayList 洗好的牌的编号列表(0-53) + */ + private static ArrayList shuffleCards() { + ArrayList cards = new ArrayList<>(); + for (int i = 0; i <= 53; i++) { + cards.add(i); + } + Collections.shuffle(cards); + return cards; + } + + /** + * 将54张牌分发给三个玩家和底牌 + * @param cards 洗好的牌的编号列表 + * @return ArrayList> 包含四个列表的集合: + * 索引0-2分别为三个玩家的牌,索引3为底牌 + */ + private static ArrayList> dealCards(ArrayList cards) { + ArrayList iPlayer = new ArrayList<>(); + ArrayList iPlayer2 = new ArrayList<>(); + ArrayList iPlayer3 = new ArrayList<>(); + ArrayList iSecretCards = new ArrayList<>(); + + for (int i = 0; i < cards.size(); i++) { + if (i >= 51) { + iSecretCards.add(cards.get(i)); + } else { + if (i % 3 == 0) { + iPlayer.add(cards.get(i)); + } else if (i % 3 == 1) { + iPlayer2.add(cards.get(i)); + } else { + iPlayer3.add(cards.get(i)); + } + } + } + + ArrayList> result = new ArrayList<>(); + result.add(iPlayer); + result.add(iPlayer2); + result.add(iPlayer3); + result.add(iSecretCards); + return result; + } + + /** + * 对玩家手中的牌进行排序 + * @param players 可变参数,接收多个玩家的牌列表 + */ + private static void sortCards(ArrayList... players) { + for (ArrayList player : players) { + Collections.sort(player); + } + } + + /** + * 展示所有玩家的牌和底牌 + * @param iPlayer 玩家1的牌号列表 + * @param iPlayer2 玩家2的牌号列表 + * @param iPlayer3 玩家3的牌号列表 + * @param iSecretCards 底牌列表 + */ + private static void showCards(ArrayList iPlayer, ArrayList iPlayer2, + ArrayList iPlayer3, ArrayList iSecretCards) { + ArrayList sPlayer = convertToCardFace(iPlayer); + ArrayList sPlayer2 = convertToCardFace(iPlayer2); + ArrayList sPlayer3 = convertToCardFace(iPlayer3); + ArrayList sSecretCards = convertToCardFace(iSecretCards); + + System.out.println("玩家1:" + sPlayer); + System.out.println("玩家2:" + sPlayer2); + System.out.println("玩家3:" + sPlayer3); + System.out.println("底牌:" + sSecretCards); + } + + /** + * 将牌号转换为具体的牌面 + * @param cards 牌号列表 + * @return ArrayList 转换后的牌面列表 + */ + private static ArrayList convertToCardFace(ArrayList cards) { + ArrayList result = new ArrayList<>(); + for (Integer key : cards) { + result.add(cardMap.get(key)); + } + return result; + } +} diff --git a/src/chapter6/demo64/Game.java b/src/chapter6/demo64/Game.java new file mode 100644 index 0000000..095eb95 --- /dev/null +++ b/src/chapter6/demo64/Game.java @@ -0,0 +1,78 @@ +package chapter6.demo64; + +import java.util.ArrayList; +import java.util.Collections; + +// Game.java - 游戏类 +public class Game { + private Deck deck; + private Player player1; + private Player player2; + private Player player3; + private ArrayList bottomCards; + + /** + * 初始化游戏 + */ + public Game() { + deck = new Deck(); + player1 = new Player("玩家1"); + player2 = new Player("玩家2"); + player3 = new Player("玩家3"); + bottomCards = new ArrayList<>(); + } + + /** + * 开始游戏 + */ + public void start() { + // 1. 洗牌 + deck.shuffle(); + + // 2. 发牌 + for (int i = 0; i < 54; i++) { + Card card = deck.dealCard(); + if (i >= 51) { + bottomCards.add(card); + } else { + switch (i % 3) { + case 0: + player1.receiveCard(card); + break; + case 1: + player2.receiveCard(card); + break; + case 2: + player3.receiveCard(card); + break; + } + } + } + + // 3. 整理手牌 + player1.sortHand(); + player2.sortHand(); + player3.sortHand(); + + // 4. 显示结果 + showResult(); + } + + /** + * 显示游戏结果 + */ + private void showResult() { + System.out.println(player1.showHand()); + System.out.println(player2.showHand()); + System.out.println(player3.showHand()); + System.out.println("底牌:" + bottomCards); + } + + /** + * 程序入口 + */ + public static void main(String[] args) { + Game game = new Game(); + game.start(); + } +} \ No newline at end of file diff --git a/src/chapter6/demo64/Main.java b/src/chapter6/demo64/Main.java new file mode 100644 index 0000000..04e6063 --- /dev/null +++ b/src/chapter6/demo64/Main.java @@ -0,0 +1,111 @@ +package chapter6.demo64; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; + +public class Main { + public static void main(String[] args) { + /* 第一步:准备扑克牌的基本元素 */ + // 准备4种花色 + ArrayList colors = new ArrayList(); + colors.add("♠"); + colors.add("♥"); + colors.add("♣"); + colors.add("♦"); + + // 准备13种点数(2-10,J,Q,K,A) + ArrayList point = new ArrayList(); + for (int i = 2; i <= 10; i++) { + point.add(i + ""); + } + point.add("J"); + point.add("Q"); + point.add("K"); + point.add("A"); + + /* 第二步:组装54张扑克牌 */ + // 用HashMap将每张牌的编号(0-53)与具体牌面对应起来 + HashMap map = new HashMap(); + int index = 0; // 牌的编号,从0开始 + + // 两层循环,生成52张普通牌(13点数 × 4花色) + for (String number : point) { + for (String color : colors) { + // 将花色与数字组合,形成52张牌,并赋予其编号 + map.put(index++, color + number); + } + } + + // 加入大小王,编号为52和53 + map.put(index++, "小☺"); + map.put(index++, "大☻"); + + /* 第三步:洗牌准备 */ + // 准备一个数字序列,代表54张牌 + ArrayList cards = new ArrayList(); + for (int i = 0; i <= 53; i++) { + cards.add(i); // 此时的cards顺序为0-53 + } + + // 使用shuffle方法打乱牌的顺序(洗牌) + Collections.shuffle(cards); + + /* 第四步:发牌 */ + // 创建4个集合,分别存储三个玩家的牌和底牌 + ArrayList iPlayer = new ArrayList(); // 玩家1的牌 + ArrayList iPlayer2 = new ArrayList(); // 玩家2的牌 + ArrayList iPlayer3 = new ArrayList(); // 玩家3的牌 + ArrayList iSecretCards = new ArrayList(); // 底牌 + + // 发牌规则:留3张底牌,其余轮流发给3个玩家 + for (int i = 0; i < cards.size(); i++) { + if (i >= 51) { + iSecretCards.add(cards.get(i));// 留取3张底牌 + } else { + if (i % 3 == 0) { + iPlayer.add(cards.get(i)); // 与3取余为0的牌发给玩家1 + } else if (i % 3 == 1) { + iPlayer2.add(cards.get(i)); // 与3取余为1的牌发给玩家2 + } else { + iPlayer3.add(cards.get(i)); // 其余的牌发给玩家3 + } + } + } + + /* 第五步:整理手牌 */ + // 对每个玩家手中的牌排序 + Collections.sort(iPlayer); + Collections.sort(iPlayer2); + Collections.sort(iPlayer3); + + /* 第六步:转换牌面并显示 */ + // iPlayer 中的存储的是每个玩家拥有的牌的编号(0-53) + // 将玩家手中的牌号转换为具体的牌面 + ArrayList sPlayer = new ArrayList(); + ArrayList sPlayer2 = new ArrayList(); + ArrayList sPlayer3 = new ArrayList(); + ArrayList sSecretCards = new ArrayList(); + + // 根据牌号,从map中找出对应的牌面 + for (Integer key : iPlayer) { + sPlayer.add(map.get(key)); + } + for (Integer key : iPlayer2) { + sPlayer2.add(map.get(key)); + } + for (Integer key : iPlayer3) { + sPlayer3.add(map.get(key)); + } + + for (Integer key : iSecretCards) { + sSecretCards.add(map.get(key)); + } + + // 展示每个玩家的牌 + System.out.println("玩家1:" + sPlayer); + System.out.println("玩家2:" + sPlayer2); + System.out.println("玩家3:" + sPlayer3); + System.out.println("底牌:" + sSecretCards); + } +} diff --git a/src/chapter6/demo64/Player.java b/src/chapter6/demo64/Player.java new file mode 100644 index 0000000..cb05b5a --- /dev/null +++ b/src/chapter6/demo64/Player.java @@ -0,0 +1,38 @@ +package chapter6.demo64; + + +import java.util.ArrayList; +import java.util.Collections; + +// Player.java - 玩家类 +public class Player { + private String name; + private ArrayList hand = new ArrayList<>(); + + public Player(String name) { + this.name = name; + } + + /** + * 接收一张牌 + * @param card 收到的牌 + */ + public void receiveCard(Card card) { + hand.add(card); + } + + /** + * 整理手牌 + */ + public void sortHand() { + Collections.sort(hand); + } + + /** + * 显示手牌 + * @return 手牌的字符串表示 + */ + public String showHand() { + return name + ":" + hand.toString(); + } +} \ No newline at end of file diff --git a/src/chapter6/demo64/README.md b/src/chapter6/demo64/README.md new file mode 100644 index 0000000..7e187a6 --- /dev/null +++ b/src/chapter6/demo64/README.md @@ -0,0 +1,226 @@ + +本案例要求编写一个**斗地主的洗牌发牌**程序,要求按照斗地主的规则完成洗牌发牌的过程。 + +## 任务描述 + +一副扑克总共有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 colors = new ArrayList(); + colors.add("♠"); + colors.add("♥"); + colors.add("♣"); + colors.add("♦"); + + // TODO 准备13种点数(2-10,J,Q,K,A) + ArrayList point = new ArrayList(); + + + /* 第二步:组装54张扑克牌 */ + // 用HashMap将每张牌的编号(0-53)与具体牌面对应起来 + HashMap map = new HashMap(); + int index = 0; // 牌的编号,从0开始 + + // TODO 两层循环,生成52张普通牌(13点数 × 4花色) + + + // 加入大小王,编号为52和53 + map.put(index++, "小☺"); + map.put(index++, "大☻"); + + /* 第三步:洗牌准备 */ + // TOOD 准备一个数字序列,代表54张牌 + ArrayList cards = new ArrayList(); + + + // 使用shuffle方法打乱牌的顺序(洗牌) + Collections.shuffle(cards); + + /* 第四步:发牌 */ + // 创建4个集合,分别存储三个玩家的牌和底牌 + ArrayList iPlayer = new ArrayList(); // 玩家1的牌 + ArrayList iPlayer2 = new ArrayList(); // 玩家2的牌 + ArrayList iPlayer3 = new ArrayList(); // 玩家3的牌 + ArrayList iSecretCards = new ArrayList(); // 底牌 + + // TODO 发牌规则:留3张底牌,其余轮流发给3个玩家 + for (int i = 0; i < cards.size(); i++) { + + } + + /* 第五步:整理手牌 */ + // 对每个玩家手中的牌排序 + Collections.sort(iPlayer); + Collections.sort(iPlayer2); + Collections.sort(iPlayer3); + + /* 第六步:转换牌面并显示 */ + // iPlayer 中的存储的是每个玩家拥有的牌的编号(0-53) + // 将玩家手中的牌号转换为具体的牌面 + ArrayList sPlayer = new ArrayList(); + ArrayList sPlayer2 = new ArrayList(); + ArrayList sPlayer3 = new ArrayList(); + ArrayList sSecretCards = new ArrayList(); + + // 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类(牌组) + +**职责**:管理一副完整的扑克牌 + +- 属性: + - cards:Card类型的ArrayList + - 花色和点数的常量数组 +- 功能: + - 初始化54张牌 + - 洗牌方法 + - 发牌方法 + +#### 3. Player类(玩家) + +**职责**:管理玩家信息和手牌 + +- 属性: + - name:玩家名称 + - hand:存储手牌的ArrayList +- 功能: + - 接收牌 + - 整理手牌 + - 显示手牌 + +#### 4. Game类(游戏管理) + +**职责**:控制游戏流程 + +- 属性: + - deck:牌组对象 + - 三个玩家对象 + - bottomCards:底牌列表 +- 功能: + - 初始化游戏 + - 执行游戏流程 + - 显示游戏结果 + +### 改造要点 + +#### 1. 封装性要求 + +- 所有类的属性都应该是私有的 +- 必要的属性提供getter/setter方法 +- 对外只暴露必要的方法 + +#### 2. 类之间的关系 + +- Game类包含Deck类和Player类的对象 +- Player类包含Card类的对象 +- Deck类负责Card对象的创建和管理 + +#### 3. 功能性要求 + +- 保持原有程序的所有功能 +- 洗牌和发牌的逻辑不变 +- 结果显示格式保持一致