update to latest
This commit is contained in:
5 files changed
+66
-52
No files matched your search
@@ -1,3 +1,4 @@
|
|||||||
|
#! python
|
||||||
import json
|
import json
|
||||||
|
|
||||||
f = open('./output/students.json')
|
f = open('./output/students.json')
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
#!/usr/bin/env python3
|
#! python
|
||||||
import json
|
import json
|
||||||
import math
|
|
||||||
import random
|
import random
|
||||||
from inspect import currentframe
|
from inspect import currentframe
|
||||||
|
|
||||||
@@ -22,7 +21,6 @@ from util.generateCourses import getSampleCourses
|
|||||||
...
|
...
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
running example:
|
running example:
|
||||||
running: {
|
running: {
|
||||||
"block1": {
|
"block1": {
|
||||||
@@ -43,23 +41,17 @@ def getLineNumber(): return currentframe().f_back.f_lineno
|
|||||||
|
|
||||||
# Takes in information to create or add a new conflict
|
# Takes in information to create or add a new conflict
|
||||||
# Returns if the particular student has a previous error
|
# Returns if the particular student has a previous error
|
||||||
def newConflict(pupilNum: str, email: str, type: str, code: str, description: str, logs: dict) -> bool:
|
def newConflict(pupilNum: str, email: str, conflictType: str, code: str, description: str, logs: dict) -> bool:
|
||||||
exists = True if pupilNum in logs else False
|
exists = True if pupilNum in logs else False
|
||||||
if exists: logs[pupilNum].append({
|
log = {
|
||||||
"Pupil #": pupilNum,
|
"Pupil #": pupilNum,
|
||||||
"Email": email,
|
"Email": email,
|
||||||
"Type": type,
|
"Type": conflictType,
|
||||||
"Code": code,
|
"Code": code,
|
||||||
"Conflict": description
|
"Conflict": description
|
||||||
})
|
}
|
||||||
else:
|
if exists: logs[pupilNum].append(log)
|
||||||
logs[pupilNum] = [{
|
else: logs[pupilNum] = [log]
|
||||||
"Pupil #": pupilNum,
|
|
||||||
"Email": email,
|
|
||||||
"Type": type,
|
|
||||||
"Code": code,
|
|
||||||
"Conflict": description
|
|
||||||
}]
|
|
||||||
return exists
|
return exists
|
||||||
|
|
||||||
minReq, median, classCap = 18, 24, 30
|
minReq, median, classCap = 18, 24, 30
|
||||||
@@ -79,7 +71,7 @@ running = {
|
|||||||
|
|
||||||
# These are the codes for Flex (spare) blocks
|
# These are the codes for Flex (spare) blocks
|
||||||
# Semester 1 and 2
|
# Semester 1 and 2
|
||||||
flex = ["XAT--12A-S", "XAT--12B-S"]
|
flex = ("XAT--12A-S", "XAT--12B-S")
|
||||||
|
|
||||||
# V3 differs a lot by V1/2 as it does not focus on fitting the classes
|
# V3 differs a lot by V1/2 as it does not focus on fitting the classes
|
||||||
# into the time table first.
|
# into the time table first.
|
||||||
@@ -118,7 +110,7 @@ def generateScheduleV3(
|
|||||||
for i in range(len(activeCourses)):
|
for i in range(len(activeCourses)):
|
||||||
index = list(activeCourses)[i]
|
index = list(activeCourses)[i]
|
||||||
if index not in emptyClasses: emptyClasses[index] = {}
|
if index not in emptyClasses: emptyClasses[index] = {}
|
||||||
classRunCount = math.floor(activeCourses[index]["Requests"] / median)
|
classRunCount = activeCourses[index]["Requests"] // median
|
||||||
remaining = activeCourses[index]["Requests"] % median
|
remaining = activeCourses[index]["Requests"] % median
|
||||||
|
|
||||||
# Put # of classRunCount classes in emptyClasses
|
# Put # of classRunCount classes in emptyClasses
|
||||||
@@ -269,14 +261,10 @@ def generateScheduleV3(
|
|||||||
# Step 4 - Attempt to fit classes into timetable
|
# Step 4 - Attempt to fit classes into timetable
|
||||||
def stepIndex(offset: int, stepType: int) -> int:
|
def stepIndex(offset: int, stepType: int) -> int:
|
||||||
# stepType 0 is for stepping between first and second semester
|
# stepType 0 is for stepping between first and second semester
|
||||||
if stepType == 0:
|
if stepType == 0: return 5 if offset == 0 or offset == -4 else -4
|
||||||
if offset == 0 or offset == -4: return 5
|
|
||||||
else: return -4
|
|
||||||
|
|
||||||
# stepType 1 is for stepping between second and first semester
|
# stepType 1 is for stepping between second and first semester
|
||||||
elif stepType == 1:
|
elif stepType == 1: return -5 if offset == 0 or offset == 6 else 6
|
||||||
if offset == 0 or offset == 6: return -5
|
|
||||||
else: return 6
|
|
||||||
|
|
||||||
# Return Error if code is altered to cause error
|
# Return Error if code is altered to cause error
|
||||||
else: raise SystemExit(f"Invalid 'stepType' in func 'stepIndex' line {getLineNumber()}")
|
else: raise SystemExit(f"Invalid 'stepType' in func 'stepIndex' line {getLineNumber()}")
|
||||||
@@ -289,12 +277,13 @@ def generateScheduleV3(
|
|||||||
# Tally first and second semester
|
# Tally first and second semester
|
||||||
sem1, sem2 = 0, 0
|
sem1, sem2 = 0, 0
|
||||||
sem1List, sem2List = {}, {}
|
sem1List, sem2List = {}, {}
|
||||||
for i in range(1, 6):
|
for i in range(1, 11):
|
||||||
sem1 += len(running[f"block{i}"])
|
if i <= 5:
|
||||||
sem1List[f"block{i}"] = running[f"block{i}"]
|
sem1 += len(running[f"block{i}"])
|
||||||
for i in range(5, 11):
|
sem1List[f"block{i}"] = running[f"block{i}"]
|
||||||
sem2 += len(running[f"block{i}"])
|
elif i > 5:
|
||||||
sem2List[f"block{i}"] = running[f"block{i}"]
|
sem2 += len(running[f"block{i}"])
|
||||||
|
sem2List[f"block{i}"] = running[f"block{i}"]
|
||||||
|
|
||||||
# If there is more than one class Running
|
# If there is more than one class Running
|
||||||
if allClassRunCounts[index] > 1:
|
if allClassRunCounts[index] > 1:
|
||||||
@@ -330,16 +319,15 @@ def generateScheduleV3(
|
|||||||
semBlocks = []
|
semBlocks = []
|
||||||
offset = 1
|
offset = 1
|
||||||
|
|
||||||
# If sem1 is less than or equal to sem2, add to sem1
|
|
||||||
if sem1 <= sem2:
|
if sem1 <= sem2:
|
||||||
for block in sem1List:
|
for block in sem1List:
|
||||||
semBlocks.append(len(block))
|
semBlocks.append(len(block))
|
||||||
|
|
||||||
|
# If sem1 is less than or equal to sem2, add to sem1
|
||||||
|
if sem1 <= sem2: [semBlocks.append(len(block)) for block in sem1List]
|
||||||
|
|
||||||
# If sem2 is less than sem1, add to sem2
|
# If sem2 is less than sem1, add to sem2
|
||||||
elif sem1 > sem2:
|
elif sem1 > sem2: [semBlocks.append(len(block)) for block in sem2List]
|
||||||
offset = 5
|
|
||||||
for block in sem2List:
|
|
||||||
semBlocks.append(len(block))
|
|
||||||
|
|
||||||
# Get block with least classes
|
# Get block with least classes
|
||||||
leastBlock = semBlocks.index(min(semBlocks))
|
leastBlock = semBlocks.index(min(semBlocks))
|
||||||
@@ -403,14 +391,14 @@ def generateScheduleV3(
|
|||||||
# Check if conflicts have been resolved
|
# Check if conflicts have been resolved
|
||||||
blocks = [student["schedule"][block] for block in student["schedule"]]
|
blocks = [student["schedule"][block] for block in student["schedule"]]
|
||||||
# If there is exceptions, make them look normal in blocks
|
# If there is exceptions, make them look normal in blocks
|
||||||
# list to ginore them when looking for clashes, and not to
|
# list to ignore them when looking for clashes, and not to
|
||||||
# accidently overwrite while evaluating other classes
|
# accidently overwrite while evaluating other classes
|
||||||
if len(exceptions) > 0:
|
if len(exceptions) > 0:
|
||||||
for i in range(len(blocks)):
|
for i in range(len(blocks)):
|
||||||
if i in exceptions: blocks[i] = ['EXPT']
|
if i in exceptions: blocks[i] = ['EXPT']
|
||||||
conflicts = sum(1 for b in blocks if len(b)>1)
|
conflicts = sum(1 for b in blocks if len(b)>1)
|
||||||
|
|
||||||
if conflicts == 0: hasConflicts = False
|
if conflicts == 0: break
|
||||||
|
|
||||||
elif conflicts > 0:
|
elif conflicts > 0:
|
||||||
|
|
||||||
@@ -586,14 +574,20 @@ def generateScheduleV3(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
# Update Student records
|
|
||||||
with open(studentsDir, "w") as outfile:
|
|
||||||
json.dump(students, outfile, indent=2)
|
|
||||||
|
|
||||||
# Log Conflict to records
|
# Log Conflict to records
|
||||||
with open(conflictsDir, "w") as outfile:
|
with open(conflictsDir, "w") as outfile:
|
||||||
json.dump(finalConflictLogs, outfile, indent=2)
|
json.dump(finalConflictLogs, outfile, indent=2)
|
||||||
|
|
||||||
|
for student in students:
|
||||||
|
for block in student["schedule"]:
|
||||||
|
if len(student["schedule"][block]) == 0:
|
||||||
|
if int(block[len(block)-1]) <= 5: student["schedule"][block].append(flex[0])
|
||||||
|
elif int(block[len(block)-1]) > 5: student["schedule"][block].append(flex[1])
|
||||||
|
|
||||||
|
# Update Student records
|
||||||
|
with open(studentsDir, "w") as outfile:
|
||||||
|
json.dump(students, outfile, indent=2)
|
||||||
|
|
||||||
return running
|
return running
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
|
|||||||
+24
-5
@@ -1,6 +1,9 @@
|
|||||||
#!/usr/bin/python3
|
#! python
|
||||||
from prettytable import PrettyTable
|
from prettytable import PrettyTable
|
||||||
from typing import Tuple
|
from typing import Tuple
|
||||||
|
from time import time, sleep
|
||||||
|
import itertools
|
||||||
|
import threading
|
||||||
import json
|
import json
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
@@ -11,6 +14,15 @@ from util.generateCourses import getSampleCourses
|
|||||||
# Import Algorithm
|
# Import Algorithm
|
||||||
from scheduleGenerator.generator import generateScheduleV3
|
from scheduleGenerator.generator import generateScheduleV3
|
||||||
|
|
||||||
|
done = False
|
||||||
|
|
||||||
|
def processing():
|
||||||
|
for c in itertools.cycle(['|', '/', '-', '\\']):
|
||||||
|
if done: break
|
||||||
|
sys.stdout.write(f'\rProcessing {c}')
|
||||||
|
sys.stdout.flush()
|
||||||
|
sleep(0.1)
|
||||||
|
|
||||||
def errorOutput(students) -> Tuple[PrettyTable, dict, dict]:
|
def errorOutput(students) -> Tuple[PrettyTable, dict, dict]:
|
||||||
# Error Table calulation / output
|
# Error Table calulation / output
|
||||||
f = open('./output/conflicts.json')
|
f = open('./output/conflicts.json')
|
||||||
@@ -34,14 +46,23 @@ def errorOutput(students) -> Tuple[PrettyTable, dict, dict]:
|
|||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
|
|
||||||
if len(sys.argv) == 1:
|
if len(sys.argv) == 1:
|
||||||
print("Processing...\n")
|
print()
|
||||||
|
|
||||||
|
st = time() # Start time
|
||||||
|
t = threading.Thread(target=processing)
|
||||||
|
t.start() # Start animation
|
||||||
|
|
||||||
sampleStudents = getSampleStudents("./sample_data/course_selection_data.csv", True)
|
sampleStudents = getSampleStudents("./sample_data/course_selection_data.csv", True)
|
||||||
samplemockCourses = getSampleCourses("./sample_data/course_selection_data.csv", True)
|
samplemockCourses = getSampleCourses("./sample_data/course_selection_data.csv", True)
|
||||||
timetable = {}
|
timetable = {}
|
||||||
timetable["Version"] = 3
|
timetable["Version"] = 3
|
||||||
timetable["timetable"] = generateScheduleV3(sampleStudents, samplemockCourses, 40, "./output/students.json", "./output/conflicts.json")
|
timetable["timetable"] = generateScheduleV3(sampleStudents, samplemockCourses, 40, "./output/students.json", "./output/conflicts.json")
|
||||||
|
|
||||||
|
done = True # End Animation
|
||||||
|
et = time() # End time
|
||||||
|
elapsed_time = round((et - st), 3) # Execution time
|
||||||
|
print(f'\n\nDone - Finished in {elapsed_time} seconds\n')
|
||||||
|
|
||||||
errors, _, _ = errorOutput(sampleStudents)
|
errors, _, _ = errorOutput(sampleStudents)
|
||||||
print(errors)
|
print(errors)
|
||||||
|
|
||||||
@@ -69,5 +90,3 @@ if __name__ == '__main__':
|
|||||||
|
|
||||||
with open("./output/timetable.json", "w") as outfile:
|
with open("./output/timetable.json", "w") as outfile:
|
||||||
json.dump(timetable, outfile, indent=2)
|
json.dump(timetable, outfile, indent=2)
|
||||||
|
|
||||||
print("\nDone")
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
#!/usr/bin/env python3
|
#! python
|
||||||
import json
|
import json
|
||||||
import csv
|
import csv
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
#!/usr/bin/env python3
|
#! python
|
||||||
import json
|
import json
|
||||||
import csv
|
import csv
|
||||||
|
|
||||||
flex= ["XAT--12A-S", "XAT--12B-S"]
|
flex= ("XAT--12A-S", "XAT--12B-S")
|
||||||
|
|
||||||
mockStudents: list[dict] = []
|
mockStudents: list[dict] = []
|
||||||
|
|
||||||
|
|||||||
Reference in new issue
Block a user