瓜分游戏币,红包拆分正态分布

本文探讨了如何用平均和随机方式瓜分游戏币给参与者,介绍了使用Redis缓存、列表与字符串数据结构,模拟微信红包算法,以及两种分配策略下的代码实现。重点在于确保公平性和效率,通过改变分配思路实现更均衡的分布。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

背景

需要做一个给每个人参加活动的人瓜分固定奖池的游戏币,有平均瓜分和随机分2种分配方案。

平均瓜分

平均分很简单,就是总money/总person取整数就行,无论整除不整除,不整除有结余也无所谓。

随机瓜分

需求详情

根据一个时间段的参与人数设置一个总游戏币数,所有人进行瓜分,每个人最少获得一个币,同时可以无限次重新随机计算,计算出来的列表进行分页展示,而且支持对单个人获得币进行修改,然后统一生成奖励。

思路

  1. 可以多次进行重新随机计算,所以不能直接将计算的结果持久化,防止大量操作删表新增操作,所以先保存数据到redis中做缓存
  2. 在缓存中需要做分页查询,类似查询榜单,list,zset类型可实现分页查询,不需要每次查询都将所有数据拉出来进行分页筛选,zset占用空间大,而且也不需要格外的value做实时排列。所以暂时选用list做存储类型
  3. 缓存中需要保存用户与随机得到的游戏币的对应,选用person+分隔符+币 的String拼接实现
  4. 需要针对一个用户获得币进行修改,list类型可根据下标索引进行修改,可支持
  5. 计算出来后,每个用户对应一个随机游戏币,需要按币的大小进行排序,存入redis,重写list,String排序实现

代码实现

涉及的redis操作(简化)

jedis.lpush(key,value); //存放key,value value是可变类型,LPUSH mylist a b c
jedis.lrange(key, startNumber, endNumber);//查询
jedis.lset(key,index,value); //根据index进行修改
jedis.lindex(key, index); //根据当前index获取list中的值
随机算法工具类
  1. 模拟微信红包算法(简单实现)
    1. 每个人最少得到1游戏币,所以先给每个人分配一个游戏币,保证在随机下每个人所得不为0

    2. 随机每个人所得范围在(0-money / people * 2)

    3. 同时利用Random产生的随机数固定种子下产生的随机序列数相同来排查记录。

    4. 当前利用微信抢红包不需要一次性将整个分布计算下来,可以在每个人领红包的时候再进行计算

    5. 利用excel工具直观查看随机数分布是否满足预想在这里插入图片描述

    6. 废话不多说,贴代码:

@Test
    public void randTestTest(){
        randTest(1000,100);
    }

    public static void randTest(int sum,int count){
        List<Integer> list = new ArrayList<>();
        sum = sum-count*1;
        Random random = new Random();
        long factor = System.currentTimeMillis();
        System.out.println("固定种子是:"+factor);
        random.setSeed(factor);//当random设置相同的种子时,随机序列数相同
        for(int i = 0;i<count;i++){
            int rand = rand(sum, count-i, list,random);
            sum = rand;
        }
        int summoneny = 0;
        int min =list.get(0);
        int max =-1;
        for(Integer entry :list){
            summoneny = summoneny+entry.intValue();
            min = Math.min(min,entry.intValue());
            max = Math.max(max,entry.intValue());
        }
        System.out.println(list.toString());
        System.out.println(min);
        System.out.println(max);
    }

    /**
     *
     * @param money 剩余的钱
     * @param people 剩余的人数
     * @param l   红包列表
     * @return
     */
    public static int rand(int money, int people, List<Integer> l ,Random random) {
        if (people == 1) {
            int red = money;
            l.add(red+1);
            return 0;
        }
        int min = 0;
        int max = money / people * 2;
        int red = random.nextInt(max);
        red = red <= min ? min : red;
        l.add(red+1);
        int remain = money-red;
        return remain;
    }
  1. 以上思想是每个人口袋能得到多少游戏币,随机在奖池中取钱。现我们转变一下思想,利用游戏币找口袋,游戏币随机落入口袋。
    1. 分布图展示,看起来后者分布更加均匀在这里插入图片描述

    2. 利用钱找人,有可能一个人没有被找过一次,当然可以先给每个人先分一个游戏币,然后剩下的币找人,上代码

 @Test
    public void rand1Test(){
        Random random = new Random();
        long factor = System.currentTimeMillis();
        System.out.println("固定种子是:"+factor);
        random.setSeed(factor);//当random设置相同的种子时,随机序列数相同
        int[] ints = rand1(1000, 100, random);
        int a = 0;
        int min =ints[0];
        int max =-1;
        for (int integer : ints) {
            a+=integer;
            min = Math.min(min,integer);
            max = Math.max(max,integer);
        }
        System.out.println(Arrays.toString(ints));
        System.out.println(a);
        System.out.println(min);
        System.out.println(max);
    }

    /**
     *
     * @param money 总钱
     * @param count 剩余的人数
     * @return
     */
    public int[] rand1(int money, int count ,Random random) {
        int[] nums = new int[count];
        for(int i= 0;i<money;i++){
            int person = random.nextInt(count);
            nums[person] +=1;
        }
        return nums;
    }
重写排序工具类
 public static void sortListString(List list){
        System.out.println("排序前:"+list.toString());
        Collections.sort(list, new Comparator<String>() {
            @Override
            public int compare(String o1, String o2) {
                return Integer.valueOf(o1.substring(o1.indexOf(":")+1,o1.length()))
                        .compareTo(Integer.valueOf((o2.substring(o2.indexOf(":")+1,o2.length()))));
            }
        });
        System.out.println("排序后:"+list.toString());
    }

总结

  1. 整个过程也看过网上很多介绍正态分布的算法,还有网上各位大神的分析与实现,以上是一个简单的实现同时也很好的契合要求,故实现如此,作此记录。
  2. 在redis的操作文档中只发现如下的存储方式,RPUSH mylist a b c,所以选择String作为载体进行存储,当然可以选择list中保存可序列化对象,将对象序列化后再保存到redis中,可以添加更多的属性。由于时间问题并未依此方案实现。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值