fei-ke
6/18/2015 - 6:47 PM

红包生成算法

红包生成算法

import java.util.ArrayList;
import java.util.List;
import java.util.Random;

/**
 * Created by fei-ke on 2015/6/18.
 */
public class RedPackAmountGenerator {
    private int mFloor;         //下限
    private int mCeiling;       //上限
    private int mCount;         //数量
    private int mTotal;         //金额

    private int mCurrent;        //当前游标

    /**
     * @param total      金额
     * @param count      总个数(为0时自动根据上下限估算个数)
     * @param floor      下限
     * @param ceiling    上限
     * @param floatRange 浮动范围(在平均值左右浮动的范围)
     */
    public RedPackAmountGenerator(int total, int count, int floor, int ceiling, float floatRange) {
        this.mTotal = total;
        this.mCount = count;

        int avg;
        if (count != 0) {
            avg = total / count;
        } else {
            avg = (floor + ceiling) / 2;
            this.mCount = total / avg;
        }

        this.mFloor = Math.max(floor, (int) (avg - avg * floatRange));
        this.mCeiling = Math.min(ceiling, (int) (avg + avg * floatRange));

        this.mCurrent = 1;
    }

    /**
     * 产生下一个随机数
     *
     * @param current    当前第几个人(从1开始)
     * @param leftAmount 剩余金额
     * @return
     */
    public int next(int current, int leftAmount) {
        this.mCurrent = current;
        this.mTotal = leftAmount;

        Range range = curRange();
        if (range.ceiling == range.floor) return range.ceiling;

        Random r = new Random();
        //nextInt范围为左闭右开区间,右值+1
        int next = r.nextInt(range.ceiling + 1 - range.floor) + range.floor;

        this.mTotal -= next;
        this.mCurrent++;
        return next;
    }

    /**
     * 检查金额人数上下限和浮动范围是否合理
     *
     * @return
     */
    public boolean isOK() {
        return mTotal >= mCount * mFloor && mTotal <= mCount * mCeiling;
    }

    /**
     * 产生下一个随机数,当前人数和剩余金额由内部记录
     *
     * @return
     */
    public int next() {
        return next(mCurrent, mTotal);
    }

    /**
     * 一次性生成所有随机数
     *
     * @return
     */
    public List all() {
        ArrayList list = new ArrayList();
        for (int i = mCurrent; i <= mCount; i++) {
            int next = next();
            list.add(next);
        }
        return list;
    }

    /**
     * 计算本次随机的范围
     */
    private Range curRange() {
        //本次生成之后剩余个数
        int leftCount = mCount - mCurrent;
        if (leftCount == 0) {
            return new Range(mTotal, mTotal);
        }
        //需要剩下最少的值
        int minLeft = leftCount * this.mFloor;
        //需要剩下最大的值
        int maxLeft = Math.min(leftCount * this.mCeiling, mTotal - this.mFloor);

        //本次随机的下限:max(本次可取最小值,基本下限,浮动范围下限)
        int rangeFloor = Math.max(mTotal - maxLeft, this.mFloor);
        //本次随机的上限:min(基本上限,本次可取最大值,浮动范围上限)
        int rangeCeiling = Math.min(this.mCeiling, mTotal - minLeft);

        return new Range(rangeFloor, rangeCeiling);
    }

/*    static int min(int... nums) {
        int min = nums[0];
        for (int i = 1; i < nums.length; i++) {
            if (nums[i] < min) {
                min = nums[i];
            }
        }
        return min;
    }

    static int max(int... nums) {
        int max = nums[0];
        for (int i = 1; i < nums.length; i++) {
            if (nums[i] > max) {
                max = nums[i];
            }
        }
        return max;
    }*/

    /**
     * 随机范围辅助类
     */
    private static class Range {
        int floor;    //下限
        int ceiling;  //上限

        public Range(int floor, int ceiling) {
            this.floor = floor;
            this.ceiling = ceiling;
        }
    }

    public static void main(String[] args) {
        int amount = 500;
        int person = 40;
        RedPackAmountGenerator generator = new RedPackAmountGenerator(amount, person, 1, 200, 0.8f);
        System.out.println("amount:" + amount + ", person:" + person);
        if (!generator.isOK()) {
            System.out.println("不合理");
            return;
        }
        System.out.println(generator.all());
    }
}