ElectiveEngine.cs 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. namespace mxdemo.Mind
  5. {
  6. #region models
  7. /// <summary>
  8. /// 选科组合
  9. /// </summary>
  10. public class SubjectGroup
  11. {
  12. public int Limitation { get; set; } // 人数限制
  13. public string Name { get; set; }
  14. public string Code { get; set; }
  15. public long Id { get; set; }
  16. }
  17. /// <summary>
  18. /// 志愿
  19. /// </summary>
  20. public class Preference
  21. {
  22. public int Rank { get; set; } // 第1、2、3志原 越小优先级越高
  23. public long GroupId {get;set;}
  24. public long StudentId { get; set; }
  25. public long Id { get; set; }
  26. }
  27. /// <summary>
  28. /// 得分情况
  29. /// </summary>
  30. public class GroupScore
  31. {
  32. public decimal Score { get; set; }
  33. public long StudentId { get; set; }
  34. public long GroupId { get; set; }
  35. }
  36. /// <summary>
  37. /// 学生信息
  38. /// </summary>
  39. public class Student
  40. {
  41. public long Id { get; set; }
  42. public string No { get; set; }
  43. public string Name { get; set; }
  44. }
  45. public class ElectiveElement
  46. {
  47. public Student Student { get; set; }
  48. public Preference Preference { get; set; }
  49. public SubjectGroup Group { get; set; }
  50. // 计算属性
  51. public int PreferenceRank { get; set; } // 志愿排名
  52. public int GroupRank { get; set; } // 组合排名,即成绩排名(组合全校排名),同样越小优先级越高
  53. }
  54. #endregion
  55. public class ElectiveResult
  56. {
  57. public ElectiveResult(List<Student> students)
  58. {
  59. this.UnmatchedStudents = students;
  60. }
  61. public List<Student> MatchedStudents { get; set; }
  62. = new List<Student>();
  63. public Dictionary<SubjectGroup, List<ElectiveElement>> MatchedDetails { get; set; }
  64. = new Dictionary<SubjectGroup, List<ElectiveElement>>();
  65. public List<Student> UnmatchedStudents { get; set; }
  66. public void AppendMatched(ElectiveElement element)
  67. {
  68. // 应该还有更多细节需要考虑
  69. var appendStudent = element.Student;
  70. if (MatchedStudents.Contains(appendStudent)) return;
  71. if (UnmatchedStudents.Contains(appendStudent))
  72. RemoveUnmatched(appendStudent);
  73. var appendGroup = MatchedDetails.ContainsKey(element.Group)
  74. ? MatchedDetails[element.Group]
  75. : new List<ElectiveElement>();
  76. if (appendGroup.Count < element.Group.Limitation)
  77. {
  78. MatchedDetails[element.Group] = appendGroup;
  79. AddMatchedAndDetails(element);
  80. }
  81. else
  82. {
  83. AddUnmatched(appendStudent);
  84. }
  85. }
  86. private void AddMatchedAndDetails(ElectiveElement element)
  87. {
  88. // 应该还有更多细节需要考虑
  89. MatchedDetails[element.Group].Add(element);
  90. MatchedStudents.Add(element.Student);
  91. }
  92. private void AddUnmatched(Student student)
  93. {
  94. // 应该还有更多细节需要考虑
  95. UnmatchedStudents.Add(student);
  96. }
  97. private void RemoveUnmatched(Student student)
  98. {
  99. // 应该还有更多细节需要考虑
  100. UnmatchedStudents.Remove(student);
  101. }
  102. }
  103. public interface IElectiveStrategy
  104. {
  105. /// <summary>
  106. /// 从开放选科中取出按优先级分组的选科
  107. /// </summary>
  108. /// <returns></returns>
  109. List<List<SubjectGroup>> GetAllPrioritizedGroups();
  110. /// <summary>
  111. /// 参与这次运算的志愿优先级集合
  112. /// </summary>
  113. /// <returns></returns>
  114. List<List<int>> GetAllPrioritizedPreferenceRanks();
  115. /// <summary>
  116. /// 参与这次运算的所有学生
  117. /// </summary>
  118. /// <returns></returns>
  119. List<Student> GetAllStudents();
  120. }
  121. public abstract class ElectiveEngine: IComparer<ElectiveElement>
  122. {
  123. protected IElectiveStrategy ElectiveStrategy { get; set; }
  124. protected ElectiveEngine(IElectiveStrategy electiveStrategy)
  125. {
  126. ElectiveStrategy = electiveStrategy;
  127. }
  128. public ElectiveResult Execute()
  129. {
  130. var prioritizedGroups = ElectiveStrategy.GetAllPrioritizedGroups();
  131. var prioritizedPreferenceRanks = ElectiveStrategy.GetAllPrioritizedPreferenceRanks();
  132. var allStudents = ElectiveStrategy.GetAllStudents();
  133. var electiveResult = new ElectiveResult(allStudents);
  134. foreach(var groups in prioritizedGroups)
  135. {
  136. foreach(var ranks in prioritizedPreferenceRanks)
  137. {
  138. var students = electiveResult.UnmatchedStudents;
  139. var elements = BuildElectiveElements(students, groups, ranks);
  140. ExecuteCore(elements, electiveResult);
  141. }
  142. }
  143. return electiveResult;
  144. }
  145. private void ExecuteCore(List<ElectiveElement> elements, ElectiveResult context)
  146. {
  147. // 核心方法优先级排序, 已经按期望排好了录取顺序
  148. elements.Sort(this); // this.IComparer<ElectiveElement>.Compare
  149. // 接下来考虑每个组合容量的问题
  150. foreach(var element in elements)
  151. {
  152. context.AppendMatched(element);
  153. }
  154. }
  155. protected virtual List<ElectiveElement> BuildElectiveElements(List<Student> students, List<SubjectGroup> groups, List<int> ranks)
  156. {
  157. // 根据组合与志愿 生成不同的选科元素
  158. // 可以按计算需要,相互挂一些引用,方便计算过程中的删除操作
  159. // TODO: 如果引入意向专业,也可以改写这个生成的逻辑
  160. throw new NotImplementedException();
  161. }
  162. /// <summary>
  163. /// 优先级比较
  164. /// </summary>
  165. /// <param name="x"></param>
  166. /// <param name="y"></param>
  167. /// <returns></returns>
  168. public abstract int Compare(ElectiveElement x, ElectiveElement y);
  169. }
  170. public class PreferenceAheadElectiveEngine : ElectiveEngine
  171. {
  172. public PreferenceAheadElectiveEngine(IElectiveStrategy electiveStrategy)
  173. :base(electiveStrategy)
  174. {
  175. }
  176. public override int Compare(ElectiveElement x, ElectiveElement y)
  177. {
  178. // TODO: 容错处理
  179. if (x.PreferenceRank == y.PreferenceRank) return y.GroupRank - x.GroupRank;
  180. return y.PreferenceRank - x.PreferenceRank;
  181. }
  182. }
  183. public class ScoreAheadElectiveEngine : ElectiveEngine
  184. {
  185. public ScoreAheadElectiveEngine(IElectiveStrategy electiveStrategy)
  186. : base(electiveStrategy)
  187. {
  188. }
  189. public override int Compare(ElectiveElement x, ElectiveElement y)
  190. {
  191. // TODO: 容错处理
  192. if (x.GroupRank == y.GroupRank) return y.PreferenceRank - x.PreferenceRank;
  193. return y.GroupRank - x.GroupRank;
  194. }
  195. }
  196. }