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