using System; using System.Collections.Generic; [Serializable] /// /// 纯整数红包记录 /// 金额单位:分 (int) /// public class RedPacketRecord { public int Phase { get; set; } // 阶段:1 或 2 public int Index { get; set; } // 第几个包 public long Amount { get; set; } // 金额(单位:分,纯整数) // 方便调试看日志的格式化方法 public string GetMoneyString() { return (Amount / 100) + "." + (Amount % 100).ToString("D2"); } } /// /// 纯整数版级联红包算法(支持动态裂变个数) /// public class CascadeRedPacketInt { private Random _random; private const int MIN_AMOUNT = 1; // 最小 1 分钱 // --- 第一阶段配置 --- private int _phase1TotalAmount; // 总金额(分) private int _phase1Count; // 第一阶段总人数 private int _phase1Grabbed = 0; // 已抢人数 public CascadeRedPacketInt(int totalMoneyCents, int phase1Count, int? seed = null) { _random = seed.HasValue ? new Random(seed.Value) : new Random(); _phase1TotalAmount = totalMoneyCents; _phase1Count = phase1Count; } /// /// 核心方法:执行一次完整的“抢大包 -> 拆小包” /// /// 【动态参数】第二轮要裂变出的红包个数 /// 该用户最终获得的一堆小红包列表 public List GrabFullCycle(int subCount) { // 1. 第一阶段:从大奖池抢一个金额 int phase1Amount = GrabPhase1(); if (phase1Amount <= 0) return null; // 2. 第二阶段:把这个金额拆分成 subCount 个小包 return SplitPhase2(phase1Amount, subCount); } /// /// 第一阶段逻辑(不变) /// private int GrabPhase1() { if (_phase1Grabbed >= _phase1Count) return -1; int amount; int remainingCount = _phase1Count - _phase1Grabbed; if (_phase1Grabbed == _phase1Count - 1) { amount = _phase1TotalAmount; } else { int avg = _phase1TotalAmount / remainingCount; int max = avg * 2; int safeMax = _phase1TotalAmount - (remainingCount * MIN_AMOUNT); if (max > safeMax) max = safeMax; if (max < MIN_AMOUNT) max = MIN_AMOUNT; amount = _random.Next(MIN_AMOUNT, max + 1); } _phase1TotalAmount -= amount; _phase1Grabbed++; return amount; } /// /// 第二阶段逻辑(修改点:接收动态个数) /// /// 种子金额(第一阶段抢到的钱) /// 要拆分的个数 private List SplitPhase2(int seedAmount, int subCount) { List subPackets = new List(); int remainingAmount = seedAmount; // 如果要求的个数小于等于0,直接把钱全给用户(或者你可以选择报错) if (subCount <= 0) { subPackets.Add(new RedPacketRecord { Phase = 2, Index = 1, Amount = seedAmount }); return subPackets; } for (int i = 1; i <= subCount; i++) { int amount; int remainingCount = subCount - i; if (remainingCount == 0) { // 最后一个包,兜底拿走所有剩余 amount = remainingAmount; } else { // 二倍均值法 int avg = remainingAmount / remainingCount; int max = avg * 2; // 边界保护 int safeMax = remainingAmount - (remainingCount * MIN_AMOUNT); if (max > safeMax) max = safeMax; if (max < MIN_AMOUNT) max = MIN_AMOUNT; amount = _random.Next(MIN_AMOUNT, max + 1); } remainingAmount -= amount; subPackets.Add(new RedPacketRecord { Phase = 2, Index = i, Amount = amount }); } return subPackets; } public bool HasNext() { return _phase1Grabbed < _phase1Count; } }