Iteration Labs (10)

← Module home · Every lab: IPO on paper → pseudocode → dry-run table → code → test every row. LAR style: no functions, no arrays, iostream-only (plus <iomanip> where shown). Lab-0 conventions apply to all ten.

Lab 1 — The drilling instructor

Scenario. A PT instructor drills cadets: each cadet does a fixed number of push-up sets. The instructor wants per-cadet totals and a class summary. This lab drills the counting loop + accumulator until it’s automatic.

Requirements. Read cadets (1–20), then for each cadet read sets (1–10) and that many marks. Print each cadet’s total; after all cadets print: class total, class average (2 dp), best cadet number + score.

Sample run (values in bold are typed input):

Cadets? 2
Cadet 1 — sets? 2
  Set 1: 20
  Set 2: 30
Cadet 1 total: 50
Cadet 2 — sets? 3
  Set 1: 10
  Set 2: 25
  Set 3: 5
Cadet 2 total: 40
Class total: 90   average: 45.00   best: cadet 1 (50)

Test table (dry-run all rows):

cadets per-cadet marks class total average best
2 20 30 / 10 25 5 90 45.00 1 (50)
1 40 40 40.00 1 (40)
3 5 5 / 5 5 5 / 5 5 5 45 15.00 any (15)
2 0 0 / 0 0 0 0.00 1 (0)

Dry-run skeleton (fill before coding):

cadet i sets j (set) mark cadetTotal classTotal best
1 1 2 1 20 20 20 —
      2 30 50 50 1 (50)
2 2 3 1 10 10 60 1 (50)
      2 25 35 85 1 (50)
      3 5 40 90 1 (50)

Student tasks. 1. Trace the sample run in the skeleton above. 2. Write the nested loop with both counters named for their jobs. 3. Best-cadet champion — why can’t best = 0 seed it? 4. Guard cadets = 0 (should print a message, divide nothing).

Extensions. ⭐ Print a - bar of length cadetTotal / 10 under each cadet’s total (a loop-printed chart). ⭐⭐ Reject any per-set mark that is negative — re-prompt without losing the cadet’s place. ⭐⭐⭐ Print how many cadets tied for the best score (Best: 50 by 2 cadet(s)) — a bestCount beside the champion (m > best resets it to 1, m == best increments it) makes the tie count exact in one pass; printing which cadet numbers tied cannot be done in one pass. Document why.

Guidance. The nesting is two-level and independent: the inner loop’s trip count comes from this cadet’s sets, not from the outer variable — note that this differs from patterns, where the inner bound is the outer variable (Lesson 4 §5). Reset cadetTotal per cadet (D6’s shadow bug is waiting for exactly this). The champion compares cadet totals, so it updates only after each cadet’s inner loop ends — never mid-cadet. Ties: a bestCount beside the champion gives the exact tie count in one pass; the tie list of cadet numbers needs the arrays module.


Lab 2 — Canteen till

Scenario. The canteen’s till takes continuous orders: dish code and quantity per item, 0 0 to close the till. Totals per category, count of items, and the day’s take.

Requirements. Repeat until code 0: read code (1 = drink 60, 2 = snack 120, 3 = meal 250, 0 = close). Read qty (1–50). Accumulate per-category takings and the item count; print a final receipt: per-category totals, item count, grand total.

Sample run:

Item (code qty, 0 0 to close): 1 2
Item (code qty, 0 0 to close): 3 1
Item (code qty, 0 0 to close): 2 4
Item (code qty, 0 0 to close): 0 0
Drinks:   120.00
Snacks:   480.00
Meals:    250.00
Items:    3
TOTAL:    850.00

Test table:

order stream drinks snacks meals items total
1 2 / 3 1 / 2 4 / 0 0 120 480 250 3 850
0 0 (immediate close) 0 0 0 0 0
2 1 / 0 0 0 120 0 1 120
1 1 / 2 1 / 3 1 / 1 1 / 0 0 120 120 250 4 490

Dry-run skeleton:

code qty drinkTotal snackTotal mealTotal items action
1 2 120 0 0 1 drink line
3 1 120 0 250 2 meal line
2 4 120 480 250 3 snack line
0 0 — — — — exit → receipt

Student tasks. 1. Sentinel 0 for the pair — decide the exact condition (code == 0 suffices; why?). 2. Route with switch inside the loop. 3. Guard qty out of range (skip the line with a message — how does the accumulator stay clean?). 4. Immediate close (0 items): what must the receipt show, and is division involved anywhere?

