refactor: finish arranger
This commit is contained in:
@ -1,140 +1,129 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Collections.Immutable;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using HFUTCourseSimulation.Kernel.Data.Built;
|
|
||||||
using HFUTCourseSimulation.Util;
|
using HFUTCourseSimulation.Util;
|
||||||
|
|
||||||
namespace HFUTCourseSimulation.Kernel {
|
namespace HFUTCourseSimulation.Kernel {
|
||||||
|
|
||||||
/// <summary>
|
///// <summary>
|
||||||
/// 一个标识符,用于指代学期中指定周的指定星期的指定节次
|
///// 一个标识符,用于指代学期中指定周的指定星期的指定节次
|
||||||
/// </summary>
|
///// </summary>
|
||||||
internal class ArrangerSpot : IEquatable<ArrangerSpot> {
|
//internal class ArrangerSpot : IEquatable<ArrangerSpot> {
|
||||||
public ArrangerSpot(int week, int day, int index) {
|
// public ArrangerSpot(int week, int day, int index) {
|
||||||
this.week = week;
|
// this.week = week;
|
||||||
this.day = day;
|
// this.day = day;
|
||||||
this.index = index;
|
// this.index = index;
|
||||||
}
|
// }
|
||||||
|
|
||||||
/// <summary>
|
// /// <summary>
|
||||||
/// 教学周
|
// /// 教学周
|
||||||
/// </summary>
|
// /// </summary>
|
||||||
public int week;
|
// public int week;
|
||||||
/// <summary>
|
// /// <summary>
|
||||||
/// 星期几
|
// /// 星期几
|
||||||
/// </summary>
|
// /// </summary>
|
||||||
public int day;
|
// public int day;
|
||||||
/// <summary>
|
// /// <summary>
|
||||||
/// 节次
|
// /// 节次
|
||||||
/// </summary>
|
// /// </summary>
|
||||||
public int index;
|
// public int index;
|
||||||
|
|
||||||
public override bool Equals(object obj) {
|
// public override bool Equals(object obj) {
|
||||||
return Equals(obj as ArrangerSpot);
|
// return Equals(obj as ArrangerSpot);
|
||||||
}
|
// }
|
||||||
|
|
||||||
public bool Equals(ArrangerSpot other) {
|
// public bool Equals(ArrangerSpot other) {
|
||||||
return !(other is null) &&
|
// return !(other is null) &&
|
||||||
week == other.week &&
|
// week == other.week &&
|
||||||
day == other.day &&
|
// day == other.day &&
|
||||||
index == other.index;
|
// index == other.index;
|
||||||
}
|
// }
|
||||||
|
|
||||||
public override int GetHashCode() {
|
// public override int GetHashCode() {
|
||||||
int hashCode = -206993699;
|
// int hashCode = -206993699;
|
||||||
hashCode = hashCode * -1521134295 + week.GetHashCode();
|
// hashCode = hashCode * -1521134295 + week.GetHashCode();
|
||||||
hashCode = hashCode * -1521134295 + day.GetHashCode();
|
// hashCode = hashCode * -1521134295 + day.GetHashCode();
|
||||||
hashCode = hashCode * -1521134295 + index.GetHashCode();
|
// hashCode = hashCode * -1521134295 + index.GetHashCode();
|
||||||
return hashCode;
|
// return hashCode;
|
||||||
}
|
// }
|
||||||
|
|
||||||
public static bool operator ==(ArrangerSpot left, ArrangerSpot right) {
|
// public static bool operator ==(ArrangerSpot left, ArrangerSpot right) {
|
||||||
return EqualityComparer<ArrangerSpot>.Default.Equals(left, right);
|
// return EqualityComparer<ArrangerSpot>.Default.Equals(left, right);
|
||||||
}
|
// }
|
||||||
|
|
||||||
public static bool operator !=(ArrangerSpot left, ArrangerSpot right) {
|
// public static bool operator !=(ArrangerSpot left, ArrangerSpot right) {
|
||||||
return !(left == right);
|
// return !(left == right);
|
||||||
}
|
// }
|
||||||
}
|
//}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 课程安排器。
|
/// 课程安排器。
|
||||||
/// 负责将课程安排到每周之中,并提示用户错误等各种信息。
|
/// 负责将课程安排到每周之中,并提示用户错误等各种信息。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class Arranger {
|
public static class Arranger {
|
||||||
public Arranger(Kernel.Data.Storage.Semester semester) {
|
|
||||||
this.semester = semester;
|
|
||||||
arrangeMap = new Dictionary<ArrangerSpot, int>();
|
|
||||||
reporter = new Reporter();
|
|
||||||
}
|
|
||||||
|
|
||||||
private Kernel.Data.Storage.Semester semester;
|
|
||||||
private Dictionary<ArrangerSpot, int> arrangeMap;
|
|
||||||
private Reporter reporter;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 获取汇报器用于查看安排日志
|
|
||||||
/// </summary>
|
|
||||||
/// <returns></returns>
|
|
||||||
public Reporter GetReporter() {
|
|
||||||
return reporter;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 开始安排课程
|
/// 开始安排课程
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>安排好的,用于呈现的课程。如果安排失败,则为null,查看汇报器来了解具体差错</returns>
|
/// <returns>安排好的,用于呈现的课程。如果安排失败,则为null,查看汇报器来了解具体差错</returns>
|
||||||
public Kernel.Data.Presentation.Semester Arrange() {
|
public static Data.Presentation.Semester Arrange(Data.Storage.Semester semester, Reporter reporter) {
|
||||||
reporter.Clear();
|
var builtSemester = CheckSemester(semester, reporter);
|
||||||
arrangeMap.Clear();
|
if (builtSemester is null) return null;
|
||||||
return ConcludeCourses();
|
|
||||||
|
var arrangeMap = ArrangeCourses(builtSemester, reporter);
|
||||||
|
var renderResult = ConcludeCourses(builtSemester, arrangeMap, reporter);
|
||||||
|
|
||||||
|
return renderResult;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#region 验证用户课表输入
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 检查用户输入的学期数据是否正确
|
/// 检查用户输入的学期数据是否正确
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>如果检查无误,返回检查后的结果,否则返回null</returns>
|
/// <returns>如果检查无误则返回检查好的结构,否则返回null</returns>
|
||||||
private Semester CheckSemester() {
|
private static Data.Built.Semester CheckSemester(Data.Storage.Semester semester, Reporter reporter) {
|
||||||
// 检查Semester
|
// 检查Semester
|
||||||
reporter.Info($"正在检查学期");
|
reporter.Info($"正在检查学期");
|
||||||
if (semester.StartDate.DayOfWeek != DayOfWeek.Monday) {
|
if (semester.StartDate.DayOfWeek != DayOfWeek.Monday) {
|
||||||
reporter.Error($"起始日期{semester.StartDate:yyyy-MM-dd}不是星期一");
|
reporter.Error($"起始日期{semester.StartDate:yyyy-MM-dd}不是星期一");
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
var rv = CheckInteger(semester.WeekCount, 1, 100, "周数", "0 < N");
|
var rv = CheckInteger(reporter, semester.WeekCount, 1, 100, "周数", "0 < N");
|
||||||
if (rv is null) return null;
|
if (rv is null) return null;
|
||||||
int weekCount = rv.Value;
|
int weekCount = rv.Value;
|
||||||
rv = CheckInteger(semester.IndexCount, 1, 100, "节次数", "0 < N");
|
rv = CheckInteger(reporter, semester.IndexCount, 1, 100, "节次数", "0 < N");
|
||||||
if (rv is null) return null;
|
if (rv is null) return null;
|
||||||
int indexCount = rv.Value;
|
int indexCount = rv.Value;
|
||||||
rv = CheckInteger(semester.BreakfastAt, 0, indexCount, "早餐时间点", "0 <= N <= 节次数");
|
rv = CheckInteger(reporter, semester.BreakfastAt, 0, indexCount, "早餐时间点", "0 <= N <= 节次数");
|
||||||
if (rv is null) return null;
|
if (rv is null) return null;
|
||||||
int breakfastAt = rv.Value;
|
int breakfastAt = rv.Value;
|
||||||
rv = CheckInteger(semester.LunchAt, breakfastAt, indexCount, "午餐时间点", "早餐时间点 <= N <= 节次数");
|
rv = CheckInteger(reporter, semester.LunchAt, breakfastAt, indexCount, "午餐时间点", "早餐时间点 <= N <= 节次数");
|
||||||
if (rv is null) return null;
|
if (rv is null) return null;
|
||||||
int lunchAt = rv.Value;
|
int lunchAt = rv.Value;
|
||||||
rv = CheckInteger(semester.DinnerAt, lunchAt, indexCount, "晚餐时间点", "午餐时间点 <= N <= 节次数");
|
rv = CheckInteger(reporter, semester.DinnerAt, lunchAt, indexCount, "晚餐时间点", "午餐时间点 <= N <= 节次数");
|
||||||
if (rv is null) return null;
|
if (rv is null) return null;
|
||||||
int dinnerAt = rv.Value;
|
int dinnerAt = rv.Value;
|
||||||
|
|
||||||
var courses = new List<Course>();
|
var courses = new List<Data.Built.Course>();
|
||||||
foreach (var course in semester.Courses) {
|
foreach (var course in semester.Courses) {
|
||||||
// 检查课程(实际上只有安排需要检查)
|
// 检查课程(实际上只有安排需要检查)
|
||||||
reporter.Info($"正在检查课程:{course.Name}");
|
reporter.Info($"正在检查课程:{course.Name}");
|
||||||
|
|
||||||
var schedules = new List<Schedule>();
|
var schedules = new List<Data.Built.Schedule>();
|
||||||
|
|
||||||
foreach (var schedule in course.Schedules) {
|
foreach (var schedule in course.Schedules) {
|
||||||
// 检查安排
|
// 检查安排
|
||||||
var week = CheckIntegerCollection(schedule.Week, 1, weekCount, "周", "1 <= N <= 周数");
|
var week = CheckIntegerCollection(reporter, schedule.Week, 1, weekCount, "周", "1 <= N <= 周数");
|
||||||
var day = CheckIntegerCollection(schedule.Day, 1, 7, "星期", "1 <= N <= 7");
|
var day = CheckIntegerCollection(reporter, schedule.Day, 1, 7, "星期", "1 <= N <= 7");
|
||||||
var index = CheckIntegerCollection(schedule.Index, 1, indexCount, "节次", "1 <= N <= 节次数");
|
var index = CheckIntegerCollection(reporter, schedule.Index, 1, indexCount, "节次", "1 <= N <= 节次数");
|
||||||
|
|
||||||
// 如果格式均正确,就添加这个安排
|
// 如果格式均正确,就添加这个安排
|
||||||
if (!(week is null || day is null || index is null)) {
|
if (!(week is null || day is null || index is null)) {
|
||||||
schedules.Add(new Schedule() {
|
schedules.Add(new Data.Built.Schedule() {
|
||||||
week = week,
|
week = week,
|
||||||
day = day,
|
day = day,
|
||||||
index = index
|
index = index
|
||||||
@ -143,7 +132,7 @@ namespace HFUTCourseSimulation.Kernel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// OK,插入课程
|
// OK,插入课程
|
||||||
courses.Add(new Course() {
|
courses.Add(new Data.Built.Course() {
|
||||||
name = course.Name,
|
name = course.Name,
|
||||||
description = course.Description,
|
description = course.Description,
|
||||||
color = ColorTrans.ToStandardColorPair(course.Color),
|
color = ColorTrans.ToStandardColorPair(course.Color),
|
||||||
@ -152,7 +141,7 @@ namespace HFUTCourseSimulation.Kernel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// OK无误,返回结果
|
// OK无误,返回结果
|
||||||
return new Semester() {
|
return new Data.Built.Semester() {
|
||||||
startDate = semester.StartDate,
|
startDate = semester.StartDate,
|
||||||
weekCount = weekCount,
|
weekCount = weekCount,
|
||||||
indexCount = indexCount,
|
indexCount = indexCount,
|
||||||
@ -168,8 +157,8 @@ namespace HFUTCourseSimulation.Kernel {
|
|||||||
/// field_name是字段的名称,field_require是字段的要求,均用于用户提示。
|
/// field_name是字段的名称,field_require是字段的要求,均用于用户提示。
|
||||||
/// 返回null表示检查失败,否则返回检查好的值。
|
/// 返回null表示检查失败,否则返回检查好的值。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private int? CheckInteger(string s, int min, int max, string field_name, string field_require) {
|
private static int? CheckInteger(Reporter reporter, string s, int min, int max, string field_name, string field_require) {
|
||||||
if (int.TryParse(semester.WeekCount, out int rv)) {
|
if (int.TryParse(s, out int rv)) {
|
||||||
if (rv < min || rv > max) {
|
if (rv < min || rv > max) {
|
||||||
reporter.Error($"{field_name}的值“{s}”超出范围。要求:{field_require}");
|
reporter.Error($"{field_name}的值“{s}”超出范围。要求:{field_require}");
|
||||||
return null;
|
return null;
|
||||||
@ -192,7 +181,7 @@ namespace HFUTCourseSimulation.Kernel {
|
|||||||
/// 检查整数集合的辅助函数,即检查Schedule中的三个字段Week,Day和Index的格式。
|
/// 检查整数集合的辅助函数,即检查Schedule中的三个字段Week,Day和Index的格式。
|
||||||
/// 各类参数含义与上面函数相同,只不过是作用到每一项上。
|
/// 各类参数含义与上面函数相同,只不过是作用到每一项上。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private IEnumerable<int> CheckIntegerCollection(string s, int min, int max, string field_name, string field_require) {
|
private static IEnumerable<int> CheckIntegerCollection(Reporter reporter, string s, int min, int max, string field_name, string field_require) {
|
||||||
// 两种整数集合所特有的字符常量,用于分割和分析
|
// 两种整数集合所特有的字符常量,用于分割和分析
|
||||||
const char COMMA = ',';
|
const char COMMA = ',';
|
||||||
const char DASH = '-';
|
const char DASH = '-';
|
||||||
@ -240,63 +229,148 @@ namespace HFUTCourseSimulation.Kernel {
|
|||||||
// 按整数集合类型进行收尾检查并返回
|
// 按整数集合类型进行收尾检查并返回
|
||||||
switch (kind) {
|
switch (kind) {
|
||||||
case IntegerCollectionKind.Individual:
|
case IntegerCollectionKind.Individual:
|
||||||
return new IndividualInt(ints);
|
return new Data.Built.IndividualInt(ints);
|
||||||
case IntegerCollectionKind.Range:
|
case IntegerCollectionKind.Range:
|
||||||
if (ints.Count != 2) {
|
if (ints.Count != 2) {
|
||||||
reporter.Error($"{field_name}的值“{s}”不是有效的整数范围表达式");
|
reporter.Error($"{field_name}的值“{s}”不是有效的整数范围表达式");
|
||||||
return null;
|
return null;
|
||||||
} else {
|
} else {
|
||||||
return new RangedInt(ints[0], ints[1]);
|
return new Data.Built.RangedInt(ints[0], ints[1]);
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region 安排课程
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 安排课程
|
/// 安排课程
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>安排无误返回true,否则返回false</returns>
|
/// <returns>返回安排好的课程表</returns>
|
||||||
private bool ArrangeCourses() {
|
private static int[,,] ArrangeCourses(Data.Built.Semester semester, Reporter reporter) {
|
||||||
// Check it first
|
// 创建课程表并预填充所有项为-1。
|
||||||
var rv = CheckSemester();
|
var arrangeMap = new int[semester.weekCount, 7, semester.indexCount];
|
||||||
if (rv is null) return false;
|
for (var week = 0; week < semester.weekCount; ++week) {
|
||||||
|
for (var day = 0; day < 7; ++day) {
|
||||||
|
for (var index = 0; index < semester.indexCount; ++index) {
|
||||||
|
arrangeMap[week, day, index] = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 遍历所有课程安排开始排课
|
// 遍历所有课程安排开始排课
|
||||||
bool okey = true;
|
// 排课冲突并不是严重错误,因此不需要强制退出
|
||||||
for (int course_index = 0; course_index < rv.courses.Count; ++course_index) {
|
for (int course_index = 0; course_index < semester.courses.Count; ++course_index) {
|
||||||
var course = rv.courses[course_index];
|
var course = semester.courses[course_index];
|
||||||
foreach (var schedule in course.schedules) {
|
foreach (var schedule in course.schedules) {
|
||||||
foreach (var week in schedule.week) {
|
foreach (var week in schedule.week) {
|
||||||
foreach (var day in schedule.day) {
|
foreach (var day in schedule.day) {
|
||||||
foreach (var index in schedule.index) {
|
foreach (var index in schedule.index) {
|
||||||
var spot = new ArrangerSpot(week, day, index);
|
// 获取课程占用情况并分析
|
||||||
if (arrangeMap.TryGetValue(spot, out int occupied_course_index)) {
|
var occupied_course_index = arrangeMap[week - 1, day - 1, index - 1];
|
||||||
var occupied_course = rv.courses[occupied_course_index];
|
if (occupied_course_index < 0) {
|
||||||
reporter.Error($"课程冲突:无法将{course.name}安排到周{week},星期{day},第{index}节。因为此处已被{occupied_course.name}占据");
|
// 没有占用的课程,可以放心安排
|
||||||
okey = false;
|
arrangeMap[week - 1, day - 1, index - 1] = course_index;
|
||||||
} else {
|
} else {
|
||||||
arrangeMap.Add(spot, course_index);
|
// 发现课程占用,汇报占用的课程并记录到flag
|
||||||
|
var occupied_course = semester.courses[occupied_course_index];
|
||||||
|
reporter.Error($"课程冲突:无法将{course.name}安排到周{week},星期{day},第{index}节。因为此处已被{occupied_course.name}占据");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return okey;
|
|
||||||
|
// 返回结果
|
||||||
|
return arrangeMap;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region 总结课程为方便渲染的结构
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 将安排好的课程总结为方便渲染的结果
|
/// 将安排好的课程总结为方便渲染的结果
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns></returns>
|
/// <returns>总结好的可用于渲染的结果</returns>
|
||||||
private Kernel.Data.Presentation.Semester ConcludeCourses() {
|
private static Data.Presentation.Semester ConcludeCourses(Data.Built.Semester semester, int[,,] arrangeMap, Reporter reporter) {
|
||||||
// Arrange it first
|
var dateCursor = semester.startDate;
|
||||||
var rv = ArrangeCourses();
|
|
||||||
if (!rv) return null;
|
|
||||||
|
|
||||||
return null;
|
var weeks = new List<Data.Presentation.Week>();
|
||||||
|
for (var week = 1; week <= semester.weekCount; ++week) {
|
||||||
|
var days = new List<Data.Presentation.Day>();
|
||||||
|
for (var day = 1; day <= 7; ++day) {
|
||||||
|
// 获取日期的字符串形式,并自增天数
|
||||||
|
var dateString = dateCursor.ToString("MM/dd");
|
||||||
|
dateCursor = dateCursor.AddDays(1);
|
||||||
|
|
||||||
|
// 获取这一日的课程
|
||||||
|
var lessons = new List<Data.Presentation.Lesson>();
|
||||||
|
Data.Presentation.Lesson current_lesson = null;
|
||||||
|
int previous_course_index = -1;
|
||||||
|
for (var index = 1; index <= semester.indexCount; ++index) {
|
||||||
|
// 比较上一个课程和当前课程的区别
|
||||||
|
var this_course_index = arrangeMap[week - 1, day - 1, index - 1];
|
||||||
|
if (this_course_index != previous_course_index) {
|
||||||
|
// 课程发生了变化,我们需要根据这种变化做出操作。
|
||||||
|
// 如果有上一任课程,我们就把它push到列表中。
|
||||||
|
if (previous_course_index >= 0) {
|
||||||
|
lessons.Add(current_lesson);
|
||||||
|
current_lesson = null;
|
||||||
}
|
}
|
||||||
|
// 然后设置当前课程
|
||||||
|
var this_course = semester.courses[this_course_index];
|
||||||
|
current_lesson = new Data.Presentation.Lesson() {
|
||||||
|
name = this_course.name,
|
||||||
|
description = this_course.description,
|
||||||
|
color = this_course.color,
|
||||||
|
startIndex = index,
|
||||||
|
indexSpan = 1
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
// 课程未曾发生改变,如果当前有课程,我们只需要单纯地自增其节次跨度
|
||||||
|
if (previous_course_index >= 0) {
|
||||||
|
current_lesson.indexSpan++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 更新上一个课程的index
|
||||||
|
previous_course_index = this_course_index;
|
||||||
|
}
|
||||||
|
// 收尾处理最后一个课程
|
||||||
|
if (previous_course_index >= 0) {
|
||||||
|
lessons.Add(current_lesson);
|
||||||
|
current_lesson = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 将这一日添加到这周中
|
||||||
|
days.Add(new Data.Presentation.Day() {
|
||||||
|
date = dateString,
|
||||||
|
lessons = lessons.ToImmutableList()
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 将这一星期添加教学周中
|
||||||
|
weeks.Add(new Data.Presentation.Week() {
|
||||||
|
days = days.ToImmutableList()
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 以教学周构建并返回学期
|
||||||
|
return new Data.Presentation.Semester() {
|
||||||
|
weekCount = semester.weekCount,
|
||||||
|
indexCount = semester.indexCount,
|
||||||
|
breakfastAt = semester.breakfastAt,
|
||||||
|
lunchAt = semester.lunchAt,
|
||||||
|
dinnerAt = semester.dinnerAt,
|
||||||
|
weeks = weeks.ToImmutableList()
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,10 @@ using System.Linq;
|
|||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 安排课程时使用的课表数据。
|
||||||
|
/// 仅在课表安排器中作为中间结构使用,其本质上为经过验证的用户输入的课表数据。
|
||||||
|
/// </summary>
|
||||||
namespace HFUTCourseSimulation.Kernel.Data.Built {
|
namespace HFUTCourseSimulation.Kernel.Data.Built {
|
||||||
|
|
||||||
public class Semester {
|
public class Semester {
|
||||||
|
@ -5,6 +5,10 @@ using System.Linq;
|
|||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 用于最终呈现的排课完毕的课表数据。
|
||||||
|
/// 方便模拟器和图片输出接口使用的课表数据,是用户输入课表的最终“编译”后的形式。
|
||||||
|
/// </summary>
|
||||||
namespace HFUTCourseSimulation.Kernel.Data.Presentation {
|
namespace HFUTCourseSimulation.Kernel.Data.Presentation {
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -30,42 +34,37 @@ namespace HFUTCourseSimulation.Kernel.Data.Presentation {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public class Semester {
|
public class Semester {
|
||||||
/// <summary>
|
|
||||||
/// 学期开始日期。
|
|
||||||
/// 该类保证该日期一定是星期一,且没有时间数据。
|
|
||||||
/// </summary>
|
|
||||||
public readonly DateTime startDate;
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 教学周个数。
|
/// 教学周个数。
|
||||||
/// 该类保证该数值与weeks中存储的数据个数相同。
|
/// 该类保证该数值与weeks中存储的数据个数相同。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public readonly int weekCount;
|
public int weekCount;
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 每天课程的节次数。
|
/// 每天课程的节次数。
|
||||||
/// 该类保证该数值总是大于等于1。
|
/// 该类保证该数值总是大于等于1。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public readonly int indexCount;
|
public int indexCount;
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 早餐插入在第几节次后。
|
/// 早餐插入在第几节次后。
|
||||||
/// 该类保证该数值总是位于0至indexCount之间(含首尾)。
|
/// 该类保证该数值总是位于0至indexCount之间(含首尾)。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public readonly int breakfastAt;
|
public int breakfastAt;
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 午餐插入在第几节次后。
|
/// 午餐插入在第几节次后。
|
||||||
/// 该类保证该数值总是位于0至indexCount之间(含首尾),
|
/// 该类保证该数值总是位于0至indexCount之间(含首尾),
|
||||||
/// 且总是大于等于breakfastAt。
|
/// 且总是大于等于breakfastAt。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public readonly int lunchAt;
|
public int lunchAt;
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 晚餐插入在第几节次后。
|
/// 晚餐插入在第几节次后。
|
||||||
/// 该类保证该数值总是位于0至indexCount之间(含首尾),
|
/// 该类保证该数值总是位于0至indexCount之间(含首尾),
|
||||||
/// 且总是大于等于lunchAt。
|
/// 且总是大于等于lunchAt。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public readonly int dinnerAt;
|
public int dinnerAt;
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 每周课程数据。
|
/// 每周课程数据。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public readonly ImmutableList<Week> weeks;
|
public ImmutableList<Week> weeks;
|
||||||
|
|
||||||
public IndexKind GetIndexKind(int index) {
|
public IndexKind GetIndexKind(int index) {
|
||||||
if (index <= 0) throw new ArgumentException("index out of range");
|
if (index <= 0) throw new ArgumentException("index out of range");
|
||||||
@ -82,41 +81,44 @@ namespace HFUTCourseSimulation.Kernel.Data.Presentation {
|
|||||||
/// 每周七天的数据。
|
/// 每周七天的数据。
|
||||||
/// 该类保证该字段总包含7项。
|
/// 该类保证该字段总包含7项。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public readonly ImmutableList<Day> days;
|
public ImmutableList<Day> days;
|
||||||
}
|
}
|
||||||
|
|
||||||
public class Day {
|
public class Day {
|
||||||
|
/// <summary>
|
||||||
|
/// 这一天的日期的字符串形式
|
||||||
|
/// </summary>
|
||||||
|
public string date;
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 这一天的所有课程。
|
/// 这一天的所有课程。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public readonly ImmutableList<Lesson> lessons;
|
public ImmutableList<Lesson> lessons;
|
||||||
}
|
}
|
||||||
|
|
||||||
public class Lesson {
|
public class Lesson {
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 课程的名称。
|
/// 课程的名称。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public readonly string name;
|
public string name;
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 课程的说明,例如教室位置,教师姓名等。
|
/// 课程的说明,例如教室位置,教师姓名等。
|
||||||
/// 该值可以包含换行。
|
/// 该值可以包含换行。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public readonly string description;
|
public string description;
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 课程的颜色
|
/// 课程的颜色
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public readonly Util.ColorPair color;
|
public Util.ColorPair color;
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 课程的起始节次。
|
/// 课程的起始节次。
|
||||||
/// 该类保证该值位于1到indexCount之间(含首尾)。
|
/// 该类保证该值位于1到indexCount之间(含首尾)。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public readonly int startIndex;
|
public int startIndex;
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 课程的结束节次。
|
/// 课程的节次跨度。
|
||||||
/// 该类保证该值位于1到indexCount之间(含首尾),
|
/// 该类保证该值总大于0,且加上startIndex后不会大于节次数。
|
||||||
/// 且大于等于startIndex。
|
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public readonly int endIndex;
|
public int indexSpan;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -8,6 +8,10 @@ using System.Text;
|
|||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using System.Windows.Media;
|
using System.Windows.Media;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 用于保存到文件的课表数据。
|
||||||
|
/// 同时也是程序中作为转换核心的数据结构,各种课表数据之间的转换以该结构为核心。
|
||||||
|
/// </summary>
|
||||||
namespace HFUTCourseSimulation.Kernel.Data.Storage {
|
namespace HFUTCourseSimulation.Kernel.Data.Storage {
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -7,6 +7,10 @@ using System.Text;
|
|||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using System.Windows.Media;
|
using System.Windows.Media;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 用于用户界面呈现的课表数据。
|
||||||
|
/// 该命名空间的类针对WPF的UI实现了特殊的接口,以正确地和用户交互。
|
||||||
|
/// </summary>
|
||||||
namespace HFUTCourseSimulation.Kernel.Data.Ui {
|
namespace HFUTCourseSimulation.Kernel.Data.Ui {
|
||||||
|
|
||||||
public class Semester : INotifyPropertyChanged {
|
public class Semester : INotifyPropertyChanged {
|
||||||
|
Reference in New Issue
Block a user