public static IEnumerable <StudyPlan> TryToImproveSchedule(StudyPlan plan) { // TODO: Fixme Semester first = currentSemester; Semester last = FSharpSchedulingWizard.lastSemester(plan); Semester bestPossible = bestAchievable(plan); //variables for mutating to get the results using while loop IEnumerable <StudyPlan> bestPlans = new StudyPlan[] { }; Semester targetGraduation = StudyPlannerModel.previousSemester(last); while (targetGraduation.CompareTo(bestPossible) >= 0) { IEnumerable <PlannedUnit> bounds = BoundsOptimizer.boundUnitsInPlan(plan, first, targetGraduation); StudyPlan newPlan = scheduleRemaning(bounds, new UnitInPlan[] { }); if (newPlan == null) { break; } //append the newPlan and try to get better plan with tighter target graduation semester bestPlans = bestPlans.Concat(new[] { newPlan }); targetGraduation = StudyPlannerModel.previousSemester(FSharpSchedulingWizard.lastSemester(newPlan)); } return(bestPlans); }
private Task Wizard(bool FSharpVersion) { cancelWizard = new CancellationTokenSource(); // run the study plan wizard in the background on a separate thread (so that the UI remains responsive) return(Task.Run(() => { if (plan.Items.Count() > 0 && StudyPlannerModel.isLegalPlan(plan.Items)) { IEnumerable <StudyPlan> wizard; if (FSharpVersion) { wizard = FSharpSchedulingWizard.TryToImproveSchedule(plan.Items); } else { wizard = CSharpSchedulingWizard.TryToImproveSchedule(plan.Items); } foreach (var betterPlan in wizard) { Debug.Assert(StudyPlannerModel.isLegalPlan(plan.Items)); uiFactory.StartNew(() => { // present each progressively improved study plan as they are discovered plan.Clear(); plan.AddRange(betterPlan); }, cancelWizard.Token); } } }, cancelWizard.Token)); }
// Transform the study plan (a list of enrolled units) into a list of semesters, each with their own list of enrolled units private IEnumerable <SemesterPlan> projectPlan() { List <SemesterPlan> semesters = new List <SemesterPlan>(); var thisYear = System.DateTime.Now.Year; for (int year = thisYear + 5; year >= thisYear - 4; year--) { foreach (var offering in new Offering[] { Offering.Semester2, Offering.Semester1 }) { Semester semester = new Semester(year, offering); semesters.Add(new SemesterPlan { label = StudyPlannerModel.display(semester), semester = semester, enrollable = inFlightUnitCode != null && StudyPlannerModel.isEnrollableIn(inFlightUnitCode, semester, plan.Items), units = plan.Items .Where(unit => unit.semester.Equals(semester)) .Select(unit => new UnitInSemester { unit = unit, offering = StudyPlannerModel.displayOffered(unit.code), group = getGroup(unit.code, unit.studyArea), statusColour = StudyPlannerModel.isLegalIn(unit.code, semester, plan.Items) ? StudyAreaColour(unit.studyArea) : "Red" }) }); } } return(semesters); }
private static StudyPlan scheduleRemaning(IEnumerable <PlannedUnit> remainingUnits, StudyPlan plannedUnits) { try { if (!remainingUnits.Any()) { return(plannedUnits); } PlannedUnit schedulableUnit = remainingUnits.First( unit => unit.possibleSemesters.Where( sem => StudyPlannerModel.isEnrollableIn(unit.code, sem, plannedUnits) ).Any() ); foreach (var sem in schedulableUnit.possibleSemesters) { if (StudyPlannerModel.isEnrollableIn(schedulableUnit.code, sem, plannedUnits)) { UnitInPlan newUnitPlan = new UnitInPlan(schedulableUnit.code, schedulableUnit.studyArea, sem); StudyPlan scheduleEachSem = scheduleRemaning(remainingUnits.Where(unit => unit.code != schedulableUnit.code), plannedUnits.Concat(new UnitInPlan[] { newUnitPlan })); if (scheduleEachSem != null) { return(scheduleEachSem); } } } }catch (Exception ex) //if can't find any schedulable unit while there are still units needed to add to the plan { return(null); } return(null); //if can't add all the remaining units }
public static IEnumerable <StudyPlan> TryToImproveSchedule(StudyPlan plan) { List <StudyPlan> improvedPlans = new List <StudyPlan>(); // earliest possible sem + first and last sem of study plan Semester earliestPossible = bestPossible(plan, currentSemester); Semester firstSem = currentSemester; /// Semester lastSem = latestSem(plan); // get target completion date Semester target = StudyPlannerModel.previousSemester(lastSem); // /// create new bounds with target completion to be rescheduled into a new study plan List <PlannedUnit> newBound = BoundsOptimizer.boundUnitsInPlan(plan, firstSem, target).ToList(); StudyPlan newPlan; while (target.CompareTo(earliestPossible) >= 0) // while target is still possible { // if bounds infeasible then can't reschedule if (!FSharpSchedulingWizard.allBoundsFeasible(ListModule.OfSeq(newBound))) { return(improvedPlans); /// return sequence } // otherwise, add plan to improved plans newPlan = scheduleRemaining(newBound, new List <UnitInPlan>()); if (newPlan is null) { break; // stop trying to find better plans } improvedPlans.Add(newPlan); // update target semester target = StudyPlannerModel.previousSemester(latestSem(newPlan)); // update new bounds for 1 sem earlier newBound = BoundsOptimizer.boundUnitsInPlan(newPlan, firstSem, target).ToList(); } return(improvedPlans); }
// Update the status colours of the units in the study plan(s) private IEnumerable <StudyArea> enrollable(IEnumerable <UnitInPlan> plan, IEnumerable <StudyArea> studyareas) { foreach (var area in studyAreas) { foreach (var unit in area.units) { if (plan.Any(unitInPlan => unitInPlan.code == unit.code)) // units that are already enrolled are shown using the colour of the study area { unit.statusColour = StudyAreaColour(plan.First(unitInPlan => unitInPlan.code == unit.code).studyArea); } else if (StudyPlannerModel.isEnrollable(unit.code, plan)) // units that can be enrolled are shown in green { unit.statusColour = "Lime"; } else { unit.statusColour = "LightGray"; // units that cannot yet be enrolled are shown in gray } } } return(new List <StudyArea>(studyAreas)); }
public static StudyPlan scheduleRemaining(List <PlannedUnit> boundUnits, List <UnitInPlan> plan) { if (boundUnits.Count == 0) // all units have been scheduled, so return plan { return(plan); } PlannedUnit firstUnit = boundUnits.FirstOrDefault(unit => unit.possibleSemesters .Any(sem => StudyPlannerModel.isEnrollableIn(unit.code, sem, plan))); if (firstUnit is null) // we have failed in finding an enrollable unit, so cannot complete schedule { return(null); } // otherwise schedule in possible semester foreach (Semester sem in firstUnit.possibleSemesters) { if (StudyPlannerModel.isEnrollableIn(firstUnit.code, sem, plan)) { UnitInPlan newUnit = new UnitInPlan(firstUnit.code, firstUnit.studyArea, sem); IEnumerable <UnitInPlan> newPlan = plan.Append(newUnit); // add new unit to plan IEnumerable <PlannedUnit> newBound = boundUnits.Where(subject => subject.code != newUnit.code); // remove new unit from planned units StudyPlan final = scheduleRemaining(newBound.ToList(), newPlan.ToList()); // try to schedule the rest of the planned units // if we finish with a plan that is not null, then we hav succeeded and return plan if (!(final is null)) { return(final); } } } // otherwise no possible choices return(null); }
// Can we legally drop the currently inFlight unit in the specified semester? private bool CanScheduleIn(Semester semester) { return(inFlightUnitCode != null && StudyPlannerModel.isEnrollableIn(inFlightUnitCode, semester, plan.Items)); }
// Load a new course by parsing Study Area information from a CSV resourse file private IEnumerable <StudyArea> LoadCourse(string CVSFile) { var studyAreas = new List <StudyArea>(); using (var file = new System.IO.StringReader(CVSFile)) { while (true) { var studyArea = new StudyArea(); studyArea.code = file.ReadLine(); if (studyArea.code == "" || studyArea.code == null) { break; } studyArea.title = file.ReadLine(); studyArea.colour = file.ReadLine(); var units = new List <UnitInStudyArea>(); studyArea.units = units; studyAreas.Add(studyArea); while (true) { var line = file.ReadLine(); if (line == null) { break; } var csv = line.Split(','); if (csv.Length < 3) { break; } else { units.Add(new UnitInStudyArea { code = csv[0], studyArea = studyArea.code, XPos = ScaleX(double.Parse(csv[1])), YPos = ScaleY(double.Parse(csv[2])), offering = StudyPlannerModel.displayOffered(csv[0]), group = csv[3] }); } } } } return(studyAreas); }
public string getPrereq(string unitCode) { return(StudyPlannerModel.getPrereq(unitCode)); }
// Miscellaneous getter methods ... public string getUnitTitle(string unitCode) { return(StudyPlannerModel.getUnitTitle(unitCode)); }