Extensions. ⭐ Count items per category too. ⭐⭐ Add code 4 (special 175) with a daily special name read once at open. ⭐⭐⭐ Print the best-selling category by revenue — three-way champion.

Guidance. This is the sentinel + switch composition at real scale. The qty guard decision (“skip vs re-prompt”) changes the loop’s contract — do it as ⭐⭐ only after the base works; document your choice.


Lab 3 — The queue processor

Scenario. A help desk serves customers; each states their issue type and the service takes a fixed time. Simulate the queue and report.

Requirements. Read customers (0–15). For each: read type (A=5 min, B=8, C=12, X=quit-simulation early). Track a running clock (accumulates minutes), print each service’s start and end time (minutes). X ends input immediately (stop reading, don’t process it). Report: customers served, total service time, average (guard!), longest single service.

Sample run:

Customers? 4
Type for customer 1: A
  Start 0, end 5
Type for customer 2: B
  Start 5, end 13
Type for customer 3: X
Simulation stopped early.
Served: 2   total time: 13 min   average: 6.50   longest: 8

Test table:

customers types served total average longest
4 A B X … 2 13 6.50 8
3 A B C 3 25 8.33 12
0 — 0 0 (no avg line) 0
2 X A 0 0 (no avg line) 0

Dry-run skeleton:

i type start end served clock longest
1 A 0 5 1 5 5
2 B 5 13 2 13 8
3 X — — — — (break)

Student tasks. 1. Map X to break vs a flag — implement one, justify in a comment. 2. Clock = accumulator; start = clock before, end = after. 3. Guard average when served = 0. 4. Why is the champion here per-service minutes, and where exactly is it updated?

Extensions. ⭐ Print a mini Gantt line per service: [0----5). ⭐⭐ If the queue would end after 60 minutes, stop scheduling and print Closing — X minutes of queue left unserved (track remaining customers). ⭐⭐⭐ Two desks: alternate customers between desk 1 and 2, each with its own clock (state per desk — C10’s two-lifetime idea).

Guidance. The clock is a derived accumulator: you print both the before and after values — the first lab where the accumulator’s mid-flight value is itself output. Average guard from S17 recurs.


Lab 4 — The honest teller

Scenario. A bank teller validates withdrawal slips one by one. Each slip: account number and amount. Rules: amount must be a positive multiple of 500, at most 25000. Print per-slip verdicts, then a summary.

Requirements. Read slips (1–30). Per slip read account (6-digit, trust it) and amount. Rules, checked in this order: amount must be (a) positive, (b) a multiple of 500, (c) at most 25000. Print OK or the first failed rule with its value. After all slips: count OK, count each rejection reason, total valid amount.

Sample run:

Slips? 3
Account: 100234 Amount: 8500
  OK
Account: 100235 Amount: 8300
  REJECT: not a multiple of 500 (8300)
Account: 100236 Amount: 27000
  REJECT: exceeds limit (27000)
OK: 1  not-multiple: 1  over-limit: 1  total valid: 8500

Test table:

slips amounts OK non-pos not-mult over total valid
3 8500 8300 27000 1 0 1 1 8500
2 500 25000 2 0 0 0 25500
1 0 0 1 0 0 0
2 499 30000 0 0 1 1 0

Dry-run skeleton:

i amount passes multiple? passes limit? verdict counters
1 8500 yes (17×500) yes OK ok 1
2 8300 no (skipped) not-multiple nm 1
3 27000 yes (54×500) no over-limit ol 1

Student tasks. 1. Order the three rules deliberately — why must positive run before multiple (0 % 500 == 0 is true!)? 2. Four counters + one accumulator in one loop. 3. Guard: the total-valid accumulator only grows on OK — trace that 8300 and 30000 contribute nothing. 4. The test table’s third row: which counter does the 0-amount slip hit, and what would happen if the multiple check ran first?

Extensions. ⭐ Print OK (17 notes of 500) — the quotient as information. ⭐⭐ A daily cap: after 50000 total, further slips print CASH LIMIT REACHED without processing. ⭐⭐⭐ Read a priority flag; process all slips and print a second report listing only rejected slips (impossible without arrays — print them immediately in a side list format; feel the limitation).

Guidance. Guard chains from decisions inside a loop — validation logic per iteration. The 0-amount trap (0 % 500 == 0 is true!) forces an explicit amount <= 0 rule; document it in requirements before coding.


