I've built this project three times now. Python terminal in October 2022. Java Swing GUI in September 2023. And now a full web app in Fall 2025.
Each time, I thought I was done. Each time, the problem got harder.
The school restructured. 22 groups now instead of 20. The two-day cycle got way more complex: Day 1 has periods 1, 4, 7, 8. Day 2 has periods 1, 2, 3, 7, 8. Periods 1, 7, and 8 show up on both day types, which creates nasty contention. Only 2-3 groups are even eligible for those shared periods on any given day within a 28-day window. On top of that, no group can have the same period within 28 calendar days, the lesson count has to stay balanced across all groups at every point in the schedule, and ideally all 22 groups get a turn before any group repeats.
The old rotation algorithm couldn't touch this. I needed actual constraint satisfaction.
I built it as a vanilla JavaScript web app. No frameworks, no build tools, just open index.html in a browser.
Compare the input to the Java version. The Swing GUI had five bare text fields on a gray window. The web app has date pickers, help tooltips, a recommendation banner, the ability to save and load holiday presets, import from CSV, load from Google Drive, and even chain schedules together using history from previous weeks. It went from "enter some numbers and hit Start" to actual software that Holly can configure herself without calling me.

python3 schedule.py.
The output is where the real difference shows. The old versions just dumped a flat table of letters and period numbers. The web version color-codes every group so you can visually scan for patterns and problems. It shows stats at the top: total days, end balance spread, max running spread, lessons per group. If there are constraint violations it flags them in red. You can click any group letter to highlight all its occurrences across the schedule. And you can drag and drop groups between cells to make manual swaps if Holly wants to override something.

The core algorithm is a week-level solver that considers all slots in a week simultaneously instead of going day by day. It uses minimum remaining values to pick the most constrained slot first, then backtracks when it hits a dead end. After the initial construction, there's a four-stage repair pipeline that fixes spacing violations, rebalances lesson counts, unblocks groups stuck on certain periods, and evens things out at the end of the schedule.
The solver tries 44 different construction variants and keeps the best result. I kept failing to solve this new CSP myself, so I started experimenting with Claude to see if it could crack it. I ended up forcing it to write out every attempt in ALGORITHM_ATTEMPTS.md so it could learn from its mistakes for once :) 18 different algorithmic approaches are logged in there before we landed on something that consistently produced valid schedules. Some of those attempts are embarrassing. A few are just "this doesn't work" followed by an explanation of why the math was wrong.
I also wrote 162 torture tests. Not because I'm thorough, but because the constraints are so tight that edge cases kept biting me and I got tired of finding bugs manually.
The web app is what Holly uses now. Print, save to Drive, export to CSV. No JAR file, no terminal, no asking me for help. She just opens a link!
Three versions. Python to Java to JavaScript. Terminal to Swing to browser. Simple rotation to constraint satisfaction. Three years of learning how to program, compressed into one project that keeps coming back.
And somehow, every time, the hardest part was the same: understanding what Holly actually needed before writing a single line of code.