diff --git a/HFUTCourseSimulation/App.config b/HFUTCourseSimulation/App.config index 8e15646..bcb2ae2 100644 --- a/HFUTCourseSimulation/App.config +++ b/HFUTCourseSimulation/App.config @@ -1,6 +1,14 @@ - + - + - \ No newline at end of file + + + + + + + + + diff --git a/HFUTCourseSimulation/HFUTCourseSimulation.csproj b/HFUTCourseSimulation/HFUTCourseSimulation.csproj index 2759d81..fffa8ea 100644 --- a/HFUTCourseSimulation/HFUTCourseSimulation.csproj +++ b/HFUTCourseSimulation/HFUTCourseSimulation.csproj @@ -8,10 +8,11 @@ WinExe HFUTCourseSimulation HFUTCourseSimulation - v4.5 + v4.8 512 {60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} 4 + AnyCPU @@ -37,8 +38,24 @@ ..\packages\Newtonsoft.Json.12.0.1\lib\net45\Newtonsoft.Json.dll + + ..\packages\System.Buffers.4.5.1\lib\net461\System.Buffers.dll + + + ..\packages\System.Collections.Immutable.9.0.8\lib\net462\System.Collections.Immutable.dll + + + ..\packages\System.Memory.4.5.5\lib\net461\System.Memory.dll + + + + ..\packages\System.Numerics.Vectors.4.5.0\lib\net46\System.Numerics.Vectors.dll + + + ..\packages\System.Runtime.CompilerServices.Unsafe.6.0.0\lib\net461\System.Runtime.CompilerServices.Unsafe.dll + @@ -60,6 +77,10 @@ + + + + Simulation.xaml diff --git a/HFUTCourseSimulation/Kernel/Context.cs b/HFUTCourseSimulation/Kernel/Context.cs new file mode 100644 index 0000000..06e24ea --- /dev/null +++ b/HFUTCourseSimulation/Kernel/Context.cs @@ -0,0 +1,25 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace HFUTCourseSimulation.Kernel { + + public class Context { + private static Context s_Instance = new Context(); + public static Context GetSingleton() { return s_Instance; } + + private Context() { + currentSemester = null; + currentCourse = null; + currentSchedule = null; + } + + private UserData.Semester currentSemester; + private UserData.Course currentCourse; + private UserData.Schedule currentSchedule; + + } + +} diff --git a/HFUTCourseSimulation/Kernel/MsgRecorder.cs b/HFUTCourseSimulation/Kernel/MsgRecorder.cs new file mode 100644 index 0000000..1139393 --- /dev/null +++ b/HFUTCourseSimulation/Kernel/MsgRecorder.cs @@ -0,0 +1,91 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace HFUTCourseSimulation.Kernel.MsgRecorder { + + /// + /// 消息的类型 + /// + public enum Kind { + Info, + Warning, + Error + } + + /// + /// 被记录的消息条目 + /// + public class Entry { + public Entry(Kind kind, string message) { + this.kind = kind; + this.message = message; + } + + public readonly Kind kind; + public readonly string message; + } + + /// + /// 用于记录模拟过程中的消息(例如错误,警告等) + /// + public class Recorder : IEnumerable { + public Recorder() { + entries = new List(); + hasError = false; + } + + private List entries; + private bool hasError; + + /// + /// 记录一条提示消息 + /// + /// 消息内容 + public void Info(string message) { + entries.Add(new Entry(Kind.Info, message)); + } + /// + /// 记录一条警告消息 + /// + /// 消息内容 + public void Warning(string message) { + entries.Add(new Entry(Kind.Warning, message)); + } + /// + /// 记录一条错误消息 + /// + /// 消息内容 + public void Error(string message) { + this.hasError = true; + entries.Add(new Entry(Kind.Error, message)); + } + + public IEnumerator GetEnumerator() { + return entries.GetEnumerator(); + } + IEnumerator IEnumerable.GetEnumerator() { + return GetEnumerator(); + } + /// + /// 检查过程中是否有错误类型的消息被记录 + /// + /// 如果有则返回true,否则为false + public bool HasError() { + return hasError; + } + + /// + /// 重置记录器状态 + /// + public void Clear() { + entries.Clear(); + hasError = false; + } + + } + +} diff --git a/HFUTCourseSimulation/Kernel/SimData.cs b/HFUTCourseSimulation/Kernel/SimData.cs new file mode 100644 index 0000000..0bccdc6 --- /dev/null +++ b/HFUTCourseSimulation/Kernel/SimData.cs @@ -0,0 +1,124 @@ +using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Drawing; + +namespace HFUTCourseSimulation.Kernel.SimData { + + /// + /// 节次的类型 + /// + public enum IndexKind { + /// + /// 破晓(太阳没升起前) + /// + Dawn, + /// + /// 上午(太阳升起后到正午) + /// + Morning, + /// + /// 下午(正午到太阳落山) + /// + Afternoon, + /// + /// 晚上(太阳落山后) + /// + Night + } + + public class Semester { + /// + /// 学期开始日期。 + /// 该类保证该日期一定是星期一,且没有时间数据。 + /// + public readonly DateTime startDate; + /// + /// 教学周个数。 + /// 该类保证该数值与weeks中存储的数据个数相同。 + /// + public readonly int weekCount; + /// + /// 每天课程的节次数。 + /// 该类保证该数值总是大于等于1。 + /// + public readonly int indexCount; + /// + /// 早餐插入在第几节次后。 + /// 该类保证该数值总是位于0至indexCount之间(含首尾)。 + /// + public readonly int breakfastAt; + /// + /// 午餐插入在第几节次后。 + /// 该类保证该数值总是位于0至indexCount之间(含首尾), + /// 且总是大于等于breakfastAt。 + /// + public readonly int lunchAt; + /// + /// 晚餐插入在第几节次后。 + /// 该类保证该数值总是位于0至indexCount之间(含首尾), + /// 且总是大于等于lunchAt。 + /// + public readonly int dinnerAt; + /// + /// 每周课程数据。 + /// + public readonly ImmutableList weeks; + + public IndexKind GetIndexKind(int index) { + if (index <= 0) throw new ArgumentException("index out of range"); + else if (index <= breakfastAt) return IndexKind.Dawn; + else if (index <= lunchAt) return IndexKind.Morning; + else if (index <= dinnerAt) return IndexKind.Afternoon; + else if (index <= indexCount) return IndexKind.Night; + else throw new ArgumentException("index out of range"); + } + } + + public class Week { + /// + /// 每周七天的数据。 + /// 该类保证该字段总包含7项。 + /// + public readonly ImmutableList days; + } + + public class Day { + /// + /// 这一天的所有课程。 + /// + public readonly ImmutableList lessons; + } + + public class Lesson { + /// + /// 课程的名称。 + /// + public readonly string name; + /// + /// 课程的说明,例如教室位置,教师姓名等。 + /// 该值可以包含换行。 + /// + public readonly string description; + /// + /// 课程的颜色 + /// + public readonly Color color; + /// + /// 课程的起始节次。 + /// 该类保证该值位于1到indexCount之间(含首尾)。 + /// + public readonly int startIndex; + /// + /// 课程的结束节次。 + /// 该类保证该值位于1到indexCount之间(含首尾), + /// 且大于等于startIndex。 + /// + public readonly int endIndex; + } + + +} diff --git a/HFUTCourseSimulation/Kernel/UserData.cs b/HFUTCourseSimulation/Kernel/UserData.cs new file mode 100644 index 0000000..d9a3116 --- /dev/null +++ b/HFUTCourseSimulation/Kernel/UserData.cs @@ -0,0 +1,155 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Drawing; +using System.Globalization; +using Newtonsoft.Json; + +namespace HFUTCourseSimulation.Kernel.UserData { + + /// + /// 学期数据 + /// + public class Semester { + public Semester() { + startDate = DateTime.Today; + weekCount = 20.ToString(); + indexCount = 11.ToString(); + breakfastAt = 0.ToString(); + lunchAt = 4.ToString(); + dinnerAt = 8.ToString(); + courses = new List(); + } + + /// + /// 学期开始日期(星期一) + /// + [JsonProperty("start_date")] + [JsonConverter(typeof(CustomDateTimeConverter))] + public DateTime startDate; + /// + /// 教学周个数 + /// + [JsonProperty("week_count")] + public string weekCount; + /// + /// 每天课程的节次数 + /// + [JsonProperty("index_count")] + public string indexCount; + /// + /// 早餐插入在第几节次后 + /// + [JsonProperty("breakfast_at")] + public string breakfastAt; + /// + /// 午餐插入在第几节次后 + /// + [JsonProperty("lunch_at")] + public string lunchAt; + /// + /// 晚餐插入在第几节次后 + /// + [JsonProperty("dinner_at")] + public string dinnerAt; + /// + /// 课程列表 + /// + [JsonProperty("courses")] + public List courses; + } + + public class Course { + public Course() { + name = ""; + description = ""; + color = Color.LightBlue; + schedules = new List(); + } + + /// + /// 课程的名称 + /// + [JsonProperty("name")] + public string name; + /// + /// 课程的说明,例如教室位置,教师姓名等。 + /// + [JsonProperty("description")] + public string description; + /// + /// 课程的颜色 + /// + [JsonProperty("color")] + [JsonConverter(typeof(CustomColorConverter))] + public Color color; + /// + /// 课程的所有安排 + /// + [JsonProperty("schedules")] + public List schedules; + } + + public class Schedule { + public Schedule() { + week = ""; + day = ""; + index = ""; + } + + /// + /// 安排在哪些周 + /// + [JsonProperty("week")] + public string week; + /// + /// 安排在周的星期几 + /// + [JsonProperty("day")] + public string day; + /// + /// 安排在这些日子的哪些节次 + /// + [JsonProperty("index")] + public string index; + } + + internal class CustomDateTimeConverter : JsonConverter { + private static readonly string DATETIME_FORMAT = "yyyy-MM-dd"; + + public override DateTime ReadJson(JsonReader reader, Type objectType, DateTime existingValue, bool hasExistingValue, JsonSerializer serializer) { + if (reader.TokenType == JsonToken.String) { + var value = reader.Value as string; + if (DateTime.TryParseExact(value, DATETIME_FORMAT, CultureInfo.InvariantCulture, DateTimeStyles.None, out DateTime rv)) { + return rv; + } else { + throw new JsonSerializationException($"given string can not be parsed as DateTime: {value}"); + } + } else { + throw new JsonSerializationException($"expect a string but got {reader.TokenType}"); + } + } + + public override void WriteJson(JsonWriter writer, DateTime value, JsonSerializer serializer) { + writer.WriteValue(value.ToString(DATETIME_FORMAT, CultureInfo.InvariantCulture)); + } + } + + internal class CustomColorConverter : JsonConverter { + public override Color ReadJson(JsonReader reader, Type objectType, Color existingValue, bool hasExistingValue, JsonSerializer serializer) { + if (reader.TokenType == JsonToken.Integer) { + var argb = Convert.ToInt32(reader.Value); + return Color.FromArgb(argb); + } else { + throw new JsonSerializationException($"expect a integer but got {reader.TokenType}"); + } + } + + public override void WriteJson(JsonWriter writer, Color value, JsonSerializer serializer) { + writer.WriteValue(value.ToArgb()); + } + } + +} diff --git a/HFUTCourseSimulation/Properties/Resources.Designer.cs b/HFUTCourseSimulation/Properties/Resources.Designer.cs index 9957e66..c48f6a9 100644 --- a/HFUTCourseSimulation/Properties/Resources.Designer.cs +++ b/HFUTCourseSimulation/Properties/Resources.Designer.cs @@ -1,53 +1,54 @@ //------------------------------------------------------------------------------ // -// 此代码由工具生成。 -// 运行时版本: 4.0.30319.42000 +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 // -// 对此文件的更改可能导致不正确的行为,如果 -// 重新生成代码,则所做更改将丢失。 +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. // //------------------------------------------------------------------------------ namespace HFUTCourseSimulation.Properties { - - + using System; + + /// - /// 强类型资源类,用于查找本地化字符串等。 + /// A strongly-typed resource class, for looking up localized strings, etc. /// - // 此类是由 StronglyTypedResourceBuilder - // 类通过类似于 ResGen 或 Visual Studio 的工具自动生成的。 - // 若要添加或删除成员,请编辑 .ResX 文件,然后重新运行 ResGen - // (以 /str 作为命令选项),或重新生成 VS 项目。 - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")] [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] internal class Resources { - + private static global::System.Resources.ResourceManager resourceMan; - + private static global::System.Globalization.CultureInfo resourceCulture; - + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] internal Resources() { } - + /// - /// 返回此类使用的缓存 ResourceManager 实例。 + /// Returns the cached ResourceManager instance used by this class. /// [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] internal static global::System.Resources.ResourceManager ResourceManager { get { - if ((resourceMan == null)) { + if (object.ReferenceEquals(resourceMan, null)) { global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("HFUTCourseSimulation.Properties.Resources", typeof(Resources).Assembly); resourceMan = temp; } return resourceMan; } } - + /// - /// 覆盖当前线程的 CurrentUICulture 属性 - /// 使用此强类型的资源类的资源查找。 + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. /// [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] internal static global::System.Globalization.CultureInfo Culture { diff --git a/HFUTCourseSimulation/Properties/Settings.Designer.cs b/HFUTCourseSimulation/Properties/Settings.Designer.cs index ea7c749..9f57339 100644 --- a/HFUTCourseSimulation/Properties/Settings.Designer.cs +++ b/HFUTCourseSimulation/Properties/Settings.Designer.cs @@ -9,14 +9,14 @@ //------------------------------------------------------------------------------ namespace HFUTCourseSimulation.Properties { - - + + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "11.0.0.0")] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "17.14.0.0")] internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase { - + private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); - + public static Settings Default { get { return defaultInstance; diff --git a/HFUTCourseSimulation/packages.config b/HFUTCourseSimulation/packages.config index 7f83af3..dca5efc 100644 --- a/HFUTCourseSimulation/packages.config +++ b/HFUTCourseSimulation/packages.config @@ -1,4 +1,9 @@  + + + + + \ No newline at end of file