~fkfd/sections

b782885391e3358f733cdbce4913ea12a21da9f2 — Frederick Yin 1 year, 6 months ago
Brute force algorithm, self-contained Python script
1 files changed, 106 insertions(+), 0 deletions(-)

A main.py
A  => main.py +106 -0
@@ 1,106 @@
#!/usr/bin/python
from itertools import combinations

DAYS_OF_WEEK = ["M", "Tu", "W", "Th", "F"]
PERIODS = ["08", "10", "12", "14", "16", "18"]


def parse_period(period: str) -> tuple:
    dow, prd = period.split(" ")
    return (DAYS_OF_WEEK.index(dow), PERIODS.index(prd))


def print_timetable(courses: dict, choice: list):
    # the design of this program allows only one course per period
    # period-major order because one period == one row when printed
    timetable = [["" for dow in DAYS_OF_WEEK] for prd in PERIODS]
    for course, sec in choice:
        periods = courses[course]["sections"][sec]
        for period in periods:
            dow, prd = parse_period(period)
            timetable[prd][dow] = f"{course}S{sec}"

    print("\t".join(DAYS_OF_WEEK))
    for periods in timetable:
        print("\t".join(periods))


def conflict(section1: list, section2: list):
    # check if two sections use the same period
    # section[12]: list of strings representing periods
    return any([(period in section1) for period in section2])


def section_choices(courses: dict):
    # generate all possible section choices
    # return a list of tuples (course_name, sec_name)
    choices = []
    for course_name, course in courses.items():
        if not choices:
            # first course
            choices = [[(course_name, sec_name)] for sec_name in course["sections"]]
        else:
            branches = []
            for choice in choices:
                branches.extend(
                    [
                        choice + [(course_name, sec_name)]
                        for sec_name in course["sections"]
                    ]
                )
            choices = branches
    return choices


def resolve(courses: dict):
    for choice in section_choices(courses):
        confl = False
        for course1, course2 in combinations(choice, 2):
            if conflict(
                courses[course1[0]]["sections"][course1[1]],
                courses[course2[0]]["sections"][course2[1]],
            ):
                confl = True
                break
        if not confl:
            print_timetable(courses, choice)
            print()


if __name__ == "__main__":
    courses = {
        "216": {
            "sections": {
                "0": ["Tu 10", "Th 10", "F 10"],
            }
        },
        "401": {
            "sections": {
                "0": ["M 16", "W 16", "F 16"],
            }
        },
        "110": {
            "sections": {
                "1": ["Tu 08", "Th 08", "F 08"],
                "2": ["Tu 10", "Th 10", "F 10"],
                "3": ["Tu 12", "Th 12", "F 12"],
                "4": ["Tu 14", "Th 14", "F 14"],
            }
        },
        "1203": {
            "sections": {
                "1": ["Tu 12", "Tu 14", "F 12", "F 14"],
                "2": ["Tu 18", "F 18"],
                "3": ["W 08", "W 10", "Th 08", "Th 10"],
            }
        },
        "1204": {
            "sections": {
                "1": ["M 18", "W 18"],
                "2": ["Tu 18", "Th 18"],
                "3": ["Tu 12", "Tu 14", "Th 12", "Th 14"],
            }
        },
    }

    resolve(courses)