美文网首页
抽奖逻辑

抽奖逻辑

作者: archerdu | 来源:发表于2019-08-21 18:09 被阅读0次
package com.example.luckdraw;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.SerializerFeature;
import lombok.Data;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.*;

/**
 * 抽奖逻辑
 */
public class LuckDrawBox {

    private static final Logger logger = LoggerFactory.getLogger(LuckDrawBox.class);

    /**
     * 抽奖
     *
     * @param users  抽奖用户
     * @param prizes 待分配的奖品奖品
     * @return 用户和奖品关联关系
     */
    public Map<User, Prize> drawPrize(List<User> users, List<Prize> prizes) {
        logger.info("LuckDrawBoxImpl drawPrize[抽奖] start users:{}, prizes:{}", users == null ? null : users.size(), prizes == null ? null : prizes.size());
        Map<User, Prize> result = new HashMap<>(users == null ? 0 : users.size());
        if (users == null || users.size() == 0 || prizes == null || prizes.size() == 0) {
            logger.info("LuckDrawBoxImpl drawPrize[抽奖] 用户或奖品不存在");
            return result;
        }
        // 奖品处理为奖品包装类
        List<PrizeWrapper> prizeWrappers = getPrizeWrappers(prizes);

        drawByPrizeProbability(users, result, prizeWrappers);

        logger.info("LuckDrawBoxImpl drawPrize[抽奖] end result:{}", JSON.toJSONString(result, SerializerFeature.DisableCircularReferenceDetect));
        return result;
    }

    /**
     * 抽人
     *
     * @param users  抽奖用户
     * @param prizes 待分配的奖品
     * @return 用户和奖品关联关系
     */
    public Map<User, Prize> drawPeople(List<User> users, List<Prize> prizes) {
        logger.info("LuckDrawBoxImpl drawPeople[抽人] start users:{}, prizes:{}, poolSize:{}", users == null ? null : users.size(), prizes == null ? null : prizes.size());
        Map<User, Prize> result = new HashMap<>(users == null ? 0 : users.size());
        if (users == null || users.size() == 0 || prizes == null || prizes.size() == 0) {
            logger.info("LuckDrawBoxImpl drawPeople[抽人] 用户或奖品不存在");
            return result;
        }
        // 奖品处理为奖品包装类
        List<PrizeWrapper> prizeWrappers = getPrizeWrappers(prizes);
        // 抽奖用户放入到奖池
        List<User> usersPool = new ArrayList<>(users);
        // 抽人
        Random random = new Random();
        int seed;
        for (PrizeWrapper item : prizeWrappers) {
            for (int i = item.getStart(), length = item.getEnd() + 1; i < length; i++) {
                if (usersPool.size() == 0) {
                    break;
                }
                seed = random.nextInt(usersPool.size());
                // 中奖用户
                logger.info("LuckDrawBoxImpl drawPeople[抽人] 用户 {} 抽中奖品 {}", usersPool.get(seed).getPin(), item.getPrize().getName());
                result.put(usersPool.get(seed), item.getPrize());
                // 移除中奖用户 暂不考虑多次中奖机会
                usersPool.remove(usersPool.get(seed));
            }
        }
        logger.info("LuckDrawBoxImpl drawPeople[抽人] end result:{}", JSON.toJSONString(result, SerializerFeature.DisableCircularReferenceDetect));
        return result;
    }

    /**
     * 处理为奖品包装类
     *
     * @param prizes 奖品
     * @return 奖品包装类
     */
    private List<PrizeWrapper> getPrizeWrappers(List<Prize> prizes) {
        List<PrizeWrapper> prizeWrappers = new ArrayList<>(prizes.size());
        int prizePoint = 0;
        for (Prize item : prizes) {
            // 剩余奖品数量
            int remainder = item.getQuantity() - item.getWinningQuantity();
            logger.info("LuckDrawBoxImpl drawPrize[抽奖] {} 剩余奖品数量 {}", item.getName(), remainder);
            if (remainder == 0) {
                continue;
            }
            PrizeWrapper prizeWrapper = new PrizeWrapper();
            prizeWrapper.setStart(prizePoint);
            // 下一个奖品的开始点
            prizePoint += remainder;
            prizeWrapper.setEnd(prizePoint - 1);
            prizeWrapper.setPrize(item);
            prizeWrappers.add(prizeWrapper);
        }
        return prizeWrappers;
    }

