Day-One Triage Console
A release just shipped and you're on call. Build/test events stream into the triage console, and the console has to make snap decisions about each one: is this build number even or odd? does this number fall in a special bucket? is this a leap year for the date math? are two measured timings "the same"? which ticket priority does this severity score deserve? should the instrumentation fire on this instruction?
You'll write the console's brain as nine small pure functions — each one is
a single operator-driven decision. The twist: you never write a loop. The
grader hammers each function with many inputs (even numbers, negative numbers,
century years, both sides of an epsilon, off-by-one boundaries), so all you have
to get right is the operators. That's the entire point of Chapter 6:
precedence, %, ?:, relational and logical operators, and the floating-point
comparison pitfall — the small mechanics that decide whether a predicate fires
in the right place. (In CS6340 these are exactly the predicates that decide
whether an instrumentation pass touches the right LLVM instructions.)
Your tasks
- Parity.
isEven(int)returnstruewhen the value divides by 2 evenly.classifyParity(int)returns"even"/"odd"using one?:expression. Test oddness with% 2 != 0, not== 1(negatives break the== 1version). - FizzBuzz category.
fizzbuzzCategory(int)returns"fizzbuzz"/"fizz"/"buzz"/"number"for a single value. Check "divisible by both 3 and 5" first (use&&). No loop, no printing — the grader does the repetition. - Leap year.
isLeapYear(int)as one logical expression (noif): divisible by 4 and (not divisible by 100 or divisible by 400). - Safe float compare.
approxEqual(double,double,double)returns whetherstd::abs(a - b) <= epsilon— never==on calculated doubles. - Non-negative wrap.
wrapIndex(int,int)folds an index into[0, size), staying non-negative even for negative indices (raw%can go negative). - Sampling gate.
shouldSampleInstruction(idx, sampleEvery, budget)fires only whensampleEvery > 0andbudget > 0andidx % sampleEvery == 0. PutsampleEvery > 0first so short-circuit&&never lets you compute% 0. - Priority ladder.
ticketPriority(int)maps a score to"P0"/"P1"/"P2"/"P3"with relational tests (nested?:orif/return). - Exactly-one-of.
exactlyOneSource(bool,bool)returns the logical XOR — for twobools that's just!=. - Integer power.
powInt(int,int)computesbase^exponentviastd::pow(C++ has no**;^is XOR). Convert thedoubleresult back toint.
Success criteria
isEven(-7)/classifyParity(-7)— the negative-odd% 2 == 1trapfizzbuzzCategory(15)and(0)— "both" must beat plain "fizz"isLeapYear(1900)vsisLeapYear(2000)— the century/400 ruleapproxEqual(0.1 + 0.2, 0.3, 1e-9)— the classic==failurewrapIndex(-1, 3) == 2— folding a negative remaindershouldSampleInstruction(8, 0, 10)— short-circuit must dodge% 0ticketPriority(90)/(70)/(40)— the band boundariespowInt(2, 8) == 256— what2 ^ 8would wrongly give you (XOR = 10)
Concepts practiced
- Remainder operator
%and the divisibility idiom(x % n) == 0(6.2, 6.3) - The sign-follows-left-operand rule for
%on negatives, and fixing it (6.3) - Conditional operator
?:as an expression-level if/else, including nesting (6.6) - Relational operators
< <= > >= == !=producingbool(6.7) - Logical operators
&& || !and short-circuit evaluation as a guard (6.8) - Logical XOR via
!=on twobools (6.8) - Floating-point comparison with an epsilon instead of
==(6.7) - Precedence & associativity — parenthesizing for an unambiguous reader (6.1)
- No
**in C++: exponentiation viastd::pow+static_cast(6.3) - Reused from earlier chapters: functions / headers / header guard (Ch 2),
boolandstatic_castandif(Ch 4),std::string_view(Ch 5)
Constraints
- Allowed:
%,?:, relational (< <= > >= == !=), logical (&& || !), arithmetic-assignment (+=),if/return,static_cast,std::abs,std::pow, and the function/string_viewmachinery already in the files. - Forbidden (not taught yet): any loop (
for/while— Chapter 8),switch(Ch 8),<random>, containers, classes. If you reach for a loop, stop — the grader is the loop. - Idioms required by the notes: divisibility as
(x % n) == 0; oddness as!= 0; parenthesize mixed logical/relational/?:expressions;sampleEvery > 0before the%in Task 6; epsilon comparison (never==) for Task 4. - Keep every function pure: read the parameters, return a value — no I/O, no globals, no side effects.
Build & run locally
make # compile-check your starter/triage.cpp (warning-clean)
make test # grade your code -> RED until the TASK blocks are filled in
make solution # run the grader against the reference solution
make clean # remove build artifacts(make run is an alias for make test here — for this lab, "running" your code
is running the grader against it, since the grader supplies main.)
Hints
Task 1 — parity and the negative trap
Even: return (value % 2) == 0;. For the label, the conditional operator is an
expression, so you can return it directly:
return ((value % 2) == 0) ? "even" : "odd";. Don't write the odd test as
% 2 == 1 — in C++ -7 % 2 is -1, so that check is false for negative odds.
Task 2 — order the checks
The "fizzbuzz" case is the most specific, so test it first:
if (((value % 3) == 0) && ((value % 5) == 0)) return "fizzbuzz"; then "fizz",
then "buzz", then fall through to "number". If you check "fizz" before
"fizzbuzz", 15 would wrongly return "fizz".
Task 3 — where the parentheses go
return ((year % 4) == 0) && (((year % 100) != 0) || ((year % 400) == 0));
The inner || group is required: && binds tighter than ||, so without the
parentheses the meaning changes.
Task 4 — magnitude of the difference
return std::abs(a - b) <= epsilon; (std::abs from <cmath>, already included).
Using <= lets epsilon == 0 still report identical values as equal.
Task 5 — fold the negative remainder
int wrapped { index % size };
if (wrapped < 0) wrapped += size; // -1 % 3 is -1; +3 makes it 2
return wrapped;Task 6 — let short-circuit protect you
return (sampleEvery > 0) && (budgetRemaining > 0) && ((instructionIndex % sampleEvery) == 0);Because && stops at the first false, when sampleEvery is 0 the % on the
right is never evaluated — so you never hit x % 0 (undefined behavior).
Task 7 — read the ladder top-down
return (score >= 90) ? "P0"
: (score >= 70) ? "P1"
: (score >= 40) ? "P2"
: "P3";The first >= that holds wins, so order alone resolves the bands.
Task 8 — XOR is just !=
return fromFile != fromStdin; — valid precisely because both operands are
already bool. (Don't use != as XOR on ints/pointers.)
Task 9 — pow returns a double
return static_cast<int>(std::pow(base, exponent) + 0.5); — the + 0.5 rounds
to the nearest int, because std::pow can land just under the true value (e.g.
124.999… for 5^3).
Stretch goals
- Make
powIntexact with an integer loop instead ofstd::pow, and detect overflow against a wider type (needs loops, Chapter 8). - Replace the fixed-epsilon
approxEqualwith a relative+absolute tolerance (std::max(std::abs(a), std::abs(b)) * relEps) — see notes 6.7. - Add a
classifyCoverage(covered, total)that returns"complete"/"partial"/"none"using%-free integer comparisons, then adoublecoverage ratio compared withapproxEqual(ratio, 1.0, 1e-12). - Turn the console into a real CLI that reads events from
std::cinand prints decisions (needscinloops + validation, Chapters 8–9).
// Chapter 6 — Operators · Project: Day-One Triage Console (STARTER)
// ─────────────────────────────────────────────────────────────────────────────
// Fill in the nine TASK blocks below. Each maps 1:1 to a task in the README and
// to a declaration in ../triage.h. The bodies currently return PLACEHOLDERS so
// the file compiles immediately — that's why `make test` is RED right now. Your
// job is to turn it GREEN by implementing the real operator logic.
//
// make build compile your code (should already work)
// make test grade it (RED until you fill these in)
// make solution run the reference if you get stuck
//
// No loops, no I/O, no globals — just operators, `if`, and return values.
#include "../triage.h"
#include <cmath> // std::abs (Task 4), std::pow (Task 9)
// ─── TASK 1: parity with `%` and `?:` ────────────────────────────────────────
// isEven: an int is even when it divides by 2 with no remainder, i.e. its
// remainder when divided by 2 is 0. Use `%` and `==`.
// classifyParity: pick the label with ONE conditional operator:
// condition ? "even" : "odd"
// Watch the trap from the notes: test oddness with `% 2 != 0`, NOT `% 2 == 1`,
// because in C++ a negative odd number has remainder -1, not 1.
//
// >>> YOUR CODE HERE <<<
//
bool isEven(int /*value*/)
{
return false; // placeholder — replace with the real check
}
std::string_view classifyParity(int /*value*/)
{
return "?"; // placeholder — replace with a ?: expression
}
// ─────────────────────────────────────────────────────────────────────────────
// ─── TASK 2: FizzBuzz as a category (no loop!) ───────────────────────────────
// Return one of "fizzbuzz" / "fizz" / "buzz" / "number" for a SINGLE value.
// Check the most specific case first: divisible by 3 AND by 5 (use `&&`).
// You may use `if`/`return`, or a nested `?:`. No printing, no loop — the grader
// supplies the loop by calling this across many numbers.
//
// >>> YOUR CODE HERE <<<
//
std::string_view fizzbuzzCategory(int /*value*/)
{
return "number"; // placeholder
}
// ─────────────────────────────────────────────────────────────────────────────
// ─── TASK 3: leap year with logical operators ────────────────────────────────
// Return, as ONE boolean expression (no `if`):
// (year % 4 == 0) && ( (year % 100 != 0) || (year % 400 == 0) )
// Keep the parentheses — they make the precedence (and the intent) unambiguous.
//
// >>> YOUR CODE HERE <<<
//
bool isLeapYear(int /*year*/)
{
return false; // placeholder
}
// ─────────────────────────────────────────────────────────────────────────────
// ─── TASK 4: safe floating-point comparison ──────────────────────────────────
// Calculated doubles rarely match with `==` (e.g. 0.1 + 0.2 != 0.3). Instead,
// return whether the magnitude of their difference is within epsilon:
// std::abs(a - b) <= epsilon
//
// >>> YOUR CODE HERE <<<
//
bool approxEqual(double /*a*/, double /*b*/, double /*epsilon*/)
{
return false; // placeholder
}
// ─────────────────────────────────────────────────────────────────────────────
// ─── TASK 5: non-negative wrap (ring-buffer index) ───────────────────────────
// Raw `index % size` can be negative in C++ (the result takes the sign of the
// left operand: -1 % 3 is -1). Compute the remainder, and if it came out
// negative, add `size` once to fold it into [0, size). Assume size > 0.
//
// >>> YOUR CODE HERE <<<
//
int wrapIndex(int /*index*/, int /*size*/)
{
return 0; // placeholder
}
// ─────────────────────────────────────────────────────────────────────────────
// ─── TASK 6: instrumentation sampling gate (CS6340 tie-in) ───────────────────
// Fire only when ALL hold: sampleEvery > 0, budgetRemaining > 0,
// and instructionIndex lands on the stride (instructionIndex % sampleEvery == 0).
// ORDER MATTERS: put `sampleEvery > 0` FIRST so short-circuit `&&` skips the `%`
// when sampleEvery is 0 (otherwise you'd compute `x % 0` — undefined behavior).
//
// >>> YOUR CODE HERE <<<
//
bool shouldSampleInstruction(int /*instructionIndex*/, int /*sampleEvery*/, int /*budgetRemaining*/)
{
return false; // placeholder
}
// ─────────────────────────────────────────────────────────────────────────────
// ─── TASK 7: ticket priority from a severity score ───────────────────────────
// Map score -> "P0"/"P1"/"P2"/"P3" using relational operators. A nested `?:`
// reads top-down like a ladder:
// (score >= 90) ? "P0" : (score >= 70) ? "P1" : (score >= 40) ? "P2" : "P3"
// (You may use `if`/`return` instead if you prefer.)
//
// >>> YOUR CODE HERE <<<
//
std::string_view ticketPriority(int /*score*/)
{
return "P3"; // placeholder
}
// ─────────────────────────────────────────────────────────────────────────────
// ─── TASK 8: exactly-one-of (logical XOR via !=) ─────────────────────────────
// "Exactly one is true" for two bools is simply `fromFile != fromStdin`.
// (This trick is ONLY valid because both operands are already bool.)
//
// >>> YOUR CODE HERE <<<
//
bool exactlyOneSource(bool /*fromFile*/, bool /*fromStdin*/)
{
return false; // placeholder
}
// ─────────────────────────────────────────────────────────────────────────────
// ─── TASK 9: integer power via std::pow ──────────────────────────────────────
// C++ has no exponent operator. Compute std::pow(base, exponent) in double, then
// convert back with static_cast<int>. std::pow lands on a value like 124.99999
// for some inputs, so add 0.5 before truncating to round to the nearest int:
// static_cast<int>(std::pow(base, exponent) + 0.5)
// Assume exponent >= 0 and the true result is non-negative and fits in an int.
//
// >>> YOUR CODE HERE <<<
//
int powInt(int /*base*/, int /*exponent*/)
{
return 0; // placeholder
}
// ─────────────────────────────────────────────────────────────────────────────
Try the lab first — the learning is in the attempt.
// Chapter 6 — Operators · Project: Day-One Triage Console (REFERENCE SOLUTION)
// ─────────────────────────────────────────────────────────────────────────────
// One complete, correct, warning-clean implementation. Peek only after you've
// taken a real swing at starter/triage.cpp — the learning is in getting your own
// operators right, then comparing.
#include "../triage.h"
#include <cmath> // std::abs, std::pow
// TASK 1 — parity.
// An int is even iff its remainder when divided by 2 is zero.
bool isEven(int value)
{
return (value % 2) == 0;
}
// classifyParity reuses the same idea via the conditional operator `?:`.
// The condition is parenthesized for readability (notes 6.6 / 6.1).
std::string_view classifyParity(int value)
{
return ((value % 2) == 0) ? "even" : "odd";
}
// TASK 2 — FizzBuzz category for a single value (no loop, no I/O).
// Check the most specific case (BOTH divisors) first; otherwise the plain
// "fizz" branch would shadow it. `&&` combines the two divisibility tests.
std::string_view fizzbuzzCategory(int value)
{
if (((value % 3) == 0) && ((value % 5) == 0))
return "fizzbuzz";
if ((value % 3) == 0)
return "fizz";
if ((value % 5) == 0)
return "buzz";
return "number";
}
// TASK 3 — Gregorian leap year as one logical expression.
// Grouping: divisible by 4 AND (not a century OR a 400-multiple).
// The inner parentheses are required for correctness, not just style: without
// them `&&` would bind tighter than `||` and change the meaning.
bool isLeapYear(int year)
{
return ((year % 4) == 0) && (((year % 100) != 0) || ((year % 400) == 0));
}
// TASK 4 — safe floating-point "equality".
// Calculated doubles carry tiny representation error, so we ask "are they within
// epsilon?" instead of "are they bit-identical?". std::abs gives |a - b|.
bool approxEqual(double a, double b, double epsilon)
{
return std::abs(a - b) <= epsilon;
}
// TASK 5 — non-negative wrap.
// In C++ the sign of `%` follows the LEFT operand, so index % size can be
// negative. Fold a negative remainder back into [0, size) by adding size once.
int wrapIndex(int index, int size)
{
int wrapped { index % size };
if (wrapped < 0)
wrapped += size; // arithmetic-assignment shorthand (notes 6.2)
return wrapped;
}
// TASK 6 — sampling gate (CS6340 instrumentation predicate).
// `sampleEvery > 0` MUST be the first operand: short-circuit `&&` then guarantees
// the `% sampleEvery` on the right is never reached when sampleEvery == 0, so we
// never trigger `x % 0` (undefined behavior). Parentheses make the gate auditable.
bool shouldSampleInstruction(int instructionIndex, int sampleEvery, int budgetRemaining)
{
return (sampleEvery > 0)
&& (budgetRemaining > 0)
&& ((instructionIndex % sampleEvery) == 0);
}
// TASK 7 — priority ladder from a severity score.
// Nested `?:` reads as a top-down ladder; the first satisfied band wins. Because
// each `>=` test is strictly higher than the next, order alone resolves the bands.
std::string_view ticketPriority(int score)
{
return (score >= 90) ? "P0"
: (score >= 70) ? "P1"
: (score >= 40) ? "P2"
: "P3";
}
// TASK 8 — exactly-one-of via logical XOR.
// C++ has no `^^`; for two bool operands, `!=` means "exactly one is true".
// Valid ONLY because both operands are already bool (notes 6.8).
bool exactlyOneSource(bool fromFile, bool fromStdin)
{
return fromFile != fromStdin;
}
// TASK 9 — integer power through std::pow.
// `^` is bitwise XOR, not exponent, and there is no `**` in C++. std::pow works
// in double and can land just below the true integer (e.g. 124.999…), so we add
// 0.5 before truncating with static_cast<int> to round to nearest.
int powInt(int base, int exponent)
{
return static_cast<int>(std::pow(base, exponent) + 0.5);
}
// Chapter 6 — Operators · Project: Day-One Triage Console (GRADER)
// ─────────────────────────────────────────────────────────────────────────────
// A tiny no-framework unit-test harness (same style as the drills/CLAUDE.md
// spec). It includes ../triage.h and calls each function across MANY inputs —
// THIS is the "loop" you don't have to write. Each CHECK that fails prints its
// expression and line number. Any failure -> non-zero exit -> `make test` is RED.
//
// The Makefile links this file against starter/triage.cpp (your code) for
// `make test`, and against solution/triage.cpp for `make test-solution`.
#include <iostream>
#include "../triage.h"
static int fails = 0;
// CHECK: assert a boolean condition; on failure, report what and where.
#define CHECK(cond) \
do { if(!(cond)){ std::cerr << "FAIL: " #cond " @line " << __LINE__ << "\n"; ++fails; } } while(0)
int main()
{
// ── Task 1: parity ───────────────────────────────────────────────────────
CHECK(isEven(0) == true); // zero is even
CHECK(isEven(2) == true);
CHECK(isEven(3) == false);
CHECK(isEven(-4) == true); // edge: negative even
CHECK(isEven(-7) == false); // edge: negative ODD — the `% 2 == 1` trap
CHECK(classifyParity(10) == "even");
CHECK(classifyParity(11) == "odd");
CHECK(classifyParity(-7) == "odd"); // edge: must NOT misfire on negatives
// ── Task 2: FizzBuzz category (specific case first) ──────────────────────
CHECK(fizzbuzzCategory(1) == "number");
CHECK(fizzbuzzCategory(9) == "fizz"); // 3 only
CHECK(fizzbuzzCategory(10) == "buzz"); // 5 only
CHECK(fizzbuzzCategory(15) == "fizzbuzz"); // both — must beat plain "fizz"
CHECK(fizzbuzzCategory(30) == "fizzbuzz");
CHECK(fizzbuzzCategory(0) == "fizzbuzz"); // edge: 0 % 3 == 0 and 0 % 5 == 0
// ── Task 3: leap year (the famous century edge cases) ────────────────────
CHECK(isLeapYear(2024) == true); // divisible by 4, not a century
CHECK(isLeapYear(2023) == false); // not divisible by 4
CHECK(isLeapYear(1900) == false); // edge: century, not /400
CHECK(isLeapYear(2000) == true); // edge: century AND /400
CHECK(isLeapYear(2100) == false); // edge: century, not /400
// ── Task 4: safe float comparison (both sides of epsilon) ────────────────
CHECK(approxEqual(0.1 + 0.2, 0.3, 1e-9) == true); // the classic == failure
CHECK(approxEqual(1.0, 1.0, 1e-9) == true); // exactly equal
CHECK(approxEqual(1.0, 1.5, 0.1) == false); // far apart -> false
CHECK(approxEqual(5.0, 5.0 + 1e-12, 1e-9) == true); // within tolerance
CHECK(approxEqual(-2.0, -2.0, 0.0) == true); // edge: zero epsilon, identical
// ── Task 5: non-negative wrap (negatives are the whole point) ────────────
CHECK(wrapIndex(0, 3) == 0);
CHECK(wrapIndex(2, 3) == 2);
CHECK(wrapIndex(3, 3) == 0);
CHECK(wrapIndex(7, 3) == 1);
CHECK(wrapIndex(-1, 3) == 2); // edge: raw -1 % 3 is -1; must fold to 2
CHECK(wrapIndex(-3, 3) == 0); // edge: lands exactly on 0
CHECK(wrapIndex(-4, 3) == 2);
// ── Task 6: sampling gate (short-circuit must guard the %) ───────────────
CHECK(shouldSampleInstruction(0, 4, 10) == true); // index 0 is on-stride
CHECK(shouldSampleInstruction(8, 4, 10) == true); // 8 % 4 == 0
CHECK(shouldSampleInstruction(5, 4, 10) == false); // off-stride
CHECK(shouldSampleInstruction(8, 4, 0) == false); // out of budget
CHECK(shouldSampleInstruction(8, 0, 10) == false); // edge: sampleEvery 0 -> must NOT do % 0
CHECK(shouldSampleInstruction(8, -2, 10) == false); // edge: negative stride rejected
// ── Task 7: priority ladder (every band + boundaries) ────────────────────
CHECK(ticketPriority(100) == "P0");
CHECK(ticketPriority(90) == "P0"); // boundary
CHECK(ticketPriority(89) == "P1"); // just below
CHECK(ticketPriority(70) == "P1"); // boundary
CHECK(ticketPriority(40) == "P2"); // boundary
CHECK(ticketPriority(39) == "P3");
CHECK(ticketPriority(0) == "P3");
// ── Task 8: exactly-one-of (XOR via !=) ──────────────────────────────────
CHECK(exactlyOneSource(true, false) == true);
CHECK(exactlyOneSource(false, true) == true);
CHECK(exactlyOneSource(true, true) == false); // both -> not "exactly one"
CHECK(exactlyOneSource(false, false) == false); // neither -> not "exactly one"
// ── Task 9: integer power via std::pow ───────────────────────────────────
CHECK(powInt(2, 0) == 1); // edge: anything^0 == 1
CHECK(powInt(2, 8) == 256); // the value `2 ^ 8` would WRONGLY give (that's XOR = 10)
CHECK(powInt(5, 3) == 125); // rounding: pow may return 124.999…
CHECK(powInt(10, 4) == 10000);
CHECK(powInt(0, 5) == 0); // edge: 0^positive == 0
CHECK(powInt(7, 1) == 7);
if (!fails)
std::cout << "PASS ✅ all triage-console checks passed.\n";
else
std::cerr << "\nFAIL ❌ " << fails << " check(s) failed — fix the TASK blocks in triage.cpp.\n";
return fails ? 1 : 0;
}
# Chapter 6 — Operators · Day-One Triage Console · unit-test grader (Style B).
# Targets follow the drills/CLAUDE.md Makefile contract. TABS, not spaces.
#
# The learner implements ../triage.h in starter/triage.cpp. There is no main() in
# triage.cpp on purpose — the grader (tests/tests.cpp) supplies main() and calls
# every function across many inputs, so the learner never writes a loop.
CXX := clang++
CXXFLAGS := -std=c++17 -Wall -Wextra
.PHONY: all build run test solution test-solution clean
all: build
# build — compile-check the learner's code (warning-clean object file, no link).
# There is no program to link yet because tests/ provides main(); `make test`
# does the full build+run. This target just proves your triage.cpp compiles.
build:
$(CXX) $(CXXFLAGS) -c starter/triage.cpp -o starter/triage.o
@echo "OK ✅ starter/triage.cpp compiles. Now run: make test"
# run — for this lab, "running" the code IS running the grader against it.
run: test
# test — grade the LEARNER's code: link the grader against starter/triage.cpp.
# RED until the TASK blocks are filled in; GREEN once they're correct.
test:
$(CXX) $(CXXFLAGS) tests/tests.cpp starter/triage.cpp -o tests/run
@./tests/run
# solution — build+run the grader against the reference implementation.
solution: test-solution
# test-solution — proof the lab is solvable: the reference MUST pass every check.
test-solution:
$(CXX) $(CXXFLAGS) tests/tests.cpp solution/triage.cpp -o tests/run
@./tests/run
clean:
rm -f starter/triage.o tests/run
rm -rf tests/run.dSYM
// Chapter 6 — Operators · Project: Day-One Triage Console
// ─────────────────────────────────────────────────────────────────────────────
// This header is the CONTRACT between you and the grader. It declares the nine
// pure functions you must implement. DO NOT EDIT THIS FILE — the tests in
// tests/tests.cpp include it, and so do BOTH starter/triage.cpp (yours) and
// solution/triage.cpp (the reference). Change a signature here and nothing links.
//
// "Pure" means: each function looks only at its arguments and returns a value.
// No input, no output, no global state, no loops. The grader supplies the
// repetition — it calls each function across MANY inputs — so you never write a
// loop (those are Chapter 8). Your whole job is to get the OPERATORS right.
//
// Header guard (Chapter 2): stops this file being pasted in twice per build.
#ifndef TRIAGE_H
#define TRIAGE_H
#include <string_view> // std::string_view — a cheap, non-owning view (Chapter 5)
// ─── TASK 1 ──────────────────────────────────────────────────────────────────
// Is `value` even? Remainder operator `%` + the conditional operator `?:`.
bool isEven(int value);
// Classify parity as a label. Return "even" or "odd" using ONE `?:` expression.
std::string_view classifyParity(int value);
// ─── TASK 2 ──────────────────────────────────────────────────────────────────
// FizzBuzz as a CATEGORY for a single number (no loop, no printing):
// divisible by both 3 and 5 -> "fizzbuzz"
// divisible by 3 only -> "fizz"
// divisible by 5 only -> "buzz"
// otherwise -> "number"
std::string_view fizzbuzzCategory(int value);
// ─── TASK 3 ──────────────────────────────────────────────────────────────────
// Gregorian leap year via LOGICAL operators (&&, ||) — no `if`, one expression:
// divisible by 4 AND (NOT divisible by 100 OR divisible by 400).
bool isLeapYear(int year);
// ─── TASK 4 ──────────────────────────────────────────────────────────────────
// Safe floating-point "equality": true when |a - b| <= epsilon.
// (Never compare calculated doubles with ==.)
bool approxEqual(double a, double b, double epsilon);
// ─── TASK 5 ──────────────────────────────────────────────────────────────────
// Wrap `index` into [0, size) the way a ring buffer needs — ALWAYS non-negative,
// even for negative indices. (Raw `%` can go negative in C++.) Assume size > 0.
int wrapIndex(int index, int size);
// ─── TASK 6 ──────────────────────────────────────────────────────────────────
// Instrumentation gate (the CS6340 tie-in): fire only when we still have budget
// AND this instruction lands on the sampling stride.
// true <=> (sampleEvery > 0) AND (budgetRemaining > 0)
// AND (instructionIndex % sampleEvery == 0)
// Short-circuit `&&` must guard the `%` so you never divide when sampleEvery is 0.
bool shouldSampleInstruction(int instructionIndex, int sampleEvery, int budgetRemaining);
// ─── TASK 7 ──────────────────────────────────────────────────────────────────
// Ticket routing from a numeric severity score (relational + nested `?:`):
// score >= 90 -> "P0"
// score >= 70 -> "P1"
// score >= 40 -> "P2"
// otherwise -> "P3"
std::string_view ticketPriority(int score);
// ─── TASK 8 ──────────────────────────────────────────────────────────────────
// Exactly-one-of (logical XOR). C++ has no logical-XOR operator, but for two
// bool operands, `!=` means "exactly one is true". Return that.
bool exactlyOneSource(bool fromFile, bool fromStdin);
// ─── TASK 9 ──────────────────────────────────────────────────────────────────
// Integer power base^exponent using std::pow (C++ has NO `**` operator; `^` is
// bitwise XOR, not exponent). std::pow returns double — convert back to int.
// Assume exponent >= 0 and the result fits in an int.
int powInt(int base, int exponent);
#endif // TRIAGE_H
make test locally
(see “Build & run locally” above).