refactor: finish simulator

This commit is contained in:
2025-09-07 17:31:13 +08:00
parent f72b244b90
commit 7768fd337c
8 changed files with 220 additions and 460 deletions

View File

@ -0,0 +1,31 @@
<Window x:Class="HFUTCourseSimulation.Dialog.Simulator"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:HFUTCourseSimulation.Dialog"
mc:Ignorable="d"
x:Name="uiMainWindow"
Title="课表模拟器" Height="500" Width="700" Closed="uiMainWindow_Closed" Loaded="uiMainWindow_Loaded">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid>
<StackPanel HorizontalAlignment="Center" Orientation="Horizontal" VerticalAlignment="Center">
<TextBlock Text="教学周:"/>
<TextBlock x:Name="uiWeek" Text="1"/>
</StackPanel>
<Button x:Name="uiBtnPre" HorizontalAlignment="Left" Content="上一周" Margin="5" Padding="5" Click="uiBtnPre_Click"/>
<Button x:Name="uiBtnNext" HorizontalAlignment="Right" Content="下一周" Margin="5" Padding="5" Click="uiBtnNext_Click"/>
</Grid>
<Grid x:Name="uiCoreGrid" Grid.Row="1">
</Grid>
</Grid>
</Window>

View File

@ -0,0 +1,174 @@
using HFUTCourseSimulation.Kernel.Data.Presentation;
using HFUTCourseSimulation.Util;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
namespace HFUTCourseSimulation.Dialog {
/// <summary>
/// Interaction logic for Simulator.xaml
/// </summary>
public partial class Simulator : Window {
private static readonly string[] WEEK_NAMES = new string[] {
"星期一",
"星期二",
"星期三",
"星期四",
"星期五",
"星期六",
"星期日"
};
public Simulator() {
InitializeComponent();
// Initialize container
weekTextBlocks = new List<TextBlock>();
courseBlocks = new List<Border>();
currentWeek = 1;
}
public Kernel.Data.Presentation.Semester CurrentSemester { get; set; }
private int currentWeek;
private List<TextBlock> weekTextBlocks;
private List<Border> courseBlocks;
private void uiMainWindow_Loaded(object sender, RoutedEventArgs e) {
// Initialize UI layout by semester
// Setup grid rows and columns
uiCoreGrid.ColumnDefinitions.Add(new ColumnDefinition() { Width = new GridLength(1, GridUnitType.Auto) });
for (int i = 0; i < WEEK_NAMES.Length; ++i) {
uiCoreGrid.ColumnDefinitions.Add(new ColumnDefinition() { Width = new GridLength(1, GridUnitType.Star) });
}
uiCoreGrid.RowDefinitions.Add(new RowDefinition() { Height = new GridLength(1, GridUnitType.Auto) });
uiCoreGrid.RowDefinitions.Add(new RowDefinition() { Height = new GridLength(1, GridUnitType.Auto) });
for (int i = 0; i < CurrentSemester.indexCount; ++i) {
uiCoreGrid.RowDefinitions.Add(new RowDefinition() { Height = new GridLength(1, GridUnitType.Star) });
}
// Set header bar
// Setup week text block
for (int week = 1; week <= WEEK_NAMES.Length; ++week) {
var weekLabel = new TextBlock();
weekLabel.Text = WEEK_NAMES[week - 1];
weekLabel.HorizontalAlignment = HorizontalAlignment.Center;
Grid.SetRow(weekLabel, 0);
Grid.SetColumn(weekLabel, week - 1 + 1);
uiCoreGrid.Children.Add(weekLabel);
var weekDateLabel = new TextBlock();
weekDateLabel.Text = "N/A";
weekDateLabel.HorizontalAlignment = HorizontalAlignment.Center;
Grid.SetRow(weekDateLabel, 1);
Grid.SetColumn(weekDateLabel, week - 1 + 1);
uiCoreGrid.Children.Add(weekDateLabel);
weekTextBlocks.Add(weekDateLabel);
}
// Setup index text block
for (int index = 1; index <= CurrentSemester.indexCount; ++index) {
var indexLabel = new TextBlock();
indexLabel.Text = index.ToString();
indexLabel.VerticalAlignment = VerticalAlignment.Center;
indexLabel.HorizontalAlignment = HorizontalAlignment.Center;
Grid.SetColumn(indexLabel, 0);
Grid.SetRow(indexLabel, index - 1 + 2);
uiCoreGrid.Children.Add(indexLabel);
}
// Set corner
var cornerLabel = new TextBlock();
cornerLabel.Text = "节次";
cornerLabel.HorizontalAlignment = HorizontalAlignment.Center;
cornerLabel.VerticalAlignment = VerticalAlignment.Center;
Grid.SetColumn(cornerLabel, 0);
Grid.SetRow(cornerLabel, 0);
Grid.SetRowSpan(cornerLabel, 2);
// Render for week 1
currentWeek = 1;
RenderWeek();
}
private void uiMainWindow_Closed(object sender, EventArgs e) {
// 清空模拟器内容
uiCoreGrid.Children.Clear();
uiCoreGrid.RowDefinitions.Clear();
uiCoreGrid.ColumnDefinitions.Clear();
weekTextBlocks.Clear();
courseBlocks.Clear();
currentWeek = 1;
}
private void RenderWeek() {
// Clear current course blocks
foreach (var block in courseBlocks) {
uiCoreGrid.Children.Remove(block);
}
courseBlocks.Clear();
// Create new course for this week
var week = CurrentSemester.weeks[currentWeek - 1];
for (int i = 0; i < 7; ++i) {
var day = week.days[i];
// 更新标题上的日期
weekTextBlocks[i].Text = day.date;
// 更新当天课程
foreach (var lesson in day.lessons) {
var courseBlock = new Border();
courseBlock.Background = new SolidColorBrush(lesson.color.Background);
courseBlock.CornerRadius = new CornerRadius(5);
Grid.SetColumn(courseBlock, i + 1);
Grid.SetRow(courseBlock, lesson.startIndex - 1 + 2);
Grid.SetRowSpan(courseBlock, lesson.indexSpan);
uiCoreGrid.Children.Add(courseBlock);
courseBlocks.Add(courseBlock);
var courseNameLabel = new TextBlock();
courseNameLabel.Text = lesson.name;
courseNameLabel.ToolTip = lesson.description;
courseNameLabel.Foreground = new SolidColorBrush(lesson.color.Foreground);
courseNameLabel.HorizontalAlignment = HorizontalAlignment.Left;
courseNameLabel.VerticalAlignment = VerticalAlignment.Center;
courseBlock.Child = courseNameLabel;
}
}
// 更新教学周序号
uiWeek.Text = currentWeek.ToString();
}
private void uiBtnPre_Click(object sender, RoutedEventArgs e) {
if (currentWeek == 1) {
Win32Dialog.Info("已经是第一周了", "错误");
return;
}
currentWeek--;
RenderWeek();
}
private void uiBtnNext_Click(object sender, RoutedEventArgs e) {
if (currentWeek == CurrentSemester.weekCount) {
Win32Dialog.Info("已经是最后一周了", "错误");
return;
}
currentWeek++;
RenderWeek();
}
}
}

