prereqEval.js Core logic
Evaluates whether a course's prerequisites are satisfied given the current placement state. Returns not just pass/fail but why it fails: missing entirely, or placed in the wrong order.
Parent
Called by
PlannerContext.jsx (for every placed course, on every state change)
Result feeds
prereqViolations Map → CourseCard warning icons, RelationLines SVG
evalPrereqTree algorithm
flowchart TD
A["evalPrereqTree(prereqs, placements, SEM_INDEX, semIdx)"] --> B{prereqs node type?}
B -->|"and"| C["eval each child"]
C --> D{worst result among children?}
D -->|all satisfied| R1["return 'satisfied'"]
D -->|any 'order'| R2["return 'order'"]
D -->|any 'unsatisfied'| R3["return 'unsatisfied'"]
B -->|"or"| E["eval each child"]
E --> F{best result among children?}
F -->|any satisfied| R4["return 'satisfied'"]
F -->|any 'order'| R5["return 'order'"]
F -->|all 'unsatisfied'| R6["return 'unsatisfied'"]
B -->|"leaf course ref"| G{"course in placements?"}
G -->|no| R7["return 'unsatisfied'"]
G -->|yes| H{"SEM_INDEX[course.semId]\n< semIdx?"}
H -->|yes, placed before| R8["return 'satisfied'"]
H -->|no, same or after| R9["return 'order'"]
Worst-case propagates up AND; best-case propagates up OR. "order" means placed but too late.
Exported function
evalPrereqTree(prereqs, placements, SEM_INDEX, semesterIdx) → "satisfied" | "order" | "unsatisfied"
Walks the prerequisite tree recursively. For each leaf course reference (
OR nodes return the best child result (satisfied > order > unsatisfied).
{ subject, classId }), checks if it's placed and whether it's in a prior semester.
- "satisfied": prereq is placed in an earlier semester ✓
- "order": prereq is placed but in the same or a later semester (ordering violation)
- "unsatisfied": prereq is not placed at all
OR nodes return the best child result (satisfied > order > unsatisfied).
Returns: "satisfied" | "order" | "unsatisfied"
How PlannerContext uses this
// PlannerContext.jsx — violation computation (simplified)
const violations = new Map();
for (const [courseId, semId] of Object.entries(placements)) {
const course = courseMap[courseId];
if (!course?.prereqs) continue;
const semIdx = SEM_INDEX[semId] ?? 0;
const result = evalPrereqTree(course.prereqs, placements, SEM_INDEX, semIdx);
if (result !== 'satisfied') violations.set(courseId, { type: result });
}
This runs after every placement change. The resulting prereqViolations Map is read by CourseCard (warning icons) and RelationLines (draws red lines for violated edges).
Corequisite violations (not in this module)
Corequisite checking is handled inline in PlannerContext — a coreq violation occurs when the required course is not placed in the same semester as the course that requires it. The check is simpler: just look up if placements[coreqId] === placements[courseId].