Penumbra Tech
← All projects
[Case study: Computer science depth]

Theory of computation review tool.

A self-contained offline study app I built to prepare for a graduate-level theory of computation course using Sipser's textbook. 859 original questions across Chapters 0–8 and three exam checkpoints, a custom spaced-repetition scheduler, full concept explainers, state-diagram practice for DFAs and NFAs, and KaTeX-rendered math — all in static HTML you double-click to launch. No install, no server, no telemetry.

Vanilla JSKaTeXSpaced repetitionSipser 3rd ed.Offline-firstNo dependencies

The live version at /toc/ is the same tool, just given a Penumbra-Tech makeover for this site (corona palette, brand strip up top). The GitHub repo is the canonical offline build — clone it, double-click index.html, and study on a plane.

[Why this is here]

I take the actual science of computer science seriously.

There's a real difference between someone who learned to wire React components together over a weekend and someone who knows what is computable, what is efficient, and what the polynomial-time hierarchy says about the limits of both. Most of the working software industry doesn't need that distinction to matter every day — but when it does, it matters a lot: when you have to reason about an unfamiliar algorithm, bound the worst-case behaviour of a system under load, or know whether the problem in front of you is actually tractable.

I came up through a formal computer-science program, not a twelve-week bootcamp. The questions in this tool cover Turing machines, decidability, the recursion theorem, Cook–Levin, NP-completeness, PSPACE, L vs NL — the material a CS graduate is supposed to be able to think about, not just have heard of.

I'm not putting it on the portfolio to brag about book learning. I'm putting it here so the kind of client who needs an engineer who can reason about correctness, complexity, and system design — not just stitch libraries — has a concrete sample of what that looks like in my hands.

[Coverage]

What the question bank actually contains.

All chapters are graded by the same hybrid algorithm (Leitner boxes + streak mastery + Bloom-style mastery-gated unlock). Exam checkpoints mirror the actual course: Exam 1 covers Ch 0–2, Exam 2 covers 3–5, Final covers 6–8.

ChTopicQuestions
0Mathematical preliminaries25
1Regular languages (DFAs/NFAs, ripping, pumping)89
2Context-free languages40
3Turing machines (Church–Turing thesis)32
4Decidability36
5Reducibility33
6Advanced computability (recursion theorem)23
7Time complexity (P, NP, NP-completeness)44
8Space complexity (PSPACE, L, NL)30
×1Exam 1 checkpoint (Ch 0–2)14
×2Exam 2 checkpoint (Ch 3–5)16
ΩFinal checkpoint (Ch 6–8)32
ΣTotal auto-graded questions414

Question types: true/false, multiple choice, select-all, fill-in-the-blank, and put-in-order. Distractors are pulled from a larger wrong-answer pool than the displayed options and reshuffled each repetition, so pattern-gaming doesn't help — you actually have to read every option every time.

[Engineering, not just content]

A hybrid spaced-repetition scheduler.

Three published methods stitched together:

  • Leitner boxes — each question lives in one of five boxes; correct answers promote it to a longer interval, a wrong answer drops it back to box 1 so it returns quickly.
  • Streak mastery — a question is only mastered after three correct answers in a row. One wrong answer resets the streak, so a lucky guess never sticks.
  • Mastery-gated progression — the next chapter unlocks when the current one hits ~90% mastery. Earlier chapters keep mixing in afterward, weighted toward questions you've missed.

The scheduler weights selection toward low-box, never-seen, and previously-missed questions, while interleaving review from earlier chapters. The snippet to the right is the weighting function that drives all of that — stripped down for display, but the real one has unit tests under tools/sim.js.

scheduler.js
VALIDATED
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// Question weight blends three signals:
// * Leitner box — lower boxes (more wrong) weighted higher
// * Recency — never-seen and recently-missed weighted higher
// * Mastery gap — chapters below 90% mastery weighted higher
function weight(question, now) {
const box = question.leitnerBox; // 1..5
const lastSeen = question.lastSeenAt;
const lastWasWrong = question.lastResult === 'wrong';
const chapterMastery = mastery[question.chapter] ?? 0;
 
const boxWeight = (6 - box) ** 1.4;
const recencyWeight = lastSeen
? Math.min(8, (now - lastSeen) / dueIntervalFor(box))
: 6;
const missWeight = lastWasWrong ? 3 : 1;
const gapWeight = chapterMastery < 0.9 ? 1 + (0.9 - chapterMastery) * 4 : 1;
 
return boxWeight * recencyWeight * missWeight * gapWeight;
}
[Hands-on practice, not just trivia]

The questions make you do the procedure.

Chapter 1 alone has 89 questions and many of them render actual state diagrams — DFAs and NFAs — and ask you to trace inputs, run the NFA→DFA subset construction one step at a time, apply GNFA “ripping” to eliminate states, or plug numbers into the pumping lemma. Multiple-choice trivia about the definitions doesn't cover it; you have to do the work.

For Chapter 7 (time complexity) and Chapter 8 (space complexity), the questions push on the reductions and inclusions: building a polynomial-time reduction to show SAT ≤p 3SAT, knowing what Savitch's theorem buys you, distinguishing P from NP from coNP from PSPACE in the diagrams.

Every answered question has an “Explain in more depth” button (it pulses after a wrong answer) that opens a full concept explainer for that topic: the definition, the intuition, the key theorem, and the common trap. There are 96 such explainers, one per covered concept.

[Two ways to use it]

Same tool, two builds.

The tool itself is one codebase — vanilla JS, KaTeX, a single index.html you can double-click. There are two builds because the right deployment depends on what you want to do with it.

[Live build · this site]

Try it in the browser.

Same tool with a Penumbra-Tech makeover — corona palette, brand strip up top, dark mode by default. Progress saves locally to this domain. Good for a quick demo, not for studying on a flight.

[Offline build · GitHub]

Clone it and study on a plane.

The canonical offline build — no Penumbra theming, light/dark toggle, fully self-contained. Clone the repo, double-click index.html, your progress lives in your own browser. Built for actual exam prep.

[Hire on substance]

If the depth matters for your project, let's talk.

Plenty of work doesn't need a theory background and that's fine. But if your problem touches algorithm design, performance bounds, correctness reasoning, or anything where “just use a library” isn't the right answer, this is the kind of toolkit you want on the other side of the table.