抽奖/大转盘/扭蛋(随机数法)工具类

算法思想

        这种算法思想最为简单。将n个奖品编号0 - N-1,其中各类奖品的概率通过其数量体现,最后程序产生0~n-1之间的随机数便是抽中的奖品编号。例如:
        苹果手机概率1%,网站会员20%,折扣券20%,很遗憾59%。这样,编号0是苹果手机,1-20是会员,21-40是折扣券,41~100是 很遗憾。产生的随机数落在那个区间,就代表那个奖品被抽中。

存在问题

1、总数N快速膨胀

        概率通过数量来体现在各个奖品概率较大的情况下,总数n可以较小。但如果在精度很高的情况下,总数必须按比例成倍扩大。
        例如,所有奖品概率都是10%,那么n只需要取10就可以。但是如果某个奖品概率是0.01%,按照这种算法,总数要扩大到100*100。

2、平衡性影响

        在Java中,Math.random()方法本身基本可以保证大量测试的情况下避免高重复,且概率分布比较平均。但是需要注意的是,该方法默认返回0-1之间的数据。
        在当前算法中,必须扩大指定倍数并且强制使用int进行类型转换。在这样的扩大和转换过程中,必然会对数据精度进行修改,转换后的数据也不能保证概率分布平均。
因此,该算法实际可能达不到预期的概率要求。

3、算法复杂度

数据准备阶段,为每个奖品确定编号与奖品信息的关系集合需要O(n);
产生随机数阶段并转换,O(1);
从集合中查找,不同的数据结构实现不同,最差需要O(n);

/**
     * 获取正式的计算map
     * @param prizeAmountMap    金额:百分比(int)
     * @param prizeTotalCountMap    金额:总共可发个数
     * @param prizeRealCountMap     金额:实际已发个数
     * @return
     */
    public static Map<Integer, Integer> getPrizeAmountMap(Map<Integer, Integer> prizeAmountMap, Map<Integer, Integer> prizeTotalCountMap, Map<Integer, Integer> prizeRealCountMap) {
        Iterator<Map.Entry<Integer, Integer>> it = prizeAmountMap.entrySet().iterator();
        while(it.hasNext()){
            Map.Entry<Integer, Integer> prizeItem = it.next();
            Integer prizeRealCount = prizeRealCountMap.get(prizeItem.getKey());
            Integer prizeTotalCount = prizeTotalCountMap.get(prizeItem.getKey());
            if(prizeRealCount >= prizeTotalCount){
                it.remove();
            }
        }
        return prizeAmountMap;
    }

    /**
     * 采用随机数抽奖方式 - 产生一个中奖金额(int)
     * @param prizeAmountMap
     * @return
     */
    public static Integer getPrizeAmount(Map<Integer, Integer> prizeAmountMap) {
        //初始化中奖金额
        Integer prizeAmount = (Integer) prizeAmountMap.keySet().toArray()[0];
        //遍历map获取概率int总和并且变形map的value
        Integer scaleSum = 0;
        for (Map.Entry<Integer, Integer> prizeItem : prizeAmountMap.entrySet()) {
            scaleSum += prizeItem.getValue();
            prizeAmountMap.put(prizeItem.getKey(), scaleSum);
        }
        //生成中奖随机数
        Integer prizeRand = new Random().nextInt(scaleSum);//[0,scaleSum)
        for (Map.Entry<Integer, Integer> prizeItem : prizeAmountMap.entrySet()) {
            if(prizeItem.getValue() > prizeRand){
                prizeAmount = prizeItem.getKey();
                break;
            }
        }
        return prizeAmount;
    }

    /**
     * 字符串转MAp
     * @param data
     * @return
     */
    public static Map<Integer, Integer> toIntegerMap(String data) {
        Map<Integer, Integer> integerMap = new LinkedHashMap<>();
        String[] itemArray = data.split(",");
        for(int i=0; i<itemArray.length; i++) {
            String[] itemData = itemArray[i].split(":");
            integerMap.put(Integer.valueOf(itemData[0]),Integer.valueOf(itemData[1]));
        }
        return integerMap;
    }


    public static void main(String[] args) {
        for(int i=0; i<10000; i++) {
            //为避免修改金额的问题,修改金额在数据上是增加项
            // 如188修改为168, 188:5000,288:3000,388:1500,688:500 -> 168:5000,188:0,288:3000,388:1500,688:500
            //188:500,288:400,388:300,688:100 -> 168:500-188已发数量,188:已发数量,288:400,388:300,688:100
            //获取需要计算的数据组装map
            String prizeAmountStr = "188:5000,288:3000,388:1500,688:500";
            Map<Integer, Integer> prizeAmountMap = toIntegerMap(prizeAmountStr);
            //采用随机数抽奖方式 - 后续需要若该金额奖励已经没有了,自动重新抽奖
            //共可发红包数量
            String prizeTotalCountStr = "188:500,288:400,388:300,688:100";
            Map<Integer, Integer> prizeTotalCountMap = JacksonUtil.toIntegerMap(prizeTotalCountStr);
            //实际已发红包数量
            Map<Integer, Integer> prizeRealCountMap = new LinkedHashMap<>();
            prizeRealCountMap.put(188, 450);
            prizeRealCountMap.put(288, 350);
            prizeRealCountMap.put(388, 250);
            prizeRealCountMap.put(688, 80);
            prizeAmountMap = getPrizeAmountMap(prizeAmountMap, prizeTotalCountMap, prizeRealCountMap);
            System.out.println(getPrizeAmount(prizeAmountMap));
        }
    }

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Vue扭蛋抽奖效果是一种基于Vue框架实现的具有互动性的抽奖效果。在这个效果中,参与者可以点击扭蛋按钮,然后蛋壳会随机转动一段时间,最终停止在一个奖品上。 实现这个效果的关键是利用Vue的动态绑定和过渡效果来实现扭蛋转动和停止的动画效果。首先,可以使用Vue的data属性来存储扭蛋的状态,例如设置一个变量isSpinning来表示是否正在旋转。当点击扭蛋按钮时,可以通过设置isSpinning为true来触发扭蛋的旋转动画。 在旋转动画方面,可以借助Vue的过渡效果来实现。可以使用transition组件来包裹扭蛋元素,并为其添加旋转动画的样式类。在data属性中添加一个变量,例如spinClass,用来控制旋转样式类的切换。在isSpinning为true时,将spinClass设置为启动旋转动画的样式类,当扭蛋停止旋转时,将spinClass设置为停止旋转的样式类。 为了使扭蛋停止在一个奖品上,可以使用Vue的计时器功能来控制扭蛋停止转动的时间。例如,在点击扭蛋按钮后,使用setTimeout函数设置一个定时器,当定时器到达指定的时间后,将isSpinning设置为false,停止扭蛋的旋转。 另外,为了实现随机停止在一个奖品上的效果,可以利用Vue的计算属性来生成随机数,并将该随机数与奖品索引绑定在一起。这样,当扭蛋停止旋转时,可以根据随机数获取对应的奖品信息,并展示在页面上。 综上所述,通过结合Vue的动态绑定、过渡效果和计时器功能,可以实现一个具有扭蛋抽奖效果的交互式页面。用户可以通过点击扭蛋按钮,享受扭蛋转动的动画效果,并在随机停止时获取奖品。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值