private int numClashes(ScheduledClass scheduledClass, byte[] slots) { var classes = new List <ScheduledClass> { scheduledClass }.Concat(scheduledClass.ChildClasses); //Don't care about classes we have no choice about clashing if (scheduledClass.OnlyChoice) { return(0); } int clashes = 0; foreach (var childClass in classes) { for (int i = childClass.SlotStart; i < childClass.SlotEnd; i++) { if (slots[i] > 0) { clashes++; break; } } } return(clashes); }
private byte[] updateSlots(ScheduledClass scheduledClass, byte[] slots) { var newSlots = new byte[24 * 4 * 5]; Array.Copy(slots, newSlots, slots.Length); //Don't care about classes we have no choice about clashing if (scheduledClass.OnlyChoice) { return(newSlots); } var classes = new List <ScheduledClass> { scheduledClass }.Concat(scheduledClass.ChildClasses); foreach (var childClass in classes) { for (int i = childClass.SlotStart; i < childClass.SlotEnd; i++) { newSlots[i]++; } } return(newSlots); }
private bool classEquivalent(ScheduledClass a, ScheduledClass b) { //optimising this way not worth it if there are child classes if (a.ChildClasses.Any() || b.ChildClasses.Any()) { return(false); } return(a.SlotStart == b.SlotStart && a.SlotEnd == b.SlotEnd); }
public Timetable(List <ScheduledClass> permutation) { int size = permutation.Count + permutation.Sum(c => c.ChildClasses.Count); Classes = new ScheduledClass[size]; int i = 0; foreach (var scheduledClass in permutation) { Classes[i] = scheduledClass; i++; foreach (var childClass in scheduledClass.ChildClasses) { Classes[i] = childClass; i++; } } }
public Timetable(List <ScheduledClass> permutation) { int size = permutation.Count + permutation.Sum(c => c.ChildClasses.Count); Classes = new ScheduledClass[size]; //Fill the classes array, including all child classes int j = 0; foreach (var scheduledClass in permutation) { Classes[j] = scheduledClass; j++; foreach (var childClass in scheduledClass.ChildClasses) { Classes[j] = childClass; j++; } } //Calculate average start time and total number of days long startTimes = 0; for (int i = 1; i <= 5; i++) { var classes = Classes.Where(c => (int)c.TimeStart.DayOfWeek == i).OrderBy(c => c.TimeStart); if (classes.Any()) { NumberDaysClasses++; startTimes += classes.First().TimeStart.TimeOfDay.Ticks; } } AverageStartTime = startTimes / NumberDaysClasses; }
private async Task downloadTimetable() { ClassInfos = new List <ClassInfo>(); string resultStr = await getTimetableHTML(Code); HtmlDocument doc = new HtmlDocument(); doc.LoadHtml(resultStr); List <HtmlNode> tables = doc.DocumentNode.Descendants("table").ToList(); List <HtmlNode> rows = new List <HtmlNode>(); //We look for the first non-empty table //This is okay as everything is filtered elsewhere (so we can ignore summer/winter/whatever) int i = 0; while (!rows.Any()) { HtmlNode timesTable = tables.Skip(i++).FirstOrDefault(); if (timesTable == null) { return; } rows = timesTable.Descendants("tbody").First().Descendants("tr").ToList(); } foreach (var row in rows) { try { var elements = row.Descendants("td").ToArray(); string date = elements[9].InnerText; string startTime = date + " " + elements[3].InnerText; string endTime = date + " " + elements[4].InnerText; string[] info = elements[0].InnerText.Split('/'); var timeStart = DateTime.ParseExact(startTime, "dd MMM yyyy HH:mm", CultureInfo.InvariantCulture); var timeEnd = DateTime.ParseExact(endTime, "dd MMM yyyy HH:mm", CultureInfo.InvariantCulture); ScheduledClass scheduledClass = new ScheduledClass(timeStart, timeEnd) { Location = elements[7].InnerText, ClassNumber = short.Parse(info[5]) }; //Don't include Breakout classses, they're useless if (info[4].Contains("Breakout")) { continue; } var classInfo = ClassInfos.FirstOrDefault(c => c.ClassType == info[4]); if (classInfo != null) { scheduledClass.ClassInfo = classInfo; classInfo.ScheduledClasses.Add(scheduledClass); } else { classInfo = new ClassInfo { ClassName = elements[1].InnerText, ScheduledClasses = new List <ScheduledClass> { scheduledClass }, ParentSubject = this, ClassType = info[4] }; scheduledClass.ClassInfo = classInfo; ClassInfos.Add(classInfo); } } catch (Exception)//Sadly can't trust timetable to be in correct format { } } }
public async Task UpdateTimetable() { ClassInfos = new List <ClassInfo>(); string resultStr = await getTimetableHTML(Code); HtmlDocument doc = new HtmlDocument(); doc.LoadHtml(resultStr); var tables = doc.DocumentNode.Descendants("table"); IEnumerable <HtmlNode> rows = new List <HtmlNode>(); //We look for the first non-empty table //This is okay as everything is filtered elsewhere (so we can ignore summer/winter/whatever) int i = 0; while (!rows.Any()) { HtmlNode timesTable = tables.Skip(i).FirstOrDefault(); if (timesTable == null) { return; } rows = timesTable.Descendants("tbody").First().Descendants("tr"); i++; } foreach (var row in rows) { try { var elements = row.Descendants("td").ToArray(); string date = elements[9].InnerText; string start = date + " " + elements[3].InnerText; string end = date + " " + elements[4].InnerText; string[] info = elements[0].InnerText.Split('/'); var timeStart = DateTime.ParseExact(start, "dd MMM yyyy HH:mm", CultureInfo.InvariantCulture); var timeEnd = DateTime.ParseExact(end, "dd MMM yyyy HH:mm", CultureInfo.InvariantCulture); ScheduledClass scheduledClass = new ScheduledClass(timeStart, timeEnd) { Location = elements[7].InnerText, ClassNumber = short.Parse(info[5]) }; //Don't include Breakout classses, they're useless if (info[4].Contains("Breakout")) { continue; } var classInfo = ClassInfos.FirstOrDefault(c => c.ClassType == info[4]); if (classInfo != null) { scheduledClass.ClassInfo = classInfo; classInfo.ScheduledClasses.Add(scheduledClass); } else { classInfo = new ClassInfo { ClassName = elements[1].InnerText, ScheduledClasses = new List <ScheduledClass> { scheduledClass }, ParentSubject = this, ClassType = info[4] }; scheduledClass.ClassInfo = classInfo; ClassInfos.Add(classInfo); } } catch (Exception)//Sadly can't trust timetable to be in correct format { } } //Make a copy of the originals to be used in rendering OriginalClassInfos = new List <ClassInfo>(ClassInfos); consolidateClasses(); //Removing equivalent classes: foreach (var classInfo in ClassInfos) { var removals = new List <ScheduledClass>();//Can't remove them during enumeration, must collect to remove later foreach (var scheduledClass in classInfo.ScheduledClasses) { if (removals.Contains(scheduledClass)) { continue; } var equivalents = classInfo.ScheduledClasses.Where(b => classEquivalent(scheduledClass, b) && b != scheduledClass); removals.AddRange(equivalents); } foreach (var removal in removals) { classInfo.ScheduledClasses.Remove(removal); } } DateTime earliestClass = DateTime.MaxValue; foreach (var scheduledClass in AllClasses) { if (scheduledClass.TimeStart < earliestClass) { earliestClass = scheduledClass.TimeStart; } } int earliestWeek = getWeekOfYear(earliestClass); foreach (var scheduledClass in AllClasses) { while (getWeekOfYear(scheduledClass.TimeStart) > earliestWeek) { scheduledClass.TimeStart = scheduledClass.TimeStart - TimeSpan.FromDays(7); scheduledClass.TimeEnd = scheduledClass.TimeEnd - TimeSpan.FromDays(7); } } }