Lab 5 — The stubborn menu

Scenario. A gym kiosk’s menu must survive any user: wrong keys re-prompt, and nothing crashes. Compose the menu pattern with validation gallery D.

Requirements. Menu: 1 = BMI (read weight kg, height m; print BMI 2dp + band: <18.5 Under, <25 Normal, <30 Over, else Obese), 2 = 1RM estimate (read weight and reps 1–10; print weight × (1 + reps/30.0), 1dp), 3 = show greeting, 0 = quit. Non-numeric input anywhere must re-prompt (fail/clear/ignore). Menu itself re-shows on any other key with Unknown option.

Test table:

action input sequence expected
BMI 1, 70, 1.75 BMI: 22.86 Normal
BMI band edges 1, 50, 1.6 / 1, 60, 1.6 / 1, 70, 1.6 / 1, 80, 1.6 Under / Normal / Over / Obese
1RM 2, 100, 1 1RM: 103.3
1RM guard 2, 100, 0 → re-prompt reps → 3 1RM: 110.0
bad keys 9, abc, 3 Unknown option twice, greeting once
quit 0 Bye!

Dry-run skeleton (BMI, 70 kg 1.75 m):

step value computed verdict
menu choice 1 — route BMI
weight 70 — valid
height 1.75 70/3.0625 = 22.857… prints 22.86
band 22.86 < 25 Normal

Student tasks. 1. Draw the do-while/switch skeleton first, with // TODO bodies. 2. BMI decimal — why does 70 / (1.75*1.75) already compute in double? 3. Make readInt(prompt) / readDouble(prompt) helpers as commented blocks you copy-paste (no functions yet!) — mark clearly that Stage C turns these into real functions. 4. Test every menu path incl. unknown keys twice.

Extensions. ⭐ Count sessions per option; print usage at quit. ⭐⭐ BMI bands with the boundary owners tested (22.49/22.5/24.99/25/29.99/30 — which band owns 25.0?). ⭐⭐⭐ Add option 4: quit confirmation Sure? (y/n) — n returns to the menu (state: you’re inside a do-while inside a do-while).

Guidance. This is the Stage-B capstone of composition: menu + switch + two validation loops + formatting. The copy-paste helper blocks are honest scaffolding — label them, and revisit after functions to see how much code evaporates.


Lab 6 — The guessing game

Scenario. The computer picks a number; the user guesses; the program coaches. First loop game — deterministic (no randomness): a fixed secret keeps testing honest.

Requirements. Secret is 42 (a named constant). Read guesses until correct: print Too low / Too high / Correct! and the attempt count. Reject out-of-range (1–100) guesses with a message that does NOT count as an attempt. Ask Play again? (y/n) after a win.

Sample run:

Guess (1-100): 25
Too low
Guess (1-100): 75
Too high
Guess (1-100): 50
Too high
Guess (1-100): 42
Correct! Took 4 tries.
Play again? (y/n): n

Test table:

secret guess sequence outcome
42 42 Correct in 1
42 25 75 50 42 Correct in 4
42 0 → re-prompt, 101 → re-prompt, 42 Correct in 1 (invalids not counted)
42 25, then 42 Correct in 2

Dry-run skeleton (secret 42, guesses 25 75 50 42):

attempt guess vs secret feedback attempts
1 25 low Too low 1
2 75 high Too high 2
3 50 high Too high 3
4 42 equal Correct! 4

Student tasks. 1. Which loop and why (must the body run first? — argue it with the §6 procedure). 2. Range guard outside the attempt counter — placement decision. 3. constexpr int SECRET = 42; at the top; no magic numbers. 4. Binary-search probing by hand: 50, 25, 37, 43 … in ≤ 7 guesses for any secret — count yours.

Extensions. ⭐ After a win, report whether the player used binary search discipline (all guesses halved the remaining range — track remaining range yourself). ⭐⭐ Narrowing range display: show the current (lo..hi) window; then the player who probes 25 when lo..hi is 26..74 gets called out. ⭐⭐⭐ Two-player mode: player 1 enters the secret (print 30 blank lines to hide it); then player 2 guesses.

Guidance. The range guard is two nested validation loops (range re-prompt around the game loop) — or one loop with two jobs; do it as one loop with an explicit attempts rule. The play-again wrapper is gallery C around the whole game — the do-while-in-do-while shape.


