improve:点名算法
改进不放回随机
This commit is contained in:
@@ -537,20 +537,34 @@ namespace Ink_Canvas
|
||||
bool enableML = MainWindow.Settings?.RandSettings?.EnableMLAvoidance ?? true;
|
||||
if (!enableML)
|
||||
{
|
||||
// 如果禁用机器学习,使用简单随机选择
|
||||
// 如果禁用机器学习,使用简单不放回随机选择
|
||||
return SelectNamesRandomly(availableNames, count, random);
|
||||
}
|
||||
|
||||
var candidatePool = new List<string>(availableNames);
|
||||
var selectedNames = new List<string>();
|
||||
var remainingNames = new List<string>(availableNames);
|
||||
|
||||
for (int i = 0; i < count && remainingNames.Count > 0; i++)
|
||||
if (count >= candidatePool.Count)
|
||||
{
|
||||
string selectedName = SelectSingleNameWithML(remainingNames, selectedNames, random);
|
||||
return new List<string>(candidatePool);
|
||||
}
|
||||
|
||||
for (int i = 0; i < count && candidatePool.Count > 0; i++)
|
||||
{
|
||||
string selectedName = SelectSingleNameWithMLWithoutReplacement(candidatePool, selectedNames, random);
|
||||
if (!string.IsNullOrEmpty(selectedName))
|
||||
{
|
||||
selectedNames.Add(selectedName);
|
||||
remainingNames.Remove(selectedName);
|
||||
candidatePool.Remove(selectedName);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (candidatePool.Count > 0)
|
||||
{
|
||||
int randomIndex = random.Next(0, candidatePool.Count);
|
||||
selectedName = candidatePool[randomIndex];
|
||||
selectedNames.Add(selectedName);
|
||||
candidatePool.RemoveAt(randomIndex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -558,21 +572,34 @@ namespace Ink_Canvas
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 简单随机选择点名人员
|
||||
/// 简单不放回随机选择点名人员
|
||||
/// </summary>
|
||||
private static List<string> SelectNamesRandomly(List<string> availableNames, int count, Random random)
|
||||
{
|
||||
if (availableNames == null || availableNames.Count == 0)
|
||||
return new List<string>();
|
||||
|
||||
var selectedNames = new List<string>();
|
||||
var remainingNames = new List<string>(availableNames);
|
||||
|
||||
for (int i = 0; i < count && remainingNames.Count > 0; i++)
|
||||
// 如果请求的数量大于或等于可用名单大小,返回所有名单
|
||||
if (count >= availableNames.Count)
|
||||
{
|
||||
int randomIndex = random.Next(remainingNames.Count);
|
||||
selectedNames.Add(remainingNames[randomIndex]);
|
||||
remainingNames.RemoveAt(randomIndex);
|
||||
return new List<string>(availableNames);
|
||||
}
|
||||
|
||||
var candidatePool = new List<string>(availableNames);
|
||||
var selectedNames = new List<string>();
|
||||
|
||||
for (int i = 0; i < count && candidatePool.Count > 0; i++)
|
||||
{
|
||||
int randomIndex = random.Next(0, candidatePool.Count);
|
||||
|
||||
selectedNames.Add(candidatePool[randomIndex]);
|
||||
|
||||
int lastIndex = candidatePool.Count - 1;
|
||||
if (randomIndex != lastIndex)
|
||||
{
|
||||
candidatePool[randomIndex] = candidatePool[lastIndex];
|
||||
}
|
||||
candidatePool.RemoveAt(lastIndex);
|
||||
}
|
||||
|
||||
return selectedNames;
|
||||
@@ -581,10 +608,10 @@ namespace Ink_Canvas
|
||||
/// <summary>
|
||||
/// 使用概率算法选择单个人员
|
||||
/// </summary>
|
||||
private static string SelectSingleNameWithML(List<string> availableNames, List<string> alreadySelected, Random random)
|
||||
private static string SelectSingleNameWithMLWithoutReplacement(List<string> candidatePool, List<string> alreadySelected, Random random)
|
||||
{
|
||||
if (availableNames.Count == 0) return null;
|
||||
if (availableNames.Count == 1) return availableNames[0];
|
||||
if (candidatePool.Count == 0) return null;
|
||||
if (candidatePool.Count == 1) return candidatePool[0];
|
||||
|
||||
// 确保历史数据已初始化
|
||||
if (historyData == null)
|
||||
@@ -599,16 +626,16 @@ namespace Ink_Canvas
|
||||
}
|
||||
|
||||
// 过滤掉已选择的人员
|
||||
var candidateNames = availableNames.Where(name => !alreadySelected.Contains(name)).ToList();
|
||||
if (candidateNames.Count == 0) return null;
|
||||
if (candidateNames.Count == 1) return candidateNames[0];
|
||||
var validCandidates = candidatePool.Where(name => !alreadySelected.Contains(name)).ToList();
|
||||
if (validCandidates.Count == 0) return null;
|
||||
if (validCandidates.Count == 1) return validCandidates[0];
|
||||
|
||||
// 检查极差:当极差达到3时,从被抽选次数最少的人中抽选
|
||||
if (historyData.NameFrequency != null && historyData.NameFrequency.Count > 0)
|
||||
{
|
||||
// 获取所有候选人员的被抽选次数
|
||||
var candidateFrequencies = new Dictionary<string, int>();
|
||||
foreach (string name in candidateNames)
|
||||
foreach (string name in validCandidates)
|
||||
{
|
||||
int count = historyData.NameFrequency.ContainsKey(name) ? historyData.NameFrequency[name] : 0;
|
||||
candidateFrequencies[name] = count;
|
||||
@@ -631,7 +658,7 @@ namespace Ink_Canvas
|
||||
|
||||
if (leastSelectedNames.Count > 0)
|
||||
{
|
||||
// 只从被抽选次数最少的人中随机选择
|
||||
// 只从被抽选次数最少的人中不放回随机选择
|
||||
int randomIndex = random.Next(0, leastSelectedNames.Count);
|
||||
return leastSelectedNames[randomIndex];
|
||||
}
|
||||
@@ -639,10 +666,10 @@ namespace Ink_Canvas
|
||||
}
|
||||
}
|
||||
|
||||
// 获取每个人员的概率
|
||||
// 获取每个候选人员的概率
|
||||
var nameProbabilities = new Dictionary<string, double>();
|
||||
|
||||
foreach (string name in candidateNames)
|
||||
foreach (string name in validCandidates)
|
||||
{
|
||||
// 获取基础概率
|
||||
double baseProbability = GetNameProbability(name);
|
||||
@@ -659,6 +686,7 @@ namespace Ink_Canvas
|
||||
return ProbabilityBasedRandomSelection(nameProbabilities, random);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 获取人员的概率
|
||||
/// </summary>
|
||||
@@ -878,30 +906,6 @@ namespace Ink_Canvas
|
||||
return 1.0 - frequency;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 加权随机选择(保留用于兼容,实际已改用概率选择)
|
||||
/// </summary>
|
||||
private static string WeightedRandomSelection(Dictionary<string, double> nameWeights, Random random)
|
||||
{
|
||||
if (nameWeights.Count == 0) return null;
|
||||
|
||||
double totalWeight = nameWeights.Values.Sum();
|
||||
if (totalWeight <= 0) return nameWeights.Keys.First();
|
||||
|
||||
double randomValue = random.NextDouble() * totalWeight;
|
||||
double currentWeight = 0;
|
||||
|
||||
foreach (var kvp in nameWeights)
|
||||
{
|
||||
currentWeight += kvp.Value;
|
||||
if (randomValue <= currentWeight)
|
||||
{
|
||||
return kvp.Key;
|
||||
}
|
||||
}
|
||||
|
||||
return nameWeights.Keys.Last();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 更新点名历史记录
|
||||
|
||||
@@ -212,59 +212,84 @@ namespace Ink_Canvas
|
||||
Random random = new Random();// randSeed + DateTime.Now.Millisecond / 10 % 10);
|
||||
string outputString = "";
|
||||
List<string> outputs = new List<string>();
|
||||
List<int> rands = new List<int>();
|
||||
|
||||
LabelOutput2.Visibility = Visibility.Collapsed;
|
||||
LabelOutput3.Visibility = Visibility.Collapsed;
|
||||
|
||||
new Thread(() =>
|
||||
{
|
||||
var animationPool = new List<int>();
|
||||
for (int num = 1; num <= PeopleCount; num++)
|
||||
{
|
||||
animationPool.Add(num);
|
||||
}
|
||||
int lastDisplayedIndex = -1;
|
||||
|
||||
for (int i = 0; i < RandWaitingTimes; i++)
|
||||
{
|
||||
int rand = random.Next(1, PeopleCount + 1);
|
||||
while (rands.Contains(rand))
|
||||
if (animationPool.Count == 0)
|
||||
{
|
||||
rand = random.Next(1, PeopleCount + 1);
|
||||
animationPool.Clear();
|
||||
for (int num = 1; num <= PeopleCount; num++)
|
||||
{
|
||||
animationPool.Add(num);
|
||||
}
|
||||
}
|
||||
rands.Add(rand);
|
||||
if (rands.Count >= PeopleCount) rands = new List<int>();
|
||||
|
||||
int randomIndex = random.Next(0, animationPool.Count);
|
||||
int selectedNumber = animationPool[randomIndex];
|
||||
|
||||
int lastIndex = animationPool.Count - 1;
|
||||
if (randomIndex != lastIndex)
|
||||
{
|
||||
animationPool[randomIndex] = animationPool[lastIndex];
|
||||
}
|
||||
animationPool.RemoveAt(lastIndex);
|
||||
|
||||
Application.Current.Dispatcher.Invoke(() =>
|
||||
{
|
||||
if (Names.Count != 0)
|
||||
{
|
||||
LabelOutput.Content = Names[rand - 1];
|
||||
LabelOutput.Content = Names[selectedNumber - 1];
|
||||
}
|
||||
else
|
||||
{
|
||||
LabelOutput.Content = rand.ToString();
|
||||
LabelOutput.Content = selectedNumber.ToString();
|
||||
}
|
||||
});
|
||||
|
||||
Thread.Sleep(RandWaitingThreadSleepTime);
|
||||
}
|
||||
|
||||
rands = new List<int>();
|
||||
Application.Current.Dispatcher.Invoke(() =>
|
||||
{
|
||||
for (int i = 0; i < TotalCount; i++)
|
||||
var candidatePool = new List<int>();
|
||||
for (int num = 1; num <= PeopleCount; num++)
|
||||
{
|
||||
int rand = random.Next(1, PeopleCount + 1);
|
||||
while (rands.Contains(rand))
|
||||
candidatePool.Add(num);
|
||||
}
|
||||
|
||||
for (int i = 0; i < TotalCount && candidatePool.Count > 0; i++)
|
||||
{
|
||||
int randomIndex = random.Next(0, candidatePool.Count);
|
||||
int selectedNumber = candidatePool[randomIndex];
|
||||
|
||||
int lastIndex = candidatePool.Count - 1;
|
||||
if (randomIndex != lastIndex)
|
||||
{
|
||||
rand = random.Next(1, PeopleCount + 1);
|
||||
candidatePool[randomIndex] = candidatePool[lastIndex];
|
||||
}
|
||||
rands.Add(rand);
|
||||
if (rands.Count >= PeopleCount) rands = new List<int>();
|
||||
candidatePool.RemoveAt(lastIndex);
|
||||
|
||||
if (Names.Count != 0)
|
||||
{
|
||||
outputs.Add(Names[rand - 1]);
|
||||
outputString += Names[rand - 1] + Environment.NewLine;
|
||||
outputs.Add(Names[selectedNumber - 1]);
|
||||
outputString += Names[selectedNumber - 1] + Environment.NewLine;
|
||||
}
|
||||
else
|
||||
{
|
||||
outputs.Add(rand.ToString());
|
||||
outputString += rand + Environment.NewLine;
|
||||
outputs.Add(selectedNumber.ToString());
|
||||
outputString += selectedNumber + Environment.NewLine;
|
||||
}
|
||||
}
|
||||
if (TotalCount <= 5)
|
||||
|
||||
Reference in New Issue
Block a user