吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 2728|回复: 2
收起左侧

[会员申请] 申请会员ID:whmynb【申请通过】

[复制链接]
吾爱游客  发表于 2021-4-7 19:26
1、申 请 I D :whmynb  
2、个人邮箱:503268460@qq.com

前言
之前思考一个问题:微信的手气红包是如何实现的
怎么保证了所有人 无先后都有机会成为手气最佳

初次尝试
一开始的想法很简单,就是固定一个奖金池,因为要保证每个最低是有一分钱,所以把随机数的总金额减去剩下每人的0.01作为最高可以获取的红包金额,接着把奖金池减去刚生成的金额,当到最后一人时,直接去把剩余的金额全部给他
具体代码如下(金额的单位为分):
[Java] 纯文本查看 复制代码
public static List<Integer> redPackRand(Integer money,Integer peopleCount){
        List<Integer> result=new ArrayList<Integer>();
        for(int i=0;i<peopleCount;i++){
            if(i==peopleCount-1){//判断是不是最后一个人,是的话直接把所有金额全部给他
//                System.out.println("第"+(i+1)+"人,获得:"+money);
                result.add(money);
            }else {
                //取得随机的金额
                Integer getMoney =(int)((money-(peopleCount-i-1))*Math.random()+1);
//                System.out.println("第"+(i+1)+"人,获得:"+getMoney);
                //奖金池中减去取走的部分
                money-=getMoney;
//                System.out.println("当前剩余:"+money);
                result.add(getMoney);
            }
        }
        return result;
    }


测试
为了测试出红包算法的情况,我写了一个测试工具,可以循环测试N次,每次M个人,查看第1-M个人可以抢到多少钱的平均数
[Java] 纯文本查看 复制代码
//分别保存进来顺序信息的创建对象
static class PackeAvg{
            //保存所有金额数据
        List<Integer> list;
        public PackeAvg(){
            list=new ArrayList<>();
        }
                //为给列表添加金额
        public void addList(Integer a){
            list.add(a);
        }
        public List<Integer> getList() {
            return list;
        }
                //算出平均值
        public Integer getAvg() {
            if(list.size()!=0){
                int sum=0;
                for (int num:list){
                    sum+=num;
                }
                return sum / list.size();
            }
            return 0;
        }
    }

public static void redPackRandAvg(int forCount){
                   //用于保存次序信息的
        List<PackeAvg> avglist=new ArrayList<>();
            //循环次数forCount
        for(int i =0;i<forCount;i++){
            //300块钱10个人抢,单位是分
            List<Integer> list = redPackRand(30000, 10);
            //标记是第几个人
            int j=0;
            for (int num:list){
                if(avglist.size()<j+1)avglist.add(new PackeAvg());
                PackeAvg packeAvg = avglist.get(j);
                packeAvg.addList(num);
                j++;
            }
        }
        int i=1;
        for (PackeAvg avg:avglist){
            System.out.println("第"+i+"个人的平均红包为:"+avg.getAvg()+",具体为"+new Gson().toJson(avg));
            i++;
        }
    }

[Java] 纯文本查看 复制代码
public static void main(String[] arg){
        //调用20000次,看看评价情况
        redPackRandAvg(20000);
    }


结果为:

