java 紅包規則
拼手氣紅包:
規則:最大金額:全部金額/個數*倍數
最小金額:0.01
最后一個紅包是全部金額-領取金額
隨機分配
package com.utils; import java.math.BigDecimal; import java.math.RoundingMode; import java.util.ArrayList; import java.util.List; import java.util.Random; /** * 紅包分發工具類 * */ public class CashRedPackUtils { /** * 一個紅包最少拆分數量 */ public static final int REDPACK_MIN_QUANTITY = 1; /** * 一個紅包最多拆分數量 */ public static final int REDPACK_MAX_QUANTITY = 100; /** * 小數位長度 */ private static final int SCALE = 2; /** * 舍棄的小數位處理方式 */ private static final RoundingMode ROUNDING_MODE = RoundingMode.HALF_EVEN; /** * 紅包放大倍數 */ private static final BigDecimal TIMES = new BigDecimal("3"); /** * 單個紅包最小金額 */ public static final BigDecimal SINGLE_RED_MIN_MONEY = new BigDecimal("0.01"); /** * 單個紅包最大金額 */ // private static final BigDecimal SINGLE_RED_MAX_MONEY = new BigDecimal("100"); /** * 遞歸計算紅包金額時連續錯誤最大值,超過此次數將返回最小值 */ private static final int ERROR_MAX_NUM = 5; /** * 遞歸計算紅包金額連續錯誤次數初始值 */ private static final int ERROR_INIT_NUM = 1; /** * 計算金額時的小數位,1000代表3位小數 */ private static final int FRACTION_LENGTH = 1000; /** * 分發紅包 * @param redMoney 紅包總金額 * @param num 紅包數量 * @return */ public static List<BigDecimal> SplitRedPackes(BigDecimal redMoney, int num) {
List<BigDecimal> redInfoList = new ArrayList<>();
// 紅包有誤
if(num < REDPACK_MIN_QUANTITY || num > REDPACK_MAX_QUANTITY)
return redInfoList;
//校驗:金額大於0 if(redMoney.compareTo(BigDecimal.ZERO) != 1) { return redInfoList; } if(num <= 1) { redInfoList.add(redMoney); return redInfoList; } Random random = new Random(); for(int i = 0; i < num; i++) { // System.out.println("\n" + (i+1) + "個紅包信息:"); int surplusNum = num - i;//未分配金額紅包數量 BigDecimal curRedMoney = fightLuckRedPacked(redMoney, surplusNum, random, ERROR_INIT_NUM); redInfoList.add(curRedMoney); redMoney = redMoney.subtract(curRedMoney); // MandoAssert.notTrue(redMoney.compareTo(BigDecimal.ZERO) == -1, "紅包金額有誤"); // System.out.println("紅包金額:" + curRedMoney + ",剩余:" + redMoney); } return redInfoList; } /** * 拼手氣紅包 * @param redMoney 紅包金額 * @param num 紅包數量 * @param random 隨機數生成對象 * @param errorNum 錯誤測試 * @return 單個紅包金額 */ private static BigDecimal fightLuckRedPacked(BigDecimal redMoney, int num, Random random, int errorNum) { if(num <= 1) { return redMoney; } if(errorNum > ERROR_MAX_NUM) { //隨機金額產生錯誤次數超過上限,返回最小值 return SINGLE_RED_MIN_MONEY; } //每個紅包最大金額 = 剩余總金額 / 未分配金額紅包數量 * 紅包放大倍數 int avgRedMaxMoney = redMoney.divide(new BigDecimal(num), ROUNDING_MODE).multiply(TIMES).intValue() * FRACTION_LENGTH; BigDecimal curRedMoney = new BigDecimal(random.nextInt(avgRedMaxMoney) * 1.00 / FRACTION_LENGTH + "").setScale(SCALE, ROUNDING_MODE); if(curRedMoney.compareTo(SINGLE_RED_MIN_MONEY) == -1) { //紅包最小值判斷:小於最小紅包金額,重新計算 return fightLuckRedPacked(redMoney, num, random, ++errorNum); } /*if(curRedMoney.compareTo(SINGLE_RED_MAX_MONEY) == 1) { //紅包最大值判斷 return fightLuckRedPacked(curRedMoney, num, random, ++errorNum); }*/ //最少保留紅包金額 BigDecimal surplusMinRedMoney = SINGLE_RED_MIN_MONEY.multiply(new BigDecimal(num - 1)); //除當前紅包剩余金額 BigDecimal surplusRedMoney = redMoney.subtract(curRedMoney); if(surplusMinRedMoney.compareTo(surplusRedMoney) == 1) { return fightLuckRedPacked(redMoney, num, random, ++errorNum); } return curRedMoney; } public static void main(String[] args) { System.out.println(SplitRedPackes(new BigDecimal("100"), 20)); } }