Files
5.24BuYu/Assets/Framework/Tool/RedPacket/LayeredRedPacket.cs
T

141 lines
4.3 KiB
C#
Raw Normal View History

2026-04-24 22:51:34 +08:00
using System;
using System.Collections.Generic;
2026-04-25 00:12:55 +08:00
[Serializable]
2026-04-24 22:51:34 +08:00
/// <summary>
/// 纯整数红包记录
/// 金额单位:分 (int)
/// </summary>
public class RedPacketRecord
{
public int Phase { get; set; } // 阶段:1 或 2
public int Index { get; set; } // 第几个包
2026-08-09 17:57:46 +08:00
public long Amount { get; set; } // 金额(单位:分,纯整数)
2026-04-24 22:51:34 +08:00
// 方便调试看日志的格式化方法
public string GetMoneyString()
{
return (Amount / 100) + "." + (Amount % 100).ToString("D2");
}
}
/// <summary>
/// 纯整数版级联红包算法(支持动态裂变个数)
/// </summary>
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;
}
/// <summary>
/// 核心方法:执行一次完整的“抢大包 -> 拆小包”
/// </summary>
/// <param name="subCount">【动态参数】第二轮要裂变出的红包个数</param>
/// <returns>该用户最终获得的一堆小红包列表</returns>
public List<RedPacketRecord> GrabFullCycle(int subCount)
{
// 1. 第一阶段:从大奖池抢一个金额
int phase1Amount = GrabPhase1();
if (phase1Amount <= 0) return null;
// 2. 第二阶段:把这个金额拆分成 subCount 个小包
return SplitPhase2(phase1Amount, subCount);
}
/// <summary>
/// 第一阶段逻辑(不变)
/// </summary>
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;
}
/// <summary>
/// 第二阶段逻辑(修改点:接收动态个数)
/// </summary>
/// <param name="seedAmount">种子金额(第一阶段抢到的钱)</param>
/// <param name="subCount">要拆分的个数</param>
private List<RedPacketRecord> SplitPhase2(int seedAmount, int subCount)
{
List<RedPacketRecord> subPackets = new List<RedPacketRecord>();
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;
}
}