From 5c75ee10a241c216d7a6ec0558249172bbec6826 Mon Sep 17 00:00:00 2001 From: SowinskiBraeden Date: Tue, 15 Nov 2022 16:37:58 -0800 Subject: [PATCH] update extracting grade scripts --- app/generator.py | 23 ++++++++++++----------- app/util/courses.py | 9 +++++---- app/util/estimateGrade.py | 34 ++++++++++++++++++++++++++++------ app/util/students.py | 12 ++++++------ 4 files changed, 51 insertions(+), 27 deletions(-) diff --git a/app/generator.py b/app/generator.py index 0e9439a..947f38f 100644 --- a/app/generator.py +++ b/app/generator.py @@ -4,7 +4,7 @@ import random from string import hexdigits from app.util.globals import flex, Error -from app.util.estimateGrade import getGradeFromCourseCode +from app.util.estimateGrade import getGrade # Takes in information to create or add a new conflict # Returns if the particular student has a previous error @@ -34,15 +34,15 @@ def insertConflictSolutions(pupilNum: str, logs: dict, data: dict) -> None: # Then it starts to attempt to fit all classes into a timetable, making corretions along # the way. Corrections being moving a students class def generateScheduleV3( - students: list, # Refer to /util/mockStudents.py to see the students list structure - courses: dict, # Reger to /util/generateCourses.py to see the courses dictionary structure - minReq: int=18, # minimum requests for a class to run - classCap: int=30, # maximum students per class - blockClassLimit: int=40, # Block class limit is the number of classrooms available per block. Default 40 classes per block - totalBlocks: int=10, # total blocks between two semesters -> default is 10 for 5 per semester... or this can be 8 for 4 blocks per semester - studentsDir: str="../output/raw/students.json", - conflictsDir: str="../output/raw/conflicts.json", - coursesDir: str="../output/raw/courses.json" + students: list, # Refer to /util/students.py to see the students list structure + courses: dict, # Refer to /util/courses.py to see the courses dictionary structure + minReq: int = 18, # minimum requests for a class to run + classCap: int = 30, # maximum students per class + blockClassLimit: int = 40, # Block class limit is the number of classrooms available per block. Default 40 classes per block + totalBlocks: int = 10, # total blocks between two semesters -> default is 10 for 5 per semester... or this can be 8 for 4 blocks per semester + studentsDir: str = "../output/raw/students.json", + conflictsDir: str = "../output/raw/conflicts.json", + coursesDir: str = "../output/raw/courses.json" ) -> tuple[dict, Error]: # Returns the completed 'running' dictionary from above # Return error that totalBlocks is invalid @@ -469,7 +469,8 @@ def generateScheduleV3( for obj in missing: blockSolution = { "CrsNo": obj["CrsNo"], "block": obj['block'], "solutions": [] } for cname in running[obj['block']]: - courseGrade = getGradeFromCourseCode(cname[:-2]) + courseInfo = running[obj['block']][cname] + courseGrade = getGrade(courseInfo['CrsNo'], courseInfo['Description']) if courseGrade is None: continue if (student["gradelevel"] == courseGrade) or (student["gradelevel"] == 12 and courseGrade == 11): if len(running[obj['block']][cname]["students"]) < classCap: diff --git a/app/util/courses.py b/app/util/courses.py index a7a0ff5..823e25c 100644 --- a/app/util/courses.py +++ b/app/util/courses.py @@ -1,13 +1,13 @@ #!/usr/bin/env python3.11 import json import csv -from app.util.estimateGrade import getGradeFromCourseCode +from app.util.estimateGrade import getGrade # Get all requested courses from data def getCourses( data_dir: str, - log: int=False, - log_dir: str='./output/raw/courses.json', + log: int = False, + log_dir: str = './output/raw/courses.json', ) -> dict[dict[str: any]]: courses = {} @@ -20,13 +20,14 @@ def getCourses( exists = True if courses[course]["CrsNo"] == row["CrsNo"] else False if exists: break if not exists: + grade = getGrade(row["CrsNo"], row["Description"]) courses[row["CrsNo"]] = { "CrsNo": row["CrsNo"], "Requests": 0, "Description": row["Description"], "Sem1": 0, "Sem2":0, - "Grade": getGradeFromCourseCode(row["CrsNo"]) + "Grade": grade } if log: diff --git a/app/util/estimateGrade.py b/app/util/estimateGrade.py index 1772847..5702aab 100644 --- a/app/util/estimateGrade.py +++ b/app/util/estimateGrade.py @@ -3,14 +3,36 @@ from app.util.globals import flex most_frequent = lambda l : max(set(l), key = l.count) -def getGradeFromCourseCode(code: str) -> int: - grades = [int(s) for s in code.split("-") if s.isdigit()] - return None if len(grades) == 0 else most_frequent(grades) +# extract a grade from a course code or description +def extractGrade(string: str) -> int: + if string in flex: return 12 -def getEstimatedGrade(pupil: dict) -> int: + grade = None + for i in range(len(string)): + # If this is a digit like 1 and the next character is a digit like 2 we know the grade is 12 + # or if this digit is 0 and the next digit is 9 we know the grade is 9 + if i != len(string) - 1 and string[i].isdigit() and string[i+1].isdigit(): + grade = int(f'{string[i]}{string[i+1]}') + if grade >= 8: break + + # if the above condition is not met, and we know this is a single number, we can just return this single number as the grade + elif string[i].isdigit(): + grade = int(string[i]) + if grade >= 8: break + + return grade if grade is not None and grade >= 8 else None + +# Estimage students grade based off requests +def estimateStudentGrade(pupil: dict) -> int: grades = [] # List of all possible grades for request in (r for r in pupil["requests"] if r not in flex): - for extractedGrade in [int(s) for s in request["CrsNo"].split("-") if s.isdigit()]: - grades.append(extractedGrade) + extractedGrade = getGrade(request["CrsNo"], request["Description"]) + if extractedGrade is not None: grades.append(extractedGrade) return None if len(grades) == 0 else most_frequent(grades) # Final estimate of grade + +# anlyse course code and description for best grade estimate +def getGrade(crsNo: str, crsDes: str) -> int: + grade = extractGrade(crsDes) + if grade is None: grade = extractGrade(crsNo) + return grade diff --git a/app/util/students.py b/app/util/students.py index 7eb40ea..77fe53d 100644 --- a/app/util/students.py +++ b/app/util/students.py @@ -1,15 +1,15 @@ #!/usr/bin/env python3.11 import json import csv -from app.util.estimateGrade import getEstimatedGrade +from app.util.estimateGrade import estimateStudentGrade from app.util.globals import flex # sort data into usable dictionary def getStudents( - data_dir: str, - log: bool=False, - totalBlocks: int=10, - log_dir: str='./output/raw/students.json' + data_dir: str, + log: bool = False, + totalBlocks: int = 10, + log_dir: str = './output/raw/students.json' ) -> list[ dict[ str: any ] ]: students: list[ dict[ str: any ] ] = [] @@ -50,7 +50,7 @@ def getStudents( # Estimate student grades for student in students: - student["gradelevel"] = getEstimatedGrade(student) + student["gradelevel"] = estimateStudentGrade(student) if log: with open(log_dir, "w") as outfile: