Skip to content

Commit 437c635

Browse files
georgeglarsonclaude
andcommitted
Remove emdashes from all READMEs
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>
1 parent da94979 commit 437c635

6 files changed

Lines changed: 33 additions & 33 deletions

File tree

CashRegister/README.md

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -45,10 +45,10 @@ Without `--verbose`, output matches the spec format exactly (`3 quarters,1 dime,
4545

4646
### Flags
4747

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.
5252

5353
## The Problem
5454

@@ -58,7 +58,7 @@ Without `--verbose`, output matches the spec format exactly (`3 quarters,1 dime,
5858

5959
### Integer cents everywhere
6060

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).
6262

6363
### Strategy trait with concrete types
6464

@@ -70,11 +70,11 @@ A `ChangeStrategy` trait defines the contract. `GreedyStrategy` minimizes denomi
7070

7171
### Injectable randomness
7272

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>`.
7474

7575
### No heavy dependencies
7676

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.
7878

7979
### Property-based testing
8080

@@ -87,7 +87,7 @@ src/
8787
main.rs CLI wiring: arg parsing, file I/O, exit codes
8888
lib.rs Module re-exports
8989
error.rs Error types with line numbers (thiserror)
90-
currency.rs Denomination definitions USD, EUR configs
90+
currency.rs Denomination definitions (USD, EUR configs)
9191
parse.rs String → cents conversion, line → Transaction
9292
strategy/
9393
mod.rs ChangeStrategy trait, Breakdown type alias
@@ -104,15 +104,15 @@ tests/
104104

105105
> What might happen if the client needs to change the random divisor?
106106
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.
108108

109109
> What might happen if the client needs to add another special case (like the random twist)?
110110
111111
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.
112112

113113
> What might happen if sales closes a new client in France?
114114
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).
116116

117117
## Testing
118118

GildedRose/README.md

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ A Go solution for the Gilded Rose inventory management system.
44

55
## Approach
66

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.
88

99
## Structure
1010

@@ -34,11 +34,11 @@ make run
3434
```
3535

3636
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
4242

4343
## Test
4444

@@ -59,5 +59,5 @@ make test
5959

6060
- **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.
6161
- **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.
6363
- **Copy semantics**: `Items()` and `FindByName()` return copies, preventing callers from accidentally mutating inventory state.

MissingNumber/README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ A Zig solution for finding the missing number in sequential series.
44

55
## Approach
66

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.
88

99
The solution is structured as a library (`root.zig`) with a thin CLI driver (`main.zig`), making the core logic reusable and independently testable.
1010

@@ -27,4 +27,4 @@ make test
2727

2828
- **Library separation**: Core logic is decoupled from I/O, enabling integration into larger systems or alternative frontends.
2929
- **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.

MorseCode/README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ A Perl solution for translating between Morse code and English.
44

55
## Approach
66

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.
88

99
## Structure
1010

@@ -42,6 +42,6 @@ make test
4242

4343
## Design Considerations
4444

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.
4646
- **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.

OnScreenKeyboard/README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ A Python solution for scripting cursor paths on a grid-based on-screen keyboard.
44

55
## Approach
66

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.
88

99
## Structure
1010

@@ -36,6 +36,6 @@ make test
3636

3737
## Design Considerations
3838

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.
4040
- **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.

README.md

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,10 @@
1010
|----------|----------|-------------------|-------|
1111
| [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 |
1212
| [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 |
1717

1818
## Prerequisites
1919

@@ -62,10 +62,10 @@ make test-all
6262

6363
## DavesSnackShack
6464

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.
6666

6767
## Philosophy
6868

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

Comments
 (0)