Java實現微信、QQ等羣主發紅包實例(拼手氣紅包)


前幾天,我更新了一個十分有趣的發紅包案例:普通紅包案例

今天,我對它進行了改進和更新

使它能夠真正模擬現實生活中社交環境下的發紅包場景!


分析:

在現實生活中,往往發手氣紅包比發普通紅包的頻率要大很多,而且,當人們點擊拼手氣紅包時的樂趣也遠遠高於普通紅包,人們在獲得不同收益的同時,也在比較別人的手氣,那麼,真正是自己或者別人在開紅包的手氣好嗎,還是另有原因呢?

其實,這都與我們所學過的隨機數有很大原因!

在這個案例中,和上次一樣,我們設想羣主發紅包自己是不能搶的,在剩下的羣成員中,大家可以隨機選擇一個紅包,爲了真實模擬,我們做兩次模擬:

第一次:發紅包的個數剛好與羣成員個數相同,即每個人都可以獲得一個紅包,且紅包的大小不少於0.01

第二次:發紅包的個數少於羣成員,即不是每個人都能獲得紅包,其中有人開出的是空包。

金額是隨機的,但是最多的不能太多,不超過總金額的一半(這是生活中搶紅包幾乎99.9%的概率下發生的,不考慮極端情況),羣主在發完錢後,羣成員在收到紅包後更新錢包。


實現:

首先,我們定義用戶類User

其中有用戶名和餘額,還有相應構造方法。

public class User {
    // 成員變量
    private String username; // 用戶名
    private double leftMoney; // 餘額,有角和分
 
    // 構造方法
    public User() {
    }
 
    public User(String username, double leftMoney) {
        this.username = username;
        this.leftMoney = leftMoney;
    }
    
    // get/set方法
    public String getUsername() {
        return username;
    }
 
    public void setUsername(String username) {
        this.username = username;
    }
 
    public double getLeftMoney() {
        return leftMoney;
    }
 
    public void setLeftMoney(double leftMoney) {
        this.leftMoney = leftMoney;
    }
 
    // 展示信息的方法
    public void show() {
        System.out.println("用戶名:"+ username +" , 餘額爲:" + leftMoney + "元");
    }
}

其次,定義羣主類Manager

對double類型小數點後兩位數提供了全新的解決方案;

思路明晰:對於發送紅包個數是否滿足羣成員需求寫出解決方案:當個數不足時,在紅包中加入等量空包,以滿足需求。

public class Manager extends User {
    // 添加構造方法
    public Manager() {
    }
 
    public Manager(String username, double leftMoney) {
        // 通過super 調用父類構造方法
        super(username, leftMoney);
    }
    
    public ArrayList<Double> send(double money, int count) {
        // 獲取羣主餘額
        double leftMoney = getLeftMoney();
        // 如果發出去的紅包大於羣主剩餘錢,則發送失敗
        if(money > leftMoney) {
            System.out.println("餘額不足!");
            return null;
        }
 
        // 創建一個集合,保存等份金額
        ArrayList<Double> list = new ArrayList<>();
    
        // 改進!解決小數後兩位問題
        double managerLast =(double)Math.round((leftMoney - money) * 100) / 100;
        super.setLeftMoney(managerLast);
        
        // 擴大100倍,相當於折算成'分'爲單位,避免小數運算損失精度的問題
        money *= 100;
        
        // 生成隨機數
        Random r = new Random();
        
        // 保存剩餘的金額以及計算分發出去紅包的份數
        int leftmoney = (int) money;
        int leftconut = count;

        // 隨機分配金額,每次分配的金額不大於總金額的50%,並將所分配的金額加入list紅包中
        for (int i = 0; i < count - 1; i++) {
            int setmoney = r.nextInt(leftmoney / leftconut * 2 ) + 1;
            double moneySetdouble = (double) Math.round(setmoney) / 100;
            list.add(moneySetdouble);
            leftmoney -= setmoney;
            leftconut --;
        }

        // 改進!解決小數後兩位問題
        double moneySetdouble = (double) Math.round(leftmoney) / 100;
        list.add(moneySetdouble);

        // 當紅包個數不能滿足分發的需求時,在紅包list中添加空包
        if(count<5){
            while(count++<5) {
                list.add(0.0);
            }
        }
        
        // 返回集合
        return list;
    }
}

然後,我們定義成員類Member

思路明晰:更新成員餘額:通過成員隨機選取一個紅包的方式,那麼就很好地避免了前面的人能拿到有金額的紅包,後面的人只能拿到空包的問題,用一種隨機的方式來控制羣成員拿紅包的先後順序,即拿到有金額的搶到紅包,空包的視爲沒有搶到紅包。

public class Member extends User {
    public Member() {
    }
    
    public Member(String username, double leftMoney) {
        super(username, leftMoney);
    }
    
    // 打開紅包,就是從集合中,隨機取出一份,保存到自己的餘額中
    public void receive(ArrayList<Double> list) {
    
    // 創建一個Random對象,隨機生成一個紅包編號
    int index = new Random().nextInt(list.size());
    
    // 從集合中移去相應編號,得到該編號的金額的紅包
    double delta = list.remove(index);
 
    // 當前成員本來有多少錢
    double money = super.getLeftMoney();
    
    // 改進!解決小數後兩位問題
    double last = (double) Math.round((money + delta) * 100) / 100;
        
    // 直接調用父類方法,設置到餘額
    super.setLeftMoney(last);
    }  
}

最後,寫執行程序,main函數執行:

先創建定義成員,顯示原信息,然後羣主發紅包,羣成員搶紅包,最後公佈搶紅包結果。

public class mainRedPacket {
        public static void main(String[] args) {
        // 創建一個羣主對象,五個成員
        Manager manager = new Manager("羣主", 266.66);
        Member one = new Member("成員A",105.63);
        Member two = new Member("成員B",5.62);
        Member three = new Member("成員C",0);
        Member four = new Member("成員D",23.4);
        Member five = new Member("成員E",3.21);

        // 顯示原始成員的餘額
        manager.show();
        one.show();
        two.show();
        three.show();
        four.show();
        five.show();
        System.out.println("==================");

        // 創建鍵盤錄入紅包金額和紅包個數
        Scanner sc = new Scanner(System.in);
        System.out.println("請輸入發送紅包的金額:");
        double money= sc.nextDouble();
        System.out.println("請輸入發送紅包的份數:");
        int count = new Scanner(System.in).nextInt();
        ArrayList<Double> list = manager.send(money,count);
        System.out.println("==================");
        
        // 顯示紅包內的金額數(上帝視角)
        System.out.println("紅包爲:" + list);
        
        // 開始搶紅包
        one.receive(list);
        two.receive(list);
        three.receive(list);
        four.receive(list);
        five.receive(list);

        // 搶到紅包,顯示餘額信息
        manager.show();
        one.show();
        two.show();
        three.show();
        four.show();
        five.show();
    }

}

結果展示:

第一種情況:發紅包的個數剛好與羣成員個數相同,即每個人都可以獲得一個紅包,且紅包的大小不少於0.01元。

第二種情況:發紅包的個數少於羣成員,即不是每個人都能獲得紅包,其中有人開出的是空包。

第三種情況:餘額不足,羣主未能發紅包!

至此,三種情況均能成功演示


思考:

在異常處理上沒有很好地下功夫,還可以改進;

讀者還可以製作用戶圖形界面,更生動形象地展示整個流程;

在分發紅包上還有一種多線程的處理方式也可以加以運用,讀者可以自行嘗試解決,博主不再進行演示。

 

感謝您的閱讀,不足之處歡迎指正!

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章