Files
ft/Client/Assets/Scripts/EventCubeMelt/Utils/SlotsGenerator.cs
2026-06-29 21:18:33 +08:00

238 lines
8.0 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using System;
using System.Collections.Generic;
using System.Linq;
using EventCubeMelt;
using UnityEngine;
using Random = UnityEngine.Random;
namespace EventCubeMelt.Utils
{
public static class SlotsGenerator
{
// 已废弃
public static List<int> GenerateSlots(int num,List<float> rates, List<int> data,List<int> rand)
{
var r = Random.value; // [0,1)
// // 随机一次或者两层
int count;
//
if (rates.Count < 2)
{
rates.Add(0.4f);
}
var r1 = rates[0];
var r2 = rates[1];
if (r < r1 ) count = 1; // 5%
else if (r < r2) count = 2; // 10%
else count = 0; // 85%
var list = PickPositions(count,data,rand );
ELog($"GenerateSlots -> {r} ,r1 = {r1} ,r2 = {r2} count = {count} {string.Join(",",rand)} => {string.Join(",",list)}");
return list;
}
public static List<int> GenerateSlots2(int num, List<float> rates, List<int> data, List<int> rand,List<int> collectIds)
{
if (collectIds is not { Count: > 0 } )
return data;
if (rand is not { Count: > 0 })
return data;
var ls = new List<int>();
for (var i = 0; i < num; i++)
{
var index = RandomSel(rates);
if (index < 0 || index >= collectIds.Count)
continue;
var value = collectIds[index];
// var has = rand.Any(item => item.id == value) ;
// ls.Add(has ? value : RandomRand(rand));
var randIndex = Random.Range(0,rand.Count);
ls.Add(rand.Contains(value) ? value : rand[randIndex]);
}
var list = PickPositionVer2(data,ls );
// ELog($"GenerateSlots2 -> {r} ,r1 = {r1} ,r2 = {r2} count = {count} {string.Join(",",rand)} => {string.Join(",",list)}");
return list;
}
// private static int RandomRand(List<(int id,int weight)> rand)
// {
// // 计算总权重
// // 计算总权重
// int totalWeight = 0;
// foreach (var item in rand)
// {
// if (item.weight < 0)
// continue;
// totalWeight += item.weight;
// }
//
// if (totalWeight == 0)
// return 101;
//
// // 在 Unity 环境中生成随机数
// int r = Random.Range(0, totalWeight);
// // 遍历查找
// int cumWeight = 0;
// foreach (var item in rand)
// {
// cumWeight += item.weight;
// if (r < cumWeight)
// {
// return item.id;
// }
// }
//
// return 101;
//
// }
private static int RandomSel(List<float> probabilities)
{
var randomValue = Random.value;
var cumulative = 0f;
for (int i = 0; i < probabilities.Count; i++)
{
cumulative += probabilities[i];
if (randomValue < cumulative)
{
return i;
}
}
return -1;
}
private static List<int> PickPositionVer2(List<int> data, List<int> rand)
{
var result = new List<int>(data);
// 如果没有随机数,直接返回
if (rand == null || rand.Count == 0)
{
return result;
}
var count = rand.Count;
// 收集非零位置
var nonZeroPositions = new List<int>();
for (var i = 0; i < data.Count; i++)
{
if (data[i] != 0)
{
nonZeroPositions.Add(i);
}
}
var actualCount = Math.Min(count, nonZeroPositions.Count);
// 随机选择位置
// Random random = new Random();
var selectedPositions = new List<int>();
// 部分洗牌:只洗需要选择的部分
for (var i = 0; i < actualCount; i++)
{
var randomIndex = Random.Range(i, nonZeroPositions.Count);
// 交换位置
(nonZeroPositions[i], nonZeroPositions[randomIndex]) = (nonZeroPositions[randomIndex], nonZeroPositions[i]);
selectedPositions.Add(nonZeroPositions[i]);
}
// 随机也洗牌
rand.ShuffleInPlace();
// 使用rand中的值替换
for (var i = 0; i < selectedPositions.Count; i++)
{
var position = selectedPositions[i];
var randIndex = i % rand.Count; // 循环使用rand中的值
result[position] = rand[randIndex];
}
return result;
}
private static List<int> PickPositions(int count ,List<int> data,List<int> rand)
{
// 如果没有随机数,直接返回
if (rand == null || rand.Count == 0 || count == 0)
{
// return result;
return data;
}
var result = new List<int>(data);
// 收集非零位置
var nonZeroPositions = new List<int>();
for (var i = 0; i < data.Count; i++)
{
if (data[i] != 0)
{
nonZeroPositions.Add(i);
}
}
var actualCount = Math.Min(count, nonZeroPositions.Count);
// 随机选择位置
// Random random = new Random();
var selectedPositions = new List<int>();
// 部分洗牌:只洗需要选择的部分
for (var i = 0; i < actualCount; i++)
{
var randomIndex = Random.Range(i, nonZeroPositions.Count);
// 交换位置
(nonZeroPositions[i], nonZeroPositions[randomIndex]) = (nonZeroPositions[randomIndex], nonZeroPositions[i]);
selectedPositions.Add(nonZeroPositions[i]);
}
// 随机也洗牌
rand.ShuffleInPlace();
// 使用rand中的值替换
for (var i = 0; i < selectedPositions.Count; i++)
{
var position = selectedPositions[i];
var randIndex = i % rand.Count; // 循环使用rand中的值
result[position] = rand[randIndex];
}
return result;
}
// 就地洗牌O(n),无偏。默认用 Random.Shared.NET 6+
public static void ShuffleInPlace<T>(this IList<T> list)
{
if (list == null)
throw new ArgumentNullException(nameof(list));
var n = list.Count;
for (int i = n - 1; i > 0; i--)
{
int j = Random.Range(0, i + 1);
if (j != i)
(list[i], list[j]) = (list[j], list[i]); // 交换
}
}
// 返回打乱后的副本(不修改原集合)
public static List<T> Shuffled<T>(this IEnumerable<T> source)
{
if (source == null)
throw new ArgumentNullException(nameof(source));
var list = new List<T>(source);
list.ShuffleInPlace();
return list;
}
#region LOG
private static void ELog(string message)
{
#if UNITY_EDITOR
if (!EventCubeMeltLogPolicy.EnableELog) return;
Debug.Log($"<color=orange> SlotsGenerator => {message} </color>");
#endif
}
#endregion
}
}