238 lines
8.0 KiB
C#
238 lines
8.0 KiB
C#
|
||
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
|
||
}
|
||
} |