发现使用这种算法,第一次进来的人都是拿的红包大概率都是最大的,而最后抢到的大概率是最小的,而且从平均数可以看到第一个可以拿走奖金池中一半的红包,就算是按照此方法先分出红包存入数组,再让别人随机顺序领也不行,因为微信上没有出现过多人红包可以取走一半的情况(分的少不算啊)
第二次尝试
痛定思痛,因为第一次尝试发现自己想的过于简单了,当抢红包需要规定抢到的红包最大范围,我看到网上有一种是平均数x2的方法,就是100块10个人抢,第一个人可以抢到的是0.01~20块钱之间,而当红包剩下40人数还剩5人的话,下一个人可以拿到的是2*(40/5),就是0.01~16块钱,这样就可以保证红包不会一下子都被拿走,也能控制红包金额大小
为了方便,我这次专门写了一个类
[Java] 纯文本查看 复制代码
public class RedPackeg {
    //为总金额
    private Integer money;
    //剩余金额
    private Integer nowMoney;
    //红包分了多少份
    private Integer packSize;
    //取走了多少份
    private Integer packNum;
    //保存金额信息
        private List<Integer> moneyList=new ArrayList<>();
    public List<Integer> getMoneyList() {
        return moneyList;
    }
        //构造函数,初始化金额和红包份数
    public RedPackeg(Integer money,Integer packSize){
        this.money=money;
        this.nowMoney=money;
        this.packSize=packSize;
        this.packNum=0;

    }
        //取红包,当取完之后返回-1
    public Integer getRedPack(){
        if(packSize>packNum){
            Integer getMoney=(int)(((nowMoney/(packSize-packNum))*2)*Math.random()+1);
            //如果getMoney取走后,剩下的钱不够每人0.01的,就把除去没人0.01外的钱都给他
            if((nowMoney-getMoney)<(packSize-packNum))getMoney = nowMoney-(packSize+packNum);
            packNum++;
            nowMoney-=getMoney;
            //如果是最后一个人就把金额全部给他
            if(packSize==packNum)getMoney+=nowMoney;
            moneyList.add(getMoney);
            return getMoney;
        }
        return -1;
    }
    
    //测试单次抢红包,能不能保证把红包金额全部发完
    //第一次忘记考虑最后一人情况,金额并没有全发完
    public static void main(String[] pp){
        RedPackeg packeg=new RedPackeg(10000,10);
        for (int i=0;i<10;i++){
            System.out.println("第"+(i+1)+"个人,获得了"+packeg.getRedPack());
        }
        List<Integer> list = packeg.getMoneyList();
        int sum=0;
        for(int a:list){
            sum+=a;
        }
        System.out.println("红包总数:"+sum);
    }
}

测试结果,感觉好像达到了自己想要的效果,赶紧循环个几次试试看,看看次序的平均红包金额吧

准备多套了一个方法,为了可以偷懒复用之前的代码
[Java] 纯文本查看 复制代码
public static List<Integer> redPackGet(Integer money,Integer peopleCount){
        RedPackeg packeg=new RedPackeg(money,peopleCount);
            //从里面取10次钱,记录都会保存在list中
        for (int i=0;i<peopleCount;i++)packeg.getRedPack();
        return packeg.getMoneyList();
    }
public static void redPackAvg(int forCount){
        List<PackeAvg> avglist=new ArrayList<>();
        for(int i =0;i<forCount;i++){
            //只是改变了这里的一个方法
            List<Integer> list = redPackGet(30000, 10);
            int j=0;
            for (int num:list){
                if(avglist.size()<j+1)avglist.add(new PackeAvg());
                PackeAvg packeAvg = avglist.get(j);
                packeAvg.addList(num);
                j++;
            }
        }
        int i=1;
        for (PackeAvg avg:avglist){
            System.out.println("第"+i+"个人的平均红包为:"+avg.getAvg()+",具体为"+new Gson().toJson(avg));
            i++;
        }
    }
    public static void main(String[] arg){
        redPackAvg(20000);
    }


循环了20000次,结果非常的靠谱,基本上可以保证不管是第几个抢红包平均的金额都是差不多的

当循环次数到400000次的时候,金额几乎相差无几

小结
通过上面的代码,已经实现了微信抢红包的基本逻辑,可能和微信真正的红包方法完全不一样,这里只是写出了一个基础部分代码,给大家提供了一个小思路而已

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

Hmily 发表于 2021-4-9 10:11
I D:whmynb  
邮箱:503268460@qq.com

申请通过,欢迎光临吾爱破解论坛,期待吾爱破解有你更加精彩,ID和密码自己通过邮件密码找回功能修改,请即时登陆并修改密码!
登陆后请在一周内在此帖报道,否则将删除ID信息。
whmynb 发表于 2021-4-9 16:04
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-11-14 14:49

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表