Lab 7 — The robust reader

Scenario. A data-entry terminal must survive a whole shift of mistyped input: letters in numeric fields, out-of-range values, empty tries. The validation gallery is the entire lab.

Requirements. Build one program that: reads a count n (robustly, 1–100), then n readings (robustly, 10–500). Then prints count, total, average, min, max — all idioms at once. Every field must re-prompt on: non-numeric input (Numbers only, please.), out-of-range (Between 10 and 500, please.). Non-numeric retries must not count as attempts.

Test table:

step user types program does
n abc Numbers only, please.
n 150 Between 1 and 100, please.
n 3 accepted
reading 1 -5 range message
reading 1 hello numbers message
reading 1 200 accepted
… 200, 300 …

Final with 200/300/120: total 620, average 206.67, min 120, max 300.

Dry-run skeleton (for the n-loop only):

attempt input fail()? clear+ignore in range? outcome
1 abc yes happens — re-prompt
2 150 no — no re-prompt
3 3 no — yes accept

Student tasks. 1. Compose gallery D (fail/clear/ignore) and A (range) into one reader — order matters (check fail first: why?). 2. Trace the reader on the test table. 3. Then the main idioms loop — note it now contains no validation; it trusts its inputs. 4. Prove the boundary: n = 100 is accepted, n = 101 is refused.

Extensions. ⭐ Track retry counts per field; print a “shift report” of retries. ⭐⭐ Reading sentinel with 0: readings of 0 mean “meter not read” — skip in stats but count them; the sentinel-vs-data question returns (D8). ⭐⭐⭐ Make the range itself a per-field parameter in your copy-paste helper block (min/max written once) — what would this look like as a function?

Guidance. Validation code is infrastructure: it doubles the program’s size while adding zero features — which is exactly why professionals factor it (Stage C). Experience the duplication honestly here; the ⭐⭐⭐ points at the cure.


Lab 8 — The warehouse scan

Scenario. Barcode scans arrive as integers until scan 0. Some scans are re-reads (the same code twice in a row is a double-beep misread) and must be ignored. Report stock movements.

Requirements. Read scans until 0. A scan equal to the previous scan is a misread: ignore it (count misreads). Valid scans: accumulate count, and count categories (1–99 = small, 100–499 = medium, ≥ 500 = large). Report: valid items, misreads, per-category counts, largest valid code (champion).

Sample run:

Scan: 23
Scan: 23      (misread — ignored)
Scan: 410
Scan: 410     (misread — ignored)
Scan: 705
Scan: 0
Items: 3   misreads: 2
Small: 1   Medium: 1   Large: 1
Largest: 705

Test table:

scan stream items misreads S/M/L largest
23 23 410 410 705 0 3 2 1/1/1 705
0 0 0 0/0/0 (no largest line)
5 5 5 0 1 2 1/0/0 5
10 20 20 20 30 0 3 2 2/1/0 30

Dry-run skeleton:

scan prev == prev? category counters prev after
23 0 no small items 1 23
23 23 yes → ignore — misreads 1 23
410 23 no medium items 2 410
410 410 yes — misreads 2 410
705 410 no large items 3 705
0 — sentinel — — exit

Student tasks. 1. prev must survive between passes — where is it declared, when updated? 2. This is C10’s run-tracking with one simplification (any repeat counts). 3. Champion + category counters + misread counter in one loop — the full idiom set. 4. Empty stream (0 first): what prints instead of Largest:? Guard it.

Extensions. ⭐ Track the longest misread streak (consecutive misreads). ⭐⭐ A scan of a cancelled item (−1) undoes the previous item if the previous was valid (a simple undo: category count −1, items −1 — think through whether prev should also revert). ⭐⭐⭐ Two consecutive identical scans = misread, but three in a row = a real triple-quantity read (count as 3 items of that code) — a genuine state machine.

Guidance. prev is a new kind of variable: state that crosses loop passes — neither counter nor accumulator. C10 generalizes this; the ⭐⭐⭐ shows why run-length logic is the seed of data compression.


Lab 9 — The pattern studio

Scenario. A print shop needs row-rule patterns for banners. Each pattern is a rule → statement translation.

Requirements. Read h (2–9). Print, each pattern clearly labelled: (a) left triangle, row r has r stars; (b) left triangle shrinking: row r has h−r+1 stars; (c) number triangle printing column numbers; (d) same but printing row numbers; (e) rectangle h×(2h) hollow (C12 rule).