    /**
     * 基于奖品概率抽奖,每个奖品独立抽奖机会
     *
     * @param users         用户
     * @param result        抽奖结果
     * @param prizeWrappers 奖品包装类
     */
    private void drawByPrizeProbability(List<User> users, Map<User, Prize> result, List<PrizeWrapper> prizeWrappers) {
        // 默认奖池基数
        int poolSize = 1000000;
        Random random = new Random();
        for (User user : users) {
            Prize winnerPrize = null;
            for (PrizeWrapper prizeWrapper : prizeWrappers) {
                int seed = random.nextInt(poolSize);
                if (prizeWrapper.quantity > 0 && seed < prizeWrapper.getPrize().getProbability()) {
                    winnerPrize = prizeWrapper.getPrize();
                    prizeWrapper.quantity--;
                    break;
                }
            }
            if (winnerPrize != null) {
                logger.info("LuckDrawBoxImpl drawPrize[抽奖] 用户 {} 抽中奖品 {}", user.getPin(), winnerPrize.getName());
            } else {
                logger.info("LuckDrawBoxImpl drawPrize[抽奖] 用户 {} 没有抽中奖品", user.getPin());
            }
            result.put(user, winnerPrize);
        }
    }

    /**
     * 基于基数抽奖,奖品数量代表不同的机会
     *
     * @param users         用户
     * @param poolSize      奖池基数
     * @param result        抽奖结果
     * @param prizeWrappers 奖品包装类
     */
    private void drawByBaseNumber(List<User> users, int poolSize, Map<User, Prize> result, List<PrizeWrapper> prizeWrappers) {

        // 默认奖池基数
        if (poolSize == 0) {
            poolSize = 10000;
        }
        // 开始抽奖
        Random random = new Random();
        for (User user : users) {
            int seed = random.nextInt(poolSize);
            Prize winnerPrize = null;
            for (PrizeWrapper prizeWrapper : prizeWrappers) {
                if (seed >= prizeWrapper.getStart() && seed <= prizeWrapper.getEnd()) {
                    winnerPrize = prizeWrapper.getPrize();
                    break;
                }
            }
            if (winnerPrize != null) {
                logger.info("LuckDrawBoxImpl drawPrize[抽奖] 用户 {} 抽中奖品 {}", user.getPin(), winnerPrize.getName());
            } else {
                logger.info("LuckDrawBoxImpl drawPrize[抽奖] 用户 {} 没有抽中奖品", user.getPin());
            }
            result.put(user, winnerPrize);
        }
    }

    /**
     * 奖品包装类
     */
    @Data
    private class PrizeWrapper {
        private int start;
        private int end;
        private int quantity;
        private Prize prize;
    }

    /**
     * 用户
     */
    @Data
    private class User {
        private String pin;
        private String name;
    }

    /**
     * 奖品
     */
    @Data
    private class Prize {
        private String name;
        private int quantity;
        private int winningQuantity;
        private int probability;
    }
}

