~fkfd/sections

4354ef0b673087f1ec9f7b0037e9430e09eb5bd4 — Frederick Yin 1 year, 6 months ago ed33fdb
Rename choice -> scheme
2 files changed, 41 insertions(+), 38 deletions(-)

M main.hs
M main.py
M main.hs => main.hs +12 -12
@@ 1,15 1,15 @@
import qualified Data.List as List
import qualified Control.Monad as Monad

printTimetable choice = do
printTimetable scheme = do
    putStrLn ""
    putStrLn $ List.intercalate ", " [course ++ "S" ++ sec | (course, (sec, _)) <- choice]
    putStrLn $ List.intercalate ", " [course ++ "S" ++ sec | (course, (sec, _)) <- scheme]
    putStrLn "M\tTu\tW\tTh\tF"
    putStr table
        where table = unlines samePeriodOfDay
              samePeriodOfDay = map (List.intercalate "\t" . horizontal) allPeriodsOfDay
        where table = unlines periodsOfDay
              periodsOfDay = map (List.intercalate "\t" . horizontal) allPeriodsOfDay
              horizontal pod = map (courseInSlot pod) allDaysOfWeek
              courseInSlot pod dow = foldl (foldFunc pod dow) "" choice
              courseInSlot pod dow = foldl (foldFunc pod dow) "" scheme
              foldFunc pod dow acc x =
                  if (dow ++ " " ++ pod) `elem` (snd $ snd x) then fst x else acc
                  where periodString = dow ++ " " ++ pod


@@ 22,16 22,16 @@ printTimetable choice = do
conflict :: (Eq a) => ([a], [a]) -> Bool
conflict courses = not $ null $ List.intersect (fst courses) (snd courses)

-- all possible choices; cartesian product of all courses and all sections thereof
sectionChoices :: [(a, [(b, [c])])] -> [[(a, (b, [c]))]]
sectionChoices [crs] = [[(fst crs, secs)] | secs <- snd crs]
sectionChoices (crs : courses) =
-- all possible schemes; cartesian product of all courses and all sections thereof
sectionSchemes :: [(a, [(b, [c])])] -> [[(a, (b, [c]))]]
sectionSchemes [crs] = [[(fst crs, secs)] | secs <- snd crs]
sectionSchemes (crs : courses) =
    [(fst crs, secs) : known | secs <- snd crs, known <- known_courses]
    where known_courses = sectionChoices courses
    where known_courses = sectionSchemes courses

-- only keep choices that do not conflict
-- only keep schemes that do not conflict
resolve :: (Ord a, Ord b, Ord c, Eq c) => [(a, [(b, [c])])] -> [[(a, (b, [c]))]]
resolve courses = filter noConflict (sectionChoices courses)
resolve courses = filter noConflict (sectionSchemes courses)
    where noConflict secs = all (== False) $ map conflict $ comb2 secs
          comb2 secs = [(snd $ snd s1, snd $ snd s2) | s1 <- secs, s2 <- secs, s1 < s2]


M main.py => main.py +29 -26
@@ 1,38 1,41 @@
#!/usr/bin/python
from itertools import combinations

# dow, pod for short
DAYS_OF_WEEK = ["M", "Tu", "W", "Th", "F"]
PERIODS = ["08", "10", "12", "14", "16", "18"]
PERIODS_OF_DAY = ["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))
    dow, pod = period.split(" ")
    return (DAYS_OF_WEEK.index(dow), PERIODS_OF_DAY.index(pod))


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:
def print_timetable(courses: dict, scheme: list):
    # this program is designed to allow only one course per period
    # period-major order because one period of day == one row when printed
    timetable = [["" for _ in DAYS_OF_WEEK] for _ in PERIODS_OF_DAY]
    for course, sec in scheme:
        periods = courses[course]["sections"][sec]
        for period in periods:
            dow, prd = parse_period(period)
            timetable[prd][dow] = f"{course}"
            dow, pod = parse_period(period)
            timetable[pod][dow] = course

    print(", ".join([f"{course}S{sec}" for course, sec in choice]))
    # print table header
    print(", ".join([f"{course}S{sec}" for course, sec in scheme]))
    print("\t".join(DAYS_OF_WEEK))
    for periods in timetable:
        print("\t".join(periods))
    # print timetable
    for courses_in_pod in timetable:
        print("\t".join(courses_in_pod))


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


def section_choices(courses: dict):
def section_schemes(courses: dict) -> list:
    if not courses:
        return []



@@ 45,28 48,28 @@ def section_choices(courses: dict):
        return [[(course_name, sec_name)] for sec_name in course["sections"]]
    else:
        # inductive case
        # recurse with all courses but one, then branch out each
        # known choice with sections of said course
        known_choices = section_choices(courses)
        choices = []
        for known in known_choices:
        # recurse with all courses but the one we removed, then branch out
        # each known scheme with all sections of said course
        known_schemes = section_schemes(courses)
        schemes = []
        for known in known_schemes:
            for sec_name in course["sections"]:
                choices.append(known + [(course_name, sec_name)])
        return choices
                schemes.append(known + [(course_name, sec_name)])
        return schemes


def resolve(courses: dict):
    for choice in section_choices(courses.copy()):
    for scheme in section_schemes(courses.copy()):
        if not any(
            [
                conflict(
                    courses[course1[0]]["sections"][course1[1]],
                    courses[course2[0]]["sections"][course2[1]],
                )
                for course1, course2 in combinations(choice, 2)
                for course1, course2 in combinations(scheme, 2)
            ]
        ):
            print_timetable(courses, choice)
            print_timetable(courses, scheme)
            print()