Sample (h = 4): (a) * / * * / * * * / * * * *; (b) * * * * / * * * / * * / *; (c) 1 / 1 2 / 1 2 3 / 1 2 3 4; (d) 1 / 2 2 / 3 3 3 / 4 4 4 4; (e) 4×8 border.

Test table:

h (a) rows (b) row 1 (c) last row (d) last row (e) checks
4 4 4 stars 1 2 3 4 4 4 4 4 border only, 8 wide
2 2 2 1 2 2 2 2×4
9 9 9 1..9 9×9 9×18

Dry-run skeleton (pattern (a), h = 4):

r inner cond prints newline after
1 c <= 1 * yes
2 c <= 2 * * yes
3 c <= 3 * * * yes
4 c <= 4 * * * * yes

Student tasks. 1. For each pattern write the row rule in words first; translate only then. 2. (c) vs (d): one printed variable differs — state which and why the output differs. 3. Trace (b)’s inner bound for h = 4, rows 1–2. 4. (e): write the border condition as one four-way OR.

Extensions. ⭐ Add (f): binary triangle 1 / 1 0 / 1 0 1 ... (parity of column). ⭐⭐ Add (g): hollow triangle (border of the triangle — condition r == 1 or r == h or c == r). ⭐⭐⭐ Add (h): the pyramid of C13 with both formulas derived on paper in your write-up.

Guidance. Patterns (a)–(d) are the full S29/S30 family; (e)–(g) add the 2D condition. The studio’s lesson: derive the rule on paper first — patterns are never debugged into existence.


Lab 10 — The number lab

Scenario. A maths-tutor tool: for any n in range, print a mini report of number properties — every Lesson 4 technique in one program.

Requirements. Read n (1–99999, validated). Print: digit count, digit sum, reversed n, palindrome verdict, factorial of the digit count, prime verdict (divisor count), divisor count itself, and the sum of all divisors of n including n. Then a Another n? (y/n) loop (gallery C).

Sample run:

n (1-99999): 4729
Digits: 4   digit sum: 22   reversed: 9274   palindrome: no
Prime: yes  divisors: 2    divisor sum: 4730
Factorial of digit count (4!): 24
Another n? (y/n): y
n (1-99999): 1221
Digits: 4   digit sum: 6   reversed: 1221   palindrome: yes
Prime: no   divisors: 8    divisor sum: 1824
Factorial of digit count (4!): 24
Another n? (y/n): n
Done.

Worked check for 1221 = 3 × 11 × 37: divisors 1, 3, 11, 33, 37, 111, 407, 1221 → 8 divisors, sum 1824. (4729 is prime: no divisor found up to 68 = ⌊√4729⌋.)

Test table:

n digits sum reversed palindrome prime divisors divisor sum fact line
4729 4 22 9274 no yes 2 4730 24
1221 4 6 1221 yes no 8 1824 24
12 2 3 21 no no 6 28 2
1 1 1 1 yes no (n>1 guard) 1 1 1
0 (rejected) — — — — — — — —

Dry-run skeleton (digit loop for 4729):

pass n last sum count n/10
1 4729 9 9 1 472
2 472 2 11 2 47
3 47 7 18 3 4
4 4 4 22 4 0

Student tasks. 1. Which techniques consume n — and which need the original? Plan the copies. 2. The divisor loop runs to n (accept the slowness; note the √n upgrade path from Lesson 4 §4). 3. The factorial block: which loop never runs for n = 1 (digit count 1 → 1! = 1), and why is the accumulator already correct? 4. y/n wrapper: which gallery pattern, and what happens on Y?

Extensions. ⭐ Add “largest digit” and “smallest digit” champions inside the digit loop. ⭐⭐ Perfect-number check (C1’s property test). ⭐⭐⭐ Print all divisors and whether n is “abundant” (divisor sum excluding n exceeds n) — needs the divisor loop to also accumulate.

Guidance. The composition discipline: each property is a small self-contained block with its own loop and its own variable names — never share loop variables across blocks. The divisor-sum block is the accumulator idiom on a nested property; the factorial block is the multiplying accumulator with a guard. This lab is the mini-project in miniature.


After the labs

Completed all ten? You’ve used every idea in Stage B’s toolkit at integration scale. The mini-project now asks you to design with them — and the functions module makes the reader helpers, validators, and idiom blocks disappear into functions.