抽奖ER图.drawio
<mxfile modified="2019-07-05T06:27:35.573Z" host="www.draw.io" agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) draw.io/8.8.0 Chrome/61.0.3163.100 Electron/2.0.2 Safari/537.36" etag="nJc6-QYmv5ewmsKv2WCB" version="10.8.9" type="device"><diagram id="3K_Z6mexA1ALRj9mF4yM" name="Page-1">7Vtbc6s2EP41ejwd7pdHwE7amZzOmebhzPRNAdmokZEH5NjOr68EAgzIsXNiG0+L40nQshLSfrurT0IBZrTaPeZwnX6nCSLA0JIdMGfAMHTTt/gfIdlXEs+QgmWOE6nUCp7xO5JCTUo3OEFFR5FRShhed4UxzTIUs44M5jnddtUWlHSfuoZLNBA8x5AMpT9xwtJ6FG4r/x3hZVo/WXf86s4K1spyJEUKE7o9EJlzYEY5pay6Wu0iRITxartU9R6O3G06lqOMnVNhtXlNfv65edx923uP7wn5e/YH+mY6snNsX48YJdwAskhzltIlzSCZt9Iwp5ssQaJZjZdanSdK11yoc+E/iLG9RBNuGOWilK2IvFuwnL6iiBKal880tfLT3KktLXSr/olOHR23FBV0k8fog8HW/gPzJWIf6ZkNPNyvEV0hlu95xRwRyPBbtyNQOtiy0Wsx4BcShk9AItt9g2QjnwTmDvACEM7A3AaBDXwHzF3AIyvwylseCN0BjMUWrwjMBF4LmrEaUWHkOMUkeYJ7uhFWKBiMX+tSmNIcv3N92GIFcyaRNBzRGiakhi6j5QPaSs+iMfmYHBW82o8aKL0n+g53HcUnWLC6g5QQuC7wS9llUXHFMcNZSBmjK6kkzYRyhnYfu8YQSVnB4qYrq8jkpDuyie1BqMvwTQ+i3PWuhL0xwH6NswG0fMBsEEUSCgU6kOBlxosELUQ1YTHME1wgxUwEbVisYYyz5VOpM7NayV9y2EJEed0FKZNYipMEZWUyYJDBl8a51hRnrLSLHfIvt16k/WYDm3c84mW9LfOvUM9ZRDM+FohL0BB3gy0SrnAewsdjaAi7hNlwzkK5Vrt8hA9hVoW4A4IIBLq48G0QapMfXNgPbGNcP7AVbmAD7wEEDwp/GMzThHASJIDlzGIthAndcPvPG/nBjJvAIm1m7G2KGRKwikpbztuEcxTrij4t8E4odhyIz9CLBXLiWDV3J67/ol0oIdt2NyFb1gAhR4FQLbs4Qo4SoXAOPPsAIQuEgfiOjdDCOIKQ8+LYzoUQ8ntTpqaNC5GrgMgHnlmSI1uQI8+5v2jyYqTG6sWzLftC0eTofXrjj4uVpw4nF4SqCXBciJCe2MhVQeQ7rgmvFE6G6Y0LUb3u7mEU8BxXM5GaNI8XPbb4UUHjlB+55DmQV5/rzFGGP6STt4XMPJNOhhzEsEyKgciO04rx8+DrjtVNqdYwXlUcUtesa6FvKdHvYc0vfA14M7FxELjTYuKXFhNHtoXuZVWpWk4MHcEVibyS+JzHhpMjXNoRxl5W6upVC1+yhCaYcz6si71DTpJ9V6YGvnbxhzuIkyN80RHc8+aGqzmCaQyJ2n93c1868L3v7qvWqw1H479NEZ8TNfs8NTPsLjUz9eHm0U0383X1crefh0/y8ikPn8zD7n0zM/+cmJ+Y2dUdYWxmZlr/owm5Oa5xckI+AtptJmTTnjA5+8XZbSCpG+7kSz5HeiA43NDixbnYyRALmJnYmJxY0+dZU3NA615Yk2EowD952mWaGk9Njcf84E44kqHaxD65Lppg/yLsYzMiQ7177UfA8+/mddNNXtb2j6IZI78INNSnU6YXgccQM7Th4cHbIqbYb+jjE2/yt9Lkwv4oSwJxRJoXYwKLAscqklpTUfW7cD+KHh4+QVKH1jwwl60wVy07m3rKJ/wQ2bcFy9F6aPXex1XUWVZqgRi20ztTYbq9hipqPWiIGxruD9Tk5HC0v+7gaKrVc5CqxdZdGpN+wYMUGxWTBx1L0MaveVA/bbi9di7kQGavu57xFf/hxfY/FSr19v89zPm/</diagram></mxfile>

相关文章

  • 抽奖逻辑

    抽奖ER图.drawio

  • 抽奖的逻辑

    看到广场上很多人在简书的抽奖活动中抽中了1万加成卡。今天我很幸运,第一反应不是高兴,而是截图,这或许是一个素材。 ...

  • js实现老虎机数字抽奖功能——微信小程序

    抽奖功能主要运用css动画及js控制动画逻辑,整体难度不大,完成整个抽奖逻辑功能需要比较严谨的逻辑,一以下是实现此...

  • 大宝之抽奖逻辑

    大宝他们舞蹈班昨天周年庆活动,每个小学员都参与了表演,在候场的时候都已经激情满满。 当然对舞蹈班来说,活动不失为一...

  • Excel实战:抽奖系统

    抽奖系统 本篇适合:有一定公式基础,主要是逻辑梳理。 QQ交流群:644328490。 需求:用excel制作抽奖...

  • 抽奖活动小程序开奖逻辑简析

    抽奖活动小程序开奖逻辑简析 ~ 今天是我的抽奖活动小程序第一个活动开奖的日子,我分享下具体的开奖逻辑,对我而言这是...

  • 抽奖小程序数据库设计

    今天在写新版抽奖小程序的抽奖逻辑,在这里记录下这个过程 抽奖活动集合目前设计有两个维度分别表示活动是否已过期,活动...

  • 基于Java的抽奖逻辑

    小组在做一个抽奖系统,现在给我分配到了抽奖逻辑这方面的实现。EMMM,拿到分配的时候是懵B的。 追加: 没有多余讲...

  • Vue中可配置的圆形抽奖转盘组件

    一、整个抽奖流程的思路分析: 点击了转盘正中间的指针(即开始抽奖按钮),判断是否可以转动(具体逻辑封装在canBe...

  • 抽奖大转盘产品逻辑

    最近几天都在研究抽奖的概率还有奖品首次出现的时间,这个概率和首次出现的时间应该是由运营部门来决定的,但公司没有运营...

网友评论

      本文标题:抽奖逻辑

      本文链接:https://www.haomeiwen.com/subject/syiisctx.html