DocumentationPractising
Guides
Practising
The daily loop in detail: how to start and test a problem, when to use hints, how a grade is computed, and how cstudy decides what you practise next.
On this page
The loop
Every problem goes through the same commands, whatever the language:
cstudy next -> cstudy start <slug> --lang kotlin -> edit in your editor -> cstudy test --watch
-> cstudy bench (optional) -> cstudy done --rating ok -> cstudy solution (optional)Commands that take a problem accept its slug (two-sum), its id, or the path of one of your solution files. Without one, they act on the active attempt: your most recent attempt still in progress.
Choosing a language
Pass --lang python, typescript, java, kotlin, go or rust to cstudy start, or set default_lang in your configuration. Reviews are scheduled per problem, so you can solve a problem in one language and review it in another.
A file path names both the problem and the language, which is how editors run cstudy on the open file: cstudy test python/practice/two_sum.py is cstudy test two-sum --lang python.
| Language | Your solution file |
|---|---|
| Python | python/practice/two_sum.py |
| TypeScript | typescript/practice/two-sum.ts |
| Java | jvm/java/src/main/java/practice/two_sum/Solution.java |
| Kotlin | jvm/kotlin/src/main/kotlin/practice/two_sum/Solution.kt |
| Go | go/practice/two_sum/two_sum.go |
| Rust | rust/practice/two_sum.rs |
Starting and resuming
cstudy start <slug> writes the stub, renders the statement to .statements/<slug>.md, begins an attempt and opens both files in $VISUAL or $EDITOR. Starting a problem you already have in progress in the same language resumes that attempt and keeps your file.
| Flag | Effect |
|---|---|
--lang L | The language; default: default_lang |
--fresh | Move your existing file to .archive/ and write a new stub; reviews always start fresh |
--timer 25m | A time box, such as 25m or 1h; finishing over it caps the grade at hard |
--no-open | Do not launch the editor |
Set open_on_start = false in your configuration if you never want cstudy to launch the editor.
Testing
cstudy test runs your code against the problem’s cases. With --watch it runs again each time you save. Visible cases are always listed; passing hidden cases collapse into a count unless you pass --all; a failing hidden case shows its input, the expected answer and yours.
$ cstudy test --time-limit
two-sum · kotlin · 14 cases (2 visible, 11 hidden, 1 generated) · time limit 5x · timer 12:31 / 25:00
build 1.8s (gradle, warm)
PASS ex1 0.04ms
PASS ex2 0.03ms
FAIL h3 hidden
input nums=[-3, 8, 0, 3] target=0
expected [0, 3] (unordered)
actual [3, 3]
TLE g1 hidden · 412ms > limit 95ms (5x hash-map, calibrated)
PASS 10 hidden cases
12/14 passed · 1 failed · 1 tle · total 2.6s| Status | Meaning |
|---|---|
PASS | The comparator accepted your output |
FAIL | Wrong answer |
ERROR | Your code raised an exception or crashed |
TIMEOUT | The hang guard (10 seconds by default) stopped a run that did not finish |
TLE | Right answer, but over the time limit (only with time limits on) |
INVALID | Your output cannot be read as the declared type |
STALLED | A concurrent stress run was still unfinished at its deadline |
NOT RUN | The case did not run |
Useful flags
| Flag | Effect |
|---|---|
--case ID | Run only these cases; repeatable |
--all | List every case, passing hidden ones included |
--time-limit[=VALUE] | Turn time limits on. The default gives each case 5 times the reference’s time (5x), with a floor of 100 ms; --time-limit=1500ms sets one limit for every case |
--no-time-limit | Turn them off, even when your configuration turns them on |
--perf | After every case passes, run a short benchmark and print its verdict |
--typecheck | TypeScript: also run tsc, since Node’s type stripping does not type-check |
--stress N | Function and design problems: also check your code on N generated inputs against a brute-force oracle; concurrent problems: run each stress case N times |
--debug | Wait for your debugger; see Debugging |
On a full pass the summary ends with all passed. Next: cstudy done --rating easy|ok|hard. Every run except a debug run is recorded, so cstudy knows whether your latest run passed when you finish.
Hints and solutions
cstudy hint reveals the next hint of the problem. Hints are counted per attempt, and using any caps the grade at ok.
$ cstudy hint
two-sum · hint 1 of 2
For each value, which partner would complete the sum?cstudy solution shows, through your pager, the explanation of the optimal approach and its code in your language. Before your attempt has passed, it asks first, because revealing the solution grades the attempt as again:
Reveal the solution? The attempt will be graded as again. [y/N]| Flag | Effect |
|---|---|
--lang L | Show the code in another language |
--approach ID | Show one approach, such as brute-force |
--all | Show every approach, in ladder order |
--explanation-only | Leave out the code |
--broken[=ID] | Concurrent problems: show a deliberately broken reference, as a spot-the-bug exercise |
--yes | Skip the confirmation |
Finishing an attempt
cstudy done closes the attempt and schedules the review. When your latest test run passed every case, rate how it went with --rating easy, ok or hard; when it did not, finish with --gave-up. Add --notes "…" to keep a note on the attempt.
$ cstudy done --rating ok
two-sum · kotlin · passed · 18m 40s · rating ok · hints 0
next review 2026-10-27 (in 3 days) · ease 2.50The rating becomes a grade, and some things cap it. The lowest cap wins:
| Situation | Grade |
|---|---|
| Gave up, or revealed the solution before passing | again (0) |
| Rated easy, ok or hard | easy (3), ok (2), hard (1) |
| Used a hint | at most ok |
| Finished over the --timer time box | at most hard |
| Latest benchmark of the attempt is suboptimal, at medium or high confidence | at most hard (turn this off with penalize_suboptimal = false under [schedule]) |
Solve time is the wall-clock time from cstudy start to cstudy done; there is no pause.
Reviews and spaced repetition
cstudy schedules each problem with a simplified SM-2 algorithm. A good grade pushes the next review further out; a lapse brings the problem back tomorrow. This is how one problem moves through 6 reviews:
| Review | Grade | Next review in | Ease after |
|---|---|---|---|
| 1 | ok | 3 days | 2.50 |
| 2 | ok | 7 days | 2.50 |
| 3 | ok | 18 days | 2.50 |
| 4 | hard | 22 days | 2.35 |
| 5 | again | 1 day | 2.15 |
| 6 | ok | 3 days | 2.15 |
Intervals never exceed 180 days (max_interval_days). A problem counts as mastered once its interval reaches 21 days with a last grade of ok or better, and as due on and after its review date.
What cstudy next picks
cstudy next answers “what should I practise now?” the same way every time for the same progress and date:
- A due review, ranked by how overdue it is relative to its interval, plus how weak its pattern is.
- Otherwise a new problem from the weakest pattern (or, outside the algorithms track, the weakest track). Within it, easy problems come first; medium opens once you pass an easy one, and hard once you pass a medium one.
- Otherwise it prints
nothing due and no new problems in scope.
$ cstudy next
review merge-intervals (medium · intervals) overdue 3d, interval 7d
start cstudy start merge-intervals --lang kotlin$ cstudy next
new koko-eating-bananas (medium · binary-search) weakest pattern: binary-search (0.75)
start cstudy start koko-eating-bananas --lang kotlinWeakness combines your recent fail rate, how much of the group you have mastered, and how long ago you last practised it. An untouched group scores 0.75, so cstudy rotates through new patterns before going deep on one.
| Flag | Effect |
|---|---|
--track T | Tracks to pick from, repeatable; default dsa, or next.tracks in your configuration |
--pattern P | Only problems with this pattern |
--difficulty D | easy, medium or hard |
--lang L | Only problems available in this language, and start in it |
--new / --review | Only new problems, or only reviews |
--start | Start the pick right away |
Checking performance
cstudy bench runs your solution and every reference approach on the same generated inputs at growing sizes, fits how the time grows, and compares you with the optimal reference. It checks your answers at every size too.
$ cstudy bench
two-sum · python · sizes 1e2..1e5 · reps 7 · power AC · load 1.2
TARGET DECLARED n=1e2 n=1e3 n=1e4 n=1e5 SLOPE BAND MEMORY
brute-force O(n^2) 0.21ms 19.8ms 2.04s budget 2.00 ~n^2 constant
hash-map O(n) 0.01ms 0.09ms 0.94ms 10.1ms 1.00 ~n|nlogn linear
you 0.01ms 0.11ms 1.10ms 11.8ms 1.01 ~n|nlogn linear
verdict optimal: matches hash-map, 1.17x at n=1e5 · confidence high (spread 3%, R^2 0.999)
space linear, same as hash-map · confidence high
history best previous 13.0ms at n=1e5 (2026-09-12) · now 9% faster · 1st of 3 runs| Verdict | Meaning |
|---|---|
optimal | Same growth band as the optimal reference, at most 1.5 times its time at the largest size, and not growing apart |
near-optimal | Same band, but the ratio grows with n: likely an extra log factor |
suboptimal | A worse growth band, or over the budget where the optimal reference finished |
unknown | Too few usable sizes, or no optimal reference in this language |
Each verdict comes with a confidence, high, medium or low, and a warning when your machine was busy or on battery. Benchmarks compare you with the references and with your own earlier runs, never with other people.
| Flag | Effect |
|---|---|
--sizes LIST | Comma-separated input sizes, such as 100,1000,10000 |
--reps N | Repetitions per size (default 7) |
--refs-only | Benchmark only the references; needs no attempt |
--no-memory | Skip the memory measurement |
--lang L | The language of the attempt to benchmark |
Note
Concurrent and project problems have no benchmark. See the performance analysis spec for what a slope can and cannot tell.
Timers and mock interviews
Any attempt can have a time box: cstudy start two-sum --timer 25m. cstudy test then shows the time left, and finishing over it caps the grade at hard.
cstudy mock simulates an interview. It picks new medium and hard problems, each from a different group where it can, starts them together with one shared timer, and locks cstudy hint and cstudy solution until the timer ends or every problem is done.
$ cstudy mock
mock interview · 2 problems · 45 min shared timer · python
1 group-anagrams (medium · arrays-hashing) weakest pattern: arrays-hashing (0.75)
stub python/practice/group_anagrams.py
statement .statements/group-anagrams.md
2 lru-cache (medium · linked-list) weakest pattern: linked-list (0.75)
stub python/practice/lru_cache.py
statement .statements/lru-cache.md
locked cstudy hint and cstudy solution, until the timer ends or every problem is done
next cstudy test group-anagrams --watch| Flag | Effect |
|---|---|
--minutes N | The shared timer (default 45) |
--count N | How many problems (default 2) |
--track T | Tracks to pick from, repeatable |
--lang L | The language to start them in |
In a mock attempt of a project problem, cstudy submit reports only how many hidden cases failed per level, as an interview would.
Tracking progress
cstudy stats summarises your progress per group: problems, attempts, passes, mastered problems, the pass rate of the last 10 attempts, median solve time and weakness. Below come your streak, the reviews due and your latest benchmark verdicts.
$ cstudy stats
GROUP PROBLEMS ATTEMPTED PASSED MASTERED PASS RATE SOLVE TIME WEAKNESS
arrays-hashing 17 5 4 1 80% 14m 10s 0.42
two-pointers 10 0 0 0 - - 0.75
system-design 10 1 1 0 100% 45m 00s 0.30
attempts 6 finished · 5 in the last 7 days · streak 3 days
reviews 1 due today · 1 overdue
bench 4 benched · 2 optimal · 1 near-optimal · 1 suboptimal · 0 unknownGroup by --by pattern (the default), track, lang or difficulty; narrow the attempt columns with --since 2026-10-01; or print --json. To browse problems with their status and next review date, use cstudy list, filtered with --status new|attempted|passed|due|mastered:
$ cstudy list
ID SLUG DIFF PATTERN STATUS DUE REFS
0001 two-sum easy arrays-hashing passed 2026-10-27 py ts java kt
0002 lru-cache medium linked-list new - py ts java kt
0014 koko-eating-... medium binary-search due 2026-10-21 py javaWritten for cstudy 0.8.0. The specs in the cstudy repository are the source of truth for every detail.