You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Replace with periods, colons, commas, or parentheses for cleaner,
more natural prose throughout all exercise documentation.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Copy file name to clipboardExpand all lines: CashRegister/README.md
+10-10Lines changed: 10 additions & 10 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -45,10 +45,10 @@ Without `--verbose`, output matches the spec format exactly (`3 quarters,1 dime,
45
45
46
46
### Flags
47
47
48
-
-`--divisor N`— Change which transactions get randomized denominations (default: 3). If `owed` in cents is divisible by N, the change is randomized. Use `--divisor 0` to disable randomization entirely.
49
-
-`--seed N`— Seed the random number generator for reproducible output. Useful for testing.
50
-
-`--currency USD|EUR`— Select the currency denomination set (default: USD).
51
-
-`--verbose`— Show transaction context alongside the change output. Labels random lines.
48
+
-`--divisor N`changes which transactions get randomized denominations (default: 3). If `owed` in cents is divisible by N, the change is randomized. Use `--divisor 0` to disable randomization entirely.
49
+
-`--seed N`seeds the random number generator for reproducible output. Useful for testing.
50
+
-`--currency USD|EUR`selects the currency denomination set (default: USD).
51
+
-`--verbose`shows transaction context alongside the change output. Labels random lines.
52
52
53
53
## The Problem
54
54
@@ -58,7 +58,7 @@ Without `--verbose`, output matches the spec format exactly (`3 quarters,1 dime,
58
58
59
59
### Integer cents everywhere
60
60
61
-
All money is represented as `u32` cents. The string `"2.13"` is parsed via string manipulation into `213u32` — no floating-point arithmetic is ever used. This eliminates an entire class of rounding bugs (e.g., `0.1 + 0.2 != 0.3` in IEEE 754).
61
+
All money is represented as `u32` cents. The string `"2.13"` is parsed via string manipulation into `213u32`, with no floating-point arithmetic anywhere. This eliminates an entire class of rounding bugs (e.g., `0.1 + 0.2 != 0.3` in IEEE 754).
62
62
63
63
### Strategy trait with concrete types
64
64
@@ -70,11 +70,11 @@ A `ChangeStrategy` trait defines the contract. `GreedyStrategy` minimizes denomi
70
70
71
71
### Injectable randomness
72
72
73
-
`RandomStrategy<R: Rng>` is generic over its RNG source. Tests inject `StdRng::seed_from_u64()` for deterministic assertions. Production uses `StdRng::from_entropy()`. Zero-cost abstraction via monomorphization — no `Box<dyn Rng>`.
73
+
`RandomStrategy<R: Rng>` is generic over its RNG source. Tests inject `StdRng::seed_from_u64()` for deterministic assertions. Production uses `StdRng::from_entropy()`. Zero-cost abstraction via monomorphization, no `Box<dyn Rng>`.
74
74
75
75
### No heavy dependencies
76
76
77
-
CLI argument parsing is a 5-line generic function, not a 50KB dependency. The only runtime dependencies are `thiserror` (structured errors) and `rand` (randomization) — both are well-established, minimal crates.
77
+
CLI argument parsing is a 5-line generic function, not a 50KB dependency. The only runtime dependencies are `thiserror` (structured errors) and `rand` (randomization), both well-established, minimal crates.
parse.rs String → cents conversion, line → Transaction
92
92
strategy/
93
93
mod.rs ChangeStrategy trait, Breakdown type alias
@@ -104,15 +104,15 @@ tests/
104
104
105
105
> What might happen if the client needs to change the random divisor?
106
106
107
-
Pass `--divisor N` at the command line. The divisor flows through `rules::make_change_for` as a parameter — no code changes needed. Setting `--divisor 0` disables randomization entirely.
107
+
Pass `--divisor N` at the command line. The divisor flows through `rules::make_change_for` as a parameter, so no code changes are needed. Setting `--divisor 0` disables randomization entirely.
108
108
109
109
> What might happen if the client needs to add another special case (like the random twist)?
110
110
111
111
Add a new strategy struct implementing `ChangeStrategy` (one file), then add a branch in `rules.rs`. Existing strategies and tests are untouched. For example, a "round up to nearest quarter" strategy would be ~20 lines of code and one new match arm.
112
112
113
113
> What might happen if sales closes a new client in France?
114
114
115
-
Pass `--currency EUR`. The EUR denomination table is already defined and wired into the CLI. Try it: `cargo run -- sample_eur.txt --currency EUR`. The denomination table drives all formatting — singular/plural names, values, everything. One caveat: France uses commas as decimal separators (`2,13` not `2.13`), which conflicts with the comma-delimited input format. A real deployment would need a configurable delimiter or a different input format (e.g., TSV, JSON).
115
+
Pass `--currency EUR`. The EUR denomination table is already defined and wired into the CLI. Try it: `cargo run -- sample_eur.txt --currency EUR`. The denomination table drives all formatting (singular/plural names, values, everything). One caveat: France uses commas as decimal separators (`2,13` not `2.13`), which conflicts with the comma-delimited input format. A real deployment would need a configurable delimiter or a different input format (e.g., TSV, JSON).
Copy file name to clipboardExpand all lines: GildedRose/README.md
+7-7Lines changed: 7 additions & 7 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -4,7 +4,7 @@ A Go solution for the Gilded Rose inventory management system.
4
4
5
5
## Approach
6
6
7
-
Each item category's degradation rules are encapsulated in a separate **Updater implementation** behind a common interface. A **Registry** maps category names (and item names for special cases like Aged Brie) to their updater. Adding a new special-case item type means adding one file and one registry entry — no existing code changes.
7
+
Each item category's degradation rules are encapsulated in a separate **Updater implementation** behind a common interface. A **Registry** maps category names (and item names for special cases like Aged Brie) to their updater. Adding a new special-case item type means adding one file and one registry entry, with no changes to existing code.
8
8
9
9
## Structure
10
10
@@ -34,11 +34,11 @@ make run
34
34
```
35
35
36
36
Interactive commands:
37
-
-`list`— show all inventory
38
-
-`item <name>`— show details for a single item
39
-
-`next`— advance to the next day
40
-
-`trash`— list items with Quality = 0
41
-
-`quit`— exit
37
+
-`list` show all inventory
38
+
-`item <name>` show details for a single item
39
+
-`next` advance to the next day
40
+
-`trash` list items with Quality = 0
41
+
-`quit` exit
42
42
43
43
## Test
44
44
@@ -59,5 +59,5 @@ make test
59
59
60
60
-**Interface-based extensibility**: New item types implement the `Updater` interface (one method: `Update(*Item)`). The registry wires them in. Existing updaters and tests are untouched.
61
61
-**Two-tier dispatch**: The registry checks item name first, then category, then falls back to Normal. This handles both category-wide rules (Conjured, Backstage Passes) and one-off items (Aged Brie) without special-casing in the logic.
62
-
-**Invariant tests**: The test suite runs the full inventory through 100 simulated days and asserts that quality constraints are never violated — a safety net against future regressions.
62
+
-**Invariant tests**: The test suite runs the full inventory through 100 simulated days and asserts that quality constraints are never violated, serving as a safety net against future regressions.
63
63
-**Copy semantics**: `Items()` and `FindByName()` return copies, preventing callers from accidentally mutating inventory state.
Copy file name to clipboardExpand all lines: MissingNumber/README.md
+2-2Lines changed: 2 additions & 2 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -4,7 +4,7 @@ A Zig solution for finding the missing number in sequential series.
4
4
5
5
## Approach
6
6
7
-
Uses the **arithmetic sum formula** — the expected sum of a contiguous range `[min, max]` is `(max + min) * (max - min + 1) / 2`. Subtracting the actual sum of the provided numbers gives the missing value in O(n) time with O(1) extra space.
7
+
Uses the **arithmetic sum formula**: the expected sum of a contiguous range `[min, max]` is `(max + min) * (max - min + 1) / 2`. Subtracting the actual sum of the provided numbers gives the missing value in O(n) time with O(1) extra space.
8
8
9
9
The solution is structured as a library (`root.zig`) with a thin CLI driver (`main.zig`), making the core logic reusable and independently testable.
10
10
@@ -27,4 +27,4 @@ make test
27
27
28
28
-**Library separation**: Core logic is decoupled from I/O, enabling integration into larger systems or alternative frontends.
29
29
-**Allocator-driven**: All allocations go through Zig's allocator interface, giving callers full control over memory strategy.
30
-
-**Extensibility**: `parseLine` and `findMissing` are independent — the parser could be swapped for streaming input, and the algorithm could be extended to handle multiple missing values.
30
+
-**Extensibility**: `parseLine` and `findMissing` are independent. The parser could be swapped for streaming input, and the algorithm could be extended to handle multiple missing values.
Copy file name to clipboardExpand all lines: MorseCode/README.md
+3-3Lines changed: 3 additions & 3 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -4,7 +4,7 @@ A Perl solution for translating between Morse code and English.
4
4
5
5
## Approach
6
6
7
-
Splits input on the delimiter hierarchy — `||||` for word boundaries, `||` for letter boundaries — then maps each Morse sequence through a lookup table. The encoder reverses the process. Clean string splitting, no regex needed for the core logic.
7
+
Splits input on the delimiter hierarchy (`||||` for word boundaries, `||` for letter boundaries), then maps each Morse sequence through a lookup table. The encoder reverses the process. Clean string splitting, no regex needed for the core logic.
8
8
9
9
## Structure
10
10
@@ -42,6 +42,6 @@ make test
42
42
43
43
## Design Considerations
44
44
45
-
-**Alphabet isolation**: The lookup table is a standalone module — swapping to a different encoding (e.g., NATO phonetic) means replacing one file.
45
+
-**Alphabet isolation**: The lookup table is a standalone module. Swapping to a different encoding (e.g., NATO phonetic) means replacing one file.
46
46
-**Bidirectional symmetry**: Encoder and decoder are full mirrors of each other, both backed by the same alphabet. `decode(encode(text)) == text` is verified for every character.
47
-
-**Extensibility**: The delimiter scheme is handled in the encoder/decoder modules, separate from the alphabet — changing the wire format doesn't touch the character mappings.
47
+
-**Extensibility**: The delimiter scheme is handled in the encoder/decoder modules, separate from the alphabet. Changing the wire format doesn't touch the character mappings.
Copy file name to clipboardExpand all lines: OnScreenKeyboard/README.md
+3-3Lines changed: 3 additions & 3 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -4,7 +4,7 @@ A Python solution for scripting cursor paths on a grid-based on-screen keyboard.
4
4
5
5
## Approach
6
6
7
-
Builds a coordinate index from the keyboard layout, then computes the Manhattan distance path (U/D/L/R) between successive characters. The layout is data, not code — swapping to a different keyboard arrangement means changing a single list.
7
+
Builds a coordinate index from the keyboard layout, then computes the Manhattan distance path (U/D/L/R) between successive characters. The layout is data, not code. Swapping to a different keyboard arrangement means changing a single list.
8
8
9
9
## Structure
10
10
@@ -36,6 +36,6 @@ make test
36
36
37
37
## Design Considerations
38
38
39
-
-**Layout as data**: The keyboard grid is a plain list of strings — no hardcoded positions. Changing from alphanumeric to any other layout is a one-line change. The `build_index` function dynamically maps characters to coordinates from any grid shape.
39
+
-**Layout as data**: The keyboard grid is a plain list of strings, no hardcoded positions. Changing from alphanumeric to any other layout is a one-line change. The `build_index` function dynamically maps characters to coordinates from any grid shape.
40
40
-**Separation of concerns**: `keyboard.py` owns the layout, `navigator.py` owns the movement logic, `main.py` is pure I/O. Each has a single reason to change.
41
-
-**Input flexibility**: The core functions accept strings and dicts — the file-reading is only in `main.py`. Switching from file to stream means changing only the driver, not the logic.
41
+
-**Input flexibility**: The core functions accept strings and dicts. The file-reading is only in `main.py`. Switching from file to stream means changing only the driver, not the logic.
|[CashRegister](./CashRegister)|**Rust**| Financial calculations demand zero-cost abstractions and type safety. Integer-cent arithmetic eliminates floating-point rounding bugs entirely. The trait system maps naturally to the strategy pattern the problem calls for. | 94 |
12
12
|[MissingNumber](./MissingNumber)|**Zig**| A tight algorithmic problem suited to a systems language. Zig's explicit allocator model and comptime features show well on small, performance-sensitive code. Demonstrates range beyond Rust while staying in the systems tier. | 70 |
13
-
|[MorseCode](./MorseCode)|**Perl**| A text-processing problem at its core — splitting on delimiters and mapping through a lookup table. Perl is *the* language for this domain, and using it signals that language choice is driven by fit, not comfort zone. | 232 |
14
-
|[OnScreenKeyboard](./OnScreenKeyboard)|**Python**| If this were production code, it would be scripting device input on a DVR or smart TV — a space where Python dominates. Clean data modeling (layout as a list, index as a dict) makes the solution readable and extensible. | 94 |
15
-
|[GildedRose](./GildedRose)|**Go**| An OOP/business logic problem centered on polymorphism and rule engines. Go's interface system is a natural fit — each item category implements a single `Updater` interface, and the registry pattern makes new rules a one-file addition. Go's simplicity forces clean design without hiding behind language features. | 107 |
16
-
|[RestaurantReviews](./RestaurantReviews)|**TypeScript/React**| TrueFit's core stack — they maintain the `bach` React composition library and a React-heavy open source portfolio. The most substantial exercise doubles as a unified control panel integrating all 5 other exercises as live panels. | 371 |
13
+
|[MorseCode](./MorseCode)|**Perl**| A text-processing problem at its core: splitting on delimiters and mapping through a lookup table. Perl is *the* language for this domain, and using it signals that language choice is driven by fit, not comfort zone. | 232 |
14
+
|[OnScreenKeyboard](./OnScreenKeyboard)|**Python**| If this were production code, it would be scripting device input on a DVR or smart TV, a space where Python dominates. Clean data modeling (layout as a list, index as a dict) makes the solution readable and extensible. | 94 |
15
+
|[GildedRose](./GildedRose)|**Go**| An OOP/business logic problem centered on polymorphism and rule engines. Go's interface system is a natural fit: each item category implements a single `Updater` interface, and the registry pattern makes new rules a one-file addition. Go's simplicity forces clean design without hiding behind language features. | 107 |
16
+
|[RestaurantReviews](./RestaurantReviews)|**TypeScript/React**| TrueFit's core stack. They maintain the `bach` React composition library and a React-heavy open source portfolio. The most substantial exercise doubles as a unified control panel integrating all 5 other exercises as live panels. | 371 |
17
17
18
18
## Prerequisites
19
19
@@ -62,10 +62,10 @@ make test-all
62
62
63
63
## DavesSnackShack
64
64
65
-
DavesSnackShack is a QA/testing exercise. Rather than treat it as a standalone item, the QA mindset is embedded throughout every exercise above — exhaustive test suites, boundary conditions, error paths, and property-based testing where applicable. The RestaurantReviews dashboard also includes a dedicated security test suite covering injection, XSS, and input validation.
65
+
DavesSnackShack is a QA/testing exercise. Rather than treat it as a standalone item, the QA mindset is embedded throughout every exercise above: exhaustive test suites, boundary conditions, error paths, and property-based testing where applicable. The RestaurantReviews dashboard also includes a dedicated security test suite covering injection, XSS, and input validation.
66
66
67
67
## Philosophy
68
68
69
-
-**Single Responsibility Principle** enforced throughout — parsing, logic, orchestration, and I/O are always in separate modules.
70
-
-**Exhaustive testing**— edge cases, error paths, boundary conditions, and round-trip verification. The goal is that a reviewer has nothing left to question.
71
-
-**Language as a design decision**— each choice is deliberate, not default. The portfolio demonstrates breadth and the ability to pick the right tool for the job.
69
+
-**Single Responsibility Principle** enforced throughout. Parsing, logic, orchestration, and I/O are always in separate modules.
70
+
-**Exhaustive testing.**Edge cases, error paths, boundary conditions, and round-trip verification. The goal is that a reviewer has nothing left to question.
71
+
-**Language as a design decision.**Each choice is deliberate, not default. The portfolio demonstrates breadth and the ability to pick the right tool for the job.
0 commit comments