From 7f01e7acb6d5226c1b0fd2b984dfa528f004003d Mon Sep 17 00:00:00 2001 From: CJKmkp <2564608840@qq.com> Date: Sat, 20 Dec 2025 19:57:11 +0800 Subject: [PATCH] =?UTF-8?q?improve:=E7=82=B9=E5=90=8D=E7=AE=97=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 改进不放回随机 --- Ink Canvas/Windows/NewStyleRollCallWindow.cs | 100 ++++++++++--------- Ink Canvas/Windows/RandWindow.xaml.cs | 63 ++++++++---- 2 files changed, 96 insertions(+), 67 deletions(-) diff --git a/Ink Canvas/Windows/NewStyleRollCallWindow.cs b/Ink Canvas/Windows/NewStyleRollCallWindow.cs index a72ef653..f0803e54 100644 --- a/Ink Canvas/Windows/NewStyleRollCallWindow.cs +++ b/Ink Canvas/Windows/NewStyleRollCallWindow.cs @@ -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(availableNames); var selectedNames = new List(); - var remainingNames = new List(availableNames); - - for (int i = 0; i < count && remainingNames.Count > 0; i++) + if (count >= candidatePool.Count) { - string selectedName = SelectSingleNameWithML(remainingNames, selectedNames, random); + return new List(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 } /// - /// 简单随机选择点名人员 + /// 简单不放回随机选择点名人员 /// private static List SelectNamesRandomly(List availableNames, int count, Random random) { if (availableNames == null || availableNames.Count == 0) return new List(); - var selectedNames = new List(); - var remainingNames = new List(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(availableNames); + } + + var candidatePool = new List(availableNames); + var selectedNames = new List(); + + 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 /// /// 使用概率算法选择单个人员 /// - private static string SelectSingleNameWithML(List availableNames, List alreadySelected, Random random) + private static string SelectSingleNameWithMLWithoutReplacement(List candidatePool, List 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(); - 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(); - 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); } + /// /// 获取人员的概率 /// @@ -878,30 +906,6 @@ namespace Ink_Canvas return 1.0 - frequency; } - /// - /// 加权随机选择(保留用于兼容,实际已改用概率选择) - /// - private static string WeightedRandomSelection(Dictionary 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(); - } /// /// 更新点名历史记录 diff --git a/Ink Canvas/Windows/RandWindow.xaml.cs b/Ink Canvas/Windows/RandWindow.xaml.cs index c3052eef..baf58235 100644 --- a/Ink Canvas/Windows/RandWindow.xaml.cs +++ b/Ink Canvas/Windows/RandWindow.xaml.cs @@ -212,59 +212,84 @@ namespace Ink_Canvas Random random = new Random();// randSeed + DateTime.Now.Millisecond / 10 % 10); string outputString = ""; List outputs = new List(); - List rands = new List(); LabelOutput2.Visibility = Visibility.Collapsed; LabelOutput3.Visibility = Visibility.Collapsed; new Thread(() => { + var animationPool = new List(); + 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 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(); Application.Current.Dispatcher.Invoke(() => { - for (int i = 0; i < TotalCount; i++) + var candidatePool = new List(); + 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(); + 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)