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

本案例要求编写一个斗地主的洗牌发牌程序,要求按照斗地主的规则完成洗牌发牌的过程。

一副扑克总共有54张牌,牌面由花色和数字组成(包括J、Q、K、A字母)组成,花色有♠、♥、♦、♣ 四种,分别表示黑桃、红桃、方块、梅花,小☺、大☻分别表示小王和大王。

斗地主游戏共有3位玩家参与,首先将这54张牌的顺序打乱每人轮流摸一次牌,剩余3张留作底牌,然后在控制台打印3位玩家的牌和3张底牌。

  • 创建扑克牌的基本元素:花色和点数
  • 花色:♠(黑桃)、♥(红桃)、♣(梅花)、♦(方块)
  • 点数:2-10、J、Q、K、A
  • 使用ArrayList分别存储花色和点数
  • 使用HashMap建立牌的编号和具体牌面的对应关系
  • 通过两层循环组合花色和点数,生成52张普通牌
  • 额外加入大小王,总共54张牌
  • 每张牌都有唯一的编号(0-53)
  • 创建一个包含0-53数字的ArrayList,代表54张牌
  • 使用Collections.shuffle()方法随机打乱这些数字的顺序
  • 打乱后的顺序就是发牌的顺序
  • 创建4个ArrayList用于存储发牌结果:
    • 3个玩家的牌(iPlayer1、iPlayer2、iPlayer3)
    • 1个底牌(iSecretCards)
  • 发牌规则:
    • 前51张牌轮流发给3个玩家(i%3来分配)
    • 最后3张作为底牌
  • 使用Collections.sort()方法对每个玩家手中的牌进行排序
  • 排序是对牌的编号进行排序,方便后续显示
  • 创建新的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-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

职责:表示一张扑克牌

  • 属性:
    • color(花色):字符串类型
    • point(点数):字符串类型
    • index(编号):整型
  • 功能:
    • 构造方法:初始化一张牌
    • toString方法:返回牌面字符串
    • 实现Comparable接口:用于排序

职责:管理一副完整的扑克牌

  • 属性:
    • cards:Card类型的ArrayList
    • 花色和点数的常量数组
  • 功能:
    • 初始化54张牌
    • 洗牌方法
    • 发牌方法

职责:管理玩家信息和手牌

  • 属性:
    • name:玩家名称
    • hand:存储手牌的ArrayList
  • 功能:
    • 接收牌
    • 整理手牌
    • 显示手牌

职责:控制游戏流程

  • 属性:
    • 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

相关内容