【Java学习笔记】模拟微信拼手气红包的案例

    技术2022-07-10  89

    【Java学习笔记】模拟微信拼手气红包的案例

    参考百度文库:微信红包随机金额生成算法模拟及应用中关于微信拼手气红包随机算法的叙述。

    Java SE已经粗略的学习了一遍,我对其中的微信红包模拟颇感兴趣,今天花时间实现了均等金额的普通红包及随机金额的拼手气红包,明天继续围绕红包案例,讨论两种常见的玩法。

    我编写了一个User类,这个类中含有2个私有字段,其中用分表示钱的数量:

    private String name; //用分来表示钱,避免使用浮点类型表示 private int moneyCountByCents;

    这个类中含有一个私有方法,用于将用分表示的钱转换为用元表示:

    //用于返回字符串类型的,用元表示的钱数,一直精确2位小数的私有方法 private String turnYuan(int moneyCountByCents) { String str = new String(); str += (moneyCountByCents/100); str += "."; str += (moneyCountByCents%100/10); str += (moneyCountByCents%10); return str; }

    设定User类的对象,既能发红包,也能抢红包。其中红包类型又分为普通红包与拼手气红包。

    首先是发普通红包的方法:

    //用于发普通红包的方法 public ArrayList<Integer> sendUsualRedPacket(int num,int moneyCountByCents) { ArrayList<Integer> redPacket = new ArrayList<>(); //一个判断,如果User要发的红包总金额大于自己剩余的钱,那么就把红包总金额赋值为自己剩余的钱 //如果User要发的红包总金额大于自己剩余的钱,那么就把红包总金额赋值为自己剩余的钱 //如果User要发的红包总金额大于自己剩余的钱,那么就把红包总金额赋值为自己剩余的钱 if (this.moneyCountByCents >= moneyCountByCents) { this.moneyCountByCents -= moneyCountByCents; }else if (this.moneyCountByCents < num){ System.out.println(this.name + "现在只有" + turnYuan(this.moneyCountByCents) + "元钱,已经没法给在座的各位发红包了。"); return null; }else { moneyCountByCents = this.moneyCountByCents; this.moneyCountByCents = 0; } System.out.println(this.name + "发了一个普通红包,总金额为:" + turnYuan(moneyCountByCents) + "元。\t" + this.name + "现在还有" + turnYuan(this.moneyCountByCents) + "元钱"); //普通红包的规则是,除了最后一个红包,其他红包内为总金额平均数向下取整, //最后一个红包为平均数向下取整加上零头 int avgMoney = moneyCountByCents/num; int remMoney = moneyCountByCents%num; for (int i = 0; i < num-1; i++) { redPacket.add(avgMoney); } redPacket.add(avgMoney + remMoney); return redPacket; }

    其次是发拼手气红包的方法:

    //用于发拼手气红包的方法 public ArrayList<Integer> sendRandomRedPacket(int num,int moneyCountByCents) { ArrayList<Integer> redPacket = new ArrayList<>(); Random random =new Random(); //一个判断,如果User要发的红包总金额大于自己剩余的钱,那么就把红包总金额赋值为自己剩余的钱 //如果User要发的红包总金额大于自己剩余的钱,那么就把红包总金额赋值为自己剩余的钱 //如果User要发的红包总金额大于自己剩余的钱,那么就把红包总金额赋值为自己剩余的钱 if (this.moneyCountByCents >= moneyCountByCents) { this.moneyCountByCents -= moneyCountByCents; }else if (this.moneyCountByCents < num){ System.out.println(this.name + "现在只有" + turnYuan(this.moneyCountByCents) + "元钱,已经没法给在座的各位发红包了。"); return null; }else { moneyCountByCents = this.moneyCountByCents; this.moneyCountByCents = 0; } System.out.println(this.name + "发了一个拼手气红包,总金额为:" + turnYuan(moneyCountByCents) + "元。\t" + this.name + "现在还有" + turnYuan(this.moneyCountByCents) + "元钱"); //最小的红包是1分钱 int minMoney = 1; int remMoney = moneyCountByCents - num * minMoney; int remNum = num; //这里参考了微信拼手气红包的随机算法,当前红包金额位于[0.01,2倍剩余平均金额]区间内。 for (int i = 0; i < num-1; i++) { int currentMoney =(int)(random.nextDouble() * 2 * remMoney/remNum - 1); redPacket.add(1 + currentMoney); remMoney -= currentMoney; remNum--; } redPacket.add(1 + remMoney); return redPacket; }

    最后是抢红包的方法:

    //抢红包的方法,利用ArrayList的remove方法 public void snatchRedPacker(ArrayList<Integer> redPacket) { int redPacketMoney = redPacket.remove(0); this.moneyCountByCents += redPacketMoney; System.out.println(this.name + "抢到了一个红包,金额为:" + this.turnYuan(redPacketMoney) + "元。\t" + this.name + "现在一共有" +this.turnYuan(this.moneyCountByCents)+ "元钱。"); }

    为了实现固定轮数的发/抢红包,利用for循环语句和ArrayList实现:

    //常数TOTAL_MONEY为所有User对象赋值 public static final int TOTAL_MONEY = 10000; public static void main(String[] args) { ArrayList<User> userArrayList = new ArrayList<>(); userArrayList.add(new User("曹操",TOTAL_MONEY)); userArrayList.add(new User("大乔",TOTAL_MONEY)); userArrayList.add(new User("小乔",TOTAL_MONEY)); ArrayList<Integer> redPacket = new ArrayList<>(); Random random = new Random(); //循环发红包,这里做了一个判断,如果某个User对象没钱了则结束发红包循环。 boolean isPool=true; for (int i = 0; isPool && i<30; i++) { System.out.println("第" + (i+1) + "轮:"); redPacket = userArrayList.get(i%userArrayList.size()) .sendRandomRedPacket(userArrayList.size(), userArrayList.size()+random.nextInt(TOTAL_MONEY -userArrayList.size())); if(redPacket != null){ for (int j = 0; j < userArrayList.size(); j++) { userArrayList.get(j).snatchRedPacker(redPacket); } }else { isPool = false; } System.out.println("------------------------------------------------------"); } }

    请大神们不吝赐教!20200630

    Processed: 0.028, SQL: 9