View File

@ -80,6 +80,9 @@
<Compile Include="Dialog\EditSchedule.xaml.cs">
<DependentUpon>EditSchedule.xaml</DependentUpon>
</Compile>
<Compile Include="Dialog\Simulator.xaml.cs">
<DependentUpon>Simulator.xaml</DependentUpon>
</Compile>
<Compile Include="ImageExport.cs" />
<Compile Include="Kernel\Arranger.cs" />
<Compile Include="Kernel\Data\Built.cs" />
@ -104,6 +107,10 @@
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Dialog\Simulator.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="MainWindow.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>

View File

@ -244,8 +244,14 @@ namespace HFUTCourseSimulation {
}
private void uiMenuSimulator_Click(object sender, RoutedEventArgs e) {
//var win = new Simulation();
//win.ShowDialog();
var semester = CurrentSemester.ToStorage();
var reporter = new Kernel.Reporter();
var rv = Kernel.Arranger.Arrange(semester, reporter);
if (rv is null) return;
var dialog = new Dialog.Simulator();
dialog.CurrentSemester = rv;
dialog.ShowDialog();
}
private void uiMenuRender_Click(object sender, RoutedEventArgs e) {

View File

@ -1,110 +0,0 @@
<Window x:Class="HFUTCourseSimulation.Simulation"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:HFUTCourseSimulation"
mc:Ignorable="d"
Title="课表输出" Height="450" Width="800">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="200"/>
</Grid.ColumnDefinitions>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<!-- operator-->
<Grid>
<StackPanel HorizontalAlignment="Center" Orientation="Horizontal" VerticalAlignment="Center">
<TextBlock Text="周:"/>
<TextBlock x:Name="uiWeek" Text="1"/>
</StackPanel>
<Button x:Name="uiBtnPre" HorizontalAlignment="Left" Content="上一周" Margin="5" Height="20" Click="uiBtnPre_Click"/>
<Button x:Name="uiBtnNext" HorizontalAlignment="Right" Content="下一周" Margin="5" Height="20" Click="uiBtnNext_Click"/>
</Grid>
<Grid Grid.Row="1">
<Grid.RowDefinitions>
<RowDefinition Height="auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Grid Background="Gray"/>
<UniformGrid Background="Gray" Rows="1" Columns="7" Grid.Row="0" Grid.Column="1">
<StackPanel Orientation="Vertical">
<TextBlock Text="星期一"/>
<TextBlock x:Name="uiWeek1" Text="1/1"/>
</StackPanel>
<StackPanel Orientation="Vertical">
<TextBlock Text="星期二"/>
<TextBlock x:Name="uiWeek2" Text="1/1"/>
</StackPanel>
<StackPanel Orientation="Vertical">
<TextBlock Text="星期三"/>
<TextBlock x:Name="uiWeek3" Text="1/1"/>
</StackPanel>
<StackPanel Orientation="Vertical">
<TextBlock Text="星期四"/>
<TextBlock x:Name="uiWeek4" Text="1/1"/>
</StackPanel>
<StackPanel Orientation="Vertical">
<TextBlock Text="星期五"/>
<TextBlock x:Name="uiWeek5" Text="1/1"/>
</StackPanel>
<StackPanel Orientation="Vertical">
<TextBlock Text="星期六"/>
<TextBlock x:Name="uiWeek6" Text="1/1"/>
</StackPanel>
<StackPanel Orientation="Vertical">
<TextBlock Text="星期日"/>
<TextBlock x:Name="uiWeek7" Text="1/1"/>
</StackPanel>
</UniformGrid>
<UniformGrid Background="Gray" Rows="11" Columns="1" Grid.Row="1" Grid.Column="0">
<TextBlock Text="1"/>
<TextBlock Text="2"/>
<TextBlock Text="3"/>
<TextBlock Text="4"/>
<TextBlock Text="5"/>
<TextBlock Text="6"/>
<TextBlock Text="7"/>
<TextBlock Text="8"/>
<TextBlock Text="9"/>
<TextBlock Text="10"/>
<TextBlock Text="11"/>
</UniformGrid>
<Grid x:Name="uiArrangeGrid" Grid.Row="1" Grid.Column="1">
</Grid>
</Grid>
</Grid>
<Grid Grid.Column="1" Background="LightYellow">
<Grid.RowDefinitions>
<RowDefinition Height="auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<TextBlock Text="安排冲突" HorizontalAlignment="Center" Margin="0,10,0,10"/>
<ListBox x:Name="uiArrangeError" Margin="5" Grid.Row="1" Background="#00000000" MouseDoubleClick="uiArrangeError_MouseDoubleClick"/>
</Grid>
</Grid>
</Window>

View File

@ -1,130 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
namespace HFUTCourseSimulation {
/// <summary>
/// Simulation.xaml 的交互逻辑
/// </summary>
public partial class Simulation : Window {
//SimulationCore simulationKernel;
public Simulation() {
InitializeComponent();
////init colums and rows
//for (int i = 0; i < 11; i++) {
// var rows = new RowDefinition();
// rows.Height = new GridLength(1, GridUnitType.Star);
// this.uiArrangeGrid.RowDefinitions.Add(rows);
//}
//for (int i = 0; i < 7; i++) {
// var colums = new ColumnDefinition();
// colums.Width = new GridLength(1, GridUnitType.Star);
// this.uiArrangeGrid.ColumnDefinitions.Add(colums);
//}
//try {
// originDate = DateTime.Parse(General.GeneralSheet.StartDate);
// weekCount = General.GeneralSheet.WeekCount;
//} catch (Exception) {
// MessageBox.Show("周数或日期转换错误,请关闭窗口", "错误", MessageBoxButton.OK, MessageBoxImage.Error, MessageBoxResult.OK);
// this.uiArrangeError.IsEnabled = false;
// this.uiBtnNext.IsEnabled = false;
// this.uiBtnPre.IsEnabled = false;
// return;
//}
//simulationKernel = new SimulationCore(originDate, weekCount);
//simulationKernel.Generate();
////refresh error list
//this.uiArrangeError.Items.Clear();
//foreach (var item in simulationKernel.ErrorList) {
// this.uiArrangeError.Items.Add(item);
//}
//currentWeek = 1;
//this.RenderGrid(simulationKernel.Render(currentWeek));
}
int currentWeek;
int weekCount;
DateTime originDate;
void RenderGrid(RenderWeek weekRes) {
////set date
//uiWeek.Text = weekRes.WeekIndex.ToString();
//uiWeek1.Text = weekRes.WeekDate[0];
//uiWeek2.Text = weekRes.WeekDate[1];
//uiWeek3.Text = weekRes.WeekDate[2];
//uiWeek4.Text = weekRes.WeekDate[3];
//uiWeek5.Text = weekRes.WeekDate[4];
//uiWeek6.Text = weekRes.WeekDate[5];
//uiWeek7.Text = weekRes.WeekDate[6];
////remove all old grid
//this.uiArrangeGrid.Children.Clear();
////generate new
//foreach (var item in weekRes.CourseList) {
// var warp = new Border();
// warp.Background = new SolidColorBrush(item.BkColor);
// warp.CornerRadius = new CornerRadius(5);
// Grid.SetRowSpan(warp, item.Span);
// var nGrid = new Grid();
// nGrid.ToolTip = item.Desc;
// var courseName = new TextBlock();
// courseName.VerticalAlignment = VerticalAlignment.Center;
// courseName.Text = item.Name;
// nGrid.Children.Add(courseName);
// warp.Child = nGrid;
// Grid.SetRow(warp, item.Start.index - 1);
// Grid.SetColumn(warp, item.Start.week - 1);
// this.uiArrangeGrid.Children.Add(warp);
//}
}
private void uiBtnPre_Click(object sender, RoutedEventArgs e) {
//if (currentWeek == 1) {
// MessageBox.Show("已经是第一周了", "错误", MessageBoxButton.OK, MessageBoxImage.Error, MessageBoxResult.OK);
// return;
//}
//currentWeek--;
//this.RenderGrid(simulationKernel.Render(currentWeek));
}
private void uiBtnNext_Click(object sender, RoutedEventArgs e) {
//if (currentWeek == weekCount) {
// MessageBox.Show("已经是最后一周了", "错误", MessageBoxButton.OK, MessageBoxImage.Error, MessageBoxResult.OK);
// return;
//}
//currentWeek++;
//this.RenderGrid(simulationKernel.Render(currentWeek));
}
private void uiArrangeError_MouseDoubleClick(object sender, MouseButtonEventArgs e) {
//if (this.uiArrangeError.SelectedIndex < 0) {
// MessageBox.Show("未选择任何项", "错误", MessageBoxButton.OK, MessageBoxImage.Error, MessageBoxResult.OK);
// return;
//}
//MessageBox.Show(this.simulationKernel.ErrorList[this.uiArrangeError.SelectedIndex], "错误详情", MessageBoxButton.OK, MessageBoxImage.Information, MessageBoxResult.OK);
}
}
}

View File

@ -1,162 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Media;
namespace HFUTCourseSimulation {
//public class SimulationCore {
// public SimulationCore(DateTime startDate, int weekCount) {
// this.weekCount = weekCount;
// this.originDate = startDate;
// }
// Dictionary<Vector3, SimulationItem> itemDict = new Dictionary<Vector3, SimulationItem>();
// public List<string> ErrorList { get; } = new List<string>();
// //List<Grid> uiList = new List<Grid>();
// DateTime originDate;
// int weekCount;
// //int currentWeek;
// public void Generate() {
// //pre-generate
// foreach (var item in General.GeneralSheet.Courses) {
// foreach (var inner in item.Schedule) {
// var weekRes = GetArrange(inner.Week);
// var dayRes = GetArrange(inner.Day);
// var indexRes = GetArrange(inner.Index);
// foreach (var weekItem in weekRes) {
// foreach (var dayItem in dayRes) {
// foreach (var indexItem in indexRes) {
// var vectorCache = new Vector3(weekItem, dayItem, indexItem);
// if (this.itemDict.Keys.Contains(vectorCache)) {
// ErrorList.Add($"课程冲突:无法将{item.Name}安排到 {weekItem}周,星期{dayItem},第{indexItem}节。因为此处已被{itemDict[vectorCache].Name}占据");
// } else {
// itemDict.Add(vectorCache, new SimulationItem() { Name = item.Name, Desc = item.Description, BkColor = Util.ColorTrans.ToWpfColor(item.BkColor) });
// }
// }
// }
// }
// }
// }
// }
// List<int> GetArrange(string str) {
// var res = new List<int>();
// try {
// if (str.Contains('-')) {
// var strSp = str.Split('-');
// int start = int.Parse(strSp[0]), end = int.Parse(strSp[1]);
// for (int i = start; i <= end; i++) {
// res.Add(i);
// }
// } else if (str.Contains(',')) {
// var strSp = str.Split(',');
// foreach (var item in strSp) {
// res.Add(int.Parse(item));
// }
// } else {
// res.Add(int.Parse(str));
// }
// } catch (Exception) {
// ErrorList.Add("解析错误:" + str);
// }
// return res;
// }
// public RenderWeek Render(int currentWeek) {
// //remove all old grid
// var result = new RenderWeek();
// result.WeekDate = new List<string>();
// //update date
// //comput start date
// result.WeekIndex = currentWeek;
// var pointer = originDate;
// pointer = pointer.AddDays(7 * (currentWeek - 1));
// result.WeekDate.Add($"{pointer.Month}/{pointer.Day}");
// pointer = pointer.AddDays(1);
// result.WeekDate.Add($"{pointer.Month}/{pointer.Day}");
// pointer = pointer.AddDays(1);
// result.WeekDate.Add($"{pointer.Month}/{pointer.Day}");
// pointer = pointer.AddDays(1);
// result.WeekDate.Add($"{pointer.Month}/{pointer.Day}");
// pointer = pointer.AddDays(1);
// result.WeekDate.Add($"{pointer.Month}/{pointer.Day}");
// pointer = pointer.AddDays(1);
// result.WeekDate.Add($"{pointer.Month}/{pointer.Day}");
// pointer = pointer.AddDays(1);
// result.WeekDate.Add($"{pointer.Month}/{pointer.Day}");
// result.CourseList = new List<SimulationRenderItem>();
// //create grid
// var query = (from item in itemDict.Keys
// where item.teachingweek == currentWeek
// select item).ToList();
// while (query.Count != 0) {
// var core = query[0];
// var data = itemDict[core];
// int length = 1;
// //check below
// if (core.index != 1 && query.Contains(core + new Vector3(0, 0, -1))) {
// if (itemDict[core + new Vector3(0, 0, -1)].Name == data.Name) {
// //if below have. jump this->move this to the end
// query.RemoveAt(0);
// query.Add(core);
// continue;
// }
// }
// //check follow
// while (true) {
// if (query.Contains(core + new Vector3(0, 0, length)) && itemDict[core + new Vector3(0, 0, length)].Name == data.Name) {
// query.Remove(core + new Vector3(0, 0, length));
// length++;
// } else break;
// }
// //create
// result.CourseList.Add(new SimulationRenderItem() { Name = data.Name, Desc = data.Desc, BkColor = data.BkColor, Start = core, Span = length });
// /*
// var warp = new Border();
// warp.Background = new SolidColorBrush(Colors.LightBlue);
// warp.CornerRadius = new CornerRadius(5);
// Grid.SetRowSpan(warp, length);
// var nGrid = new Grid();
// nGrid.ToolTip = data.Desc;
// var courseName = new TextBlock();
// courseName.VerticalAlignment = VerticalAlignment.Center;
// courseName.Text = data.Name;
// nGrid.Children.Add(courseName);
// warp.Child = nGrid;
// Grid.SetRow(warp, core.index - 1);
// Grid.SetColumn(warp, core.week - 1);
// this.uiArrangeGrid.Children.Add(warp);
// */
// //remove first item
// query.RemoveAt(0);
// }
// return result;
// }
//}
}

View File

@ -1,56 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Media;
namespace HFUTCourseSimulation {
public class SimulationItem {
public string Name { get; set; }
public string Desc { get; set; }
public Color BkColor { get; set; }
}
public struct Vector3 {
public Vector3(int x, int y, int z) {
teachingweek = x;
week = y;
index = z;
}
public int teachingweek;
public int week;
public int index;
public static Vector3 operator+(Vector3 a, Vector3 b) {
return new Vector3(a.teachingweek + b.teachingweek,
a.week + b.week, a.index + b.index);
}
public static bool operator ==(Vector3 a, Vector3 b) {
return (a.teachingweek == b.teachingweek && a.week == b.week && a.index == b.index);
}
public static bool operator !=(Vector3 a, Vector3 b) {
return !(a == b);
}
public override bool Equals(object obj) {
return (Vector3)obj == this;
}
}
//===========================================================================
public class RenderWeek {
public int WeekIndex { get; set; }
public List<string> WeekDate { get; set; }
public List<SimulationRenderItem> CourseList { get; set; }
}
public class SimulationRenderItem : SimulationItem {
public Vector3 Start { get; set; }
public int Span { get; set; }
}
}