C++ / C# · progressively harder

Optional challenge bank

Explore the repository freely, or choose a challenge for inspiration; completing all 18 levels is not expected.

Use these optional challenges when you want a starting point or a next investigation. They are useful after the four core exercises, but can be explored in any order; each level names its prerequisites, and you do not need to complete the whole bank. Use your assigned language unless it says both.

The file map and test commands is a reference, not required reading before every exercise. Prompt support fades from questions to keywords and then your own approach; use whatever support fits the level you choose. Ask OpenCode for a small hint when needed.

Start a fresh agent Read the selected level in docs/challenges.md. Tell us its purpose, the first check to run, and which result we should inspect before editing.

Optional · 18 levels

Pick your next level together

Levels 1–7 use your assigned language. Levels 8–18 may use both C++ and C#.

  1. 01Map both implementationsFind the corresponding functions and tests in C++ and C# before extending them.Purpose · task · result
    Purpose

    Find the corresponding functions and tests in C++ and C# before extending them.

    Task
    1. Run git status --short and git rev-parse HEAD as a separate extra-exercise baseline; describe existing changes only if they affect your comparison.
    2. Use the file map to locate both implementations of ClippedArea and ClassifyPoint, and their actual test assertions.
    3. Run ./scripts/test-cpp.sh and ./scripts/test-csharp.sh; keep both results available for comparison without editing.
    Hint

    The core exercises may already have changed one language. Preserve that starting point.

    Prompt support

    Ask for a file map and both test results.

    Done when

    You can locate both versions and distinguish existing failures from later changes.

  2. 02Map specification rules to testsFind behaviours the public tests cover—and those they miss.Purpose · task · result
    Purpose

    Find behaviours the public tests cover—and those they miss.

    Task
    1. Read docs/spec.md and both public-test files from the file map.
    2. Create docs/contract-test-matrix.md: one row per explicit rule, with C++ assertion, C# assertion and coverage gap columns.
    3. Check each assertion’s input and comparison; cite its file and test name or line. Do not edit tests yet.
    Hint

    An untested rule is a coverage gap. Behaviour the specification never defines is a different kind of gap.

    Prompt support

    Ask which assertions support each rule and what is missing.

    Done when

    Every explicit rule has traceable coverage or a clearly named gap.

  3. 03Add small geometry regressionsProtect two defined behaviours with examples you can calculate yourself.Purpose · task · result
    Purpose

    Protect two defined behaviours with examples you can calculate yourself.

    Task

    In your assigned language’s public tests, add missing coverage for:

    • Vertex classification: polygon (0,0),(10,0),(10,10),(0,10), point (0,0) → Boundary.
    • Partial overlap: polygon (5,5),(15,5),(15,15),(5,15), Rect64(0,0,10,10) → area 25.

    Test both vertex orders. Explain each expectation, avoid duplicate coverage, and run ./scripts/test-cpp.sh or ./scripts/test-csharp.sh.

    Hint

    Compare classification exactly and area within 0.001; a reversed polygon describes the same shape.

    Prompt support

    Ask for justified expectations and regressions in both orientations.

    Done when

    Both cases and orientations pass in your language’s public suite.

  4. 04Test touching shapes and translationCheck that touching produces zero area and moving all inputs preserves behaviour.Purpose · task · result
    Purpose

    Check that touching produces zero area and moving all inputs preserves behaviour.

    Task

    Add these cases to your assigned public tests:

    • Edge touch: polygon (10,2),(14,2),(14,8),(10,8) and Rect64(0,0,10,10) → exactly 0.
    • Corner touch: polygon (10,10),(14,10),(14,14),(10,14) with that rectangle → exactly 0.
    • Translation: polygon (2,2),(8,2),(8,8),(2,8), Rect64(0,0,6,6), point (2,5). Calculate area and classification first. Then shift polygon, rectangle and point by (-5,-7) and assert both the calculated expectations and unchanged results.

    Run ./scripts/test-cpp.sh or ./scripts/test-csharp.sh.

    Hint

    Use exact zero and classification assertions; use 0.001 tolerance for nonzero areas and area comparisons.

    Prompt starter — finish it as a team

    Ask why touching and translation should preserve these expectations.

    Done when

    Original and translated cases pass with independently explained expectations.

  5. 05Predict before runningSeparate your prediction, the AI’s confidence and the implementation’s actual behaviour.Purpose · task · result
    Purpose

    Separate your prediction, the AI’s confidence and the implementation’s actual behaviour.

    Task

    First write your team’s predictions, then ask for AI predictions and confidence. Do not run these inputs until both are saved in docs/prediction-results.md.

    OperationPolygonRectangle or point
    ClassifyPoint(0,10),(10,10),(10,0),(0,0)point (10,10)
    ClassifyPoint(0,0),(0,0),(10,0),(10,10),(0,10)point (5,0)
    ClippedArea(0,0),(10,0),(10,10),(0,10)Rect64(5,0,5,10)
    ClippedArea(0,0),(10,10)Rect64(0,0,10,10)
    ClippedArea(0,0),(1000000,0),(1000000,1),(0,1)Rect64(0,0,1000000,1000000)
    ClassifyPoint(0,0),(10,10),(10,0),(0,10)point (5,5)

    Use a temporary runner in your language under build/experiments/ to print actual results. Save the exact command and observations beside the original predictions, identify which results the specification promises, then remove the runner.

    Hint

    Some inputs are deliberately outside the specification’s defined cases. Print observations; do not turn guesses into test assertions.

    Prompt starter — finish it as a team

    Ask for predictions and confidence before allowing any execution.

    Done when

    All six rows distinguish predictions, observations and specification coverage; wrapper and public tests are unchanged.

  6. 06Propose a missing ruleTurn unspecified behaviour into an explicit design question.Purpose · task · result
    Purpose

    Turn unspecified behaviour into an explicit design question.

    Task
    1. In your language, use a temporary runner to observe ClippedArea for (0,0),(10,10),(10,0),(0,10) and Rect64(0,0,10,10).
    2. This polygon crosses itself; docs/spec.md does not settle its interpretation. Propose a testable rule with a benefit, compatibility implications and an example test.
    3. Append the proposal, input, exact command and observation to docs/spec-proposals.md (create it if absent). Remove the runner; leave the existing specification, wrapper and tests unchanged.
    Hint

    Observed output is evidence for discussion, not automatically the required answer.

    Prompt starter — finish it as a team

    Ask what rule would make this behaviour testable.

    Done when

    A clearly labelled proposal explains both the intended behaviour and its consequences.

  7. 07Challenge a proposed optimisationUse a counterexample to test whether a faster-looking implementation is correct.Purpose · task · result
    Purpose

    Use a counterexample to test whether a faster-looking implementation is correct.

    Task

    Start with passing tests in your assigned language.

    1. Read the supplied bounding-box proposal. Design a polygon where one of its early returns gives the wrong area. Calculate the correct result independently.
    2. Add a public regression and show it passing on the original code.
    3. Apply ./scripts/apply-l7-patch.sh cpp or ./scripts/apply-l7-patch.sh csharp. Run your language’s test script and show an assertion failure. Then run the same helper with --revert and demonstrate a pass again.

    Record the calculation and three results. If the helper cannot find its insertion point, stop and ask a facilitator; do not adapt or force the patch.

    Hint

    A polygon’s bounding box can contain empty space. Inspect the final diff: keep the regression and other team work, remove every temporary patch line.

    Optional hint

    Ask which early-return claim a counterexample could disprove.

    Done when

    The recorded pass → assertion failure → pass shows that your regression rejects the proposal.

  8. 08Mirror a regression in both languagesCheck that C++ and C# protect the same behaviour.Purpose · task · result
    Purpose

    Check that C++ and C# protect the same behaviour.

    Task
    1. Choose a regression from extras 3–7, or the partial-overlap case in extra 3 if you skipped them.
    2. Add equivalent assertions to both public-test files in the file map. Compare coordinates, ordering, expected values and tolerances side by side.
    3. Run ./scripts/test-cpp.sh, ./scripts/test-csharp.sh and ./scripts/test-all.sh.
    Hint

    Investigate mismatches; do not change expectations just to match each implementation.

    Optional hint

    Prompt ingredients: same input, same expectation, both languages.

    Done when

    Both suites test the same justified result and all three commands pass.

  9. 09Follow a clipping operation through the libraryVerify an AI explanation against actual Clipper2 source.Purpose · task · result
    Purpose

    Verify an AI explanation against actual Clipper2 source.

    Task
    1. Ask how an edge crossing is handled and output paths are assembled. In your language, locate GetIntersection, AddCorner and ExecuteInternal in src/cpp/Clipper2Lib/src/clipper.rectclip.cpp or src/csharp/Clipper2Lib/Clipper.RectClip.cs.
    2. Open and verify at least two file:line citations from the explanation.
    3. Test one observable claim through ClippedArea or RectClip in your public suite. Explain the expected result, run your language’s test script and retain the passing regression.
    Hint

    Trace one small example. Save the exact prompt and context if you want to compare models in extra 17.

    Optional hint

    Prompt ingredients: edge crossing, source citations, observable evidence.

    Done when

    Two citations support the explanation and a passing test demonstrates one claim.

  10. 10Test relationships across shapesCheck properties across multiple inputs while keeping exact-value regressions.Purpose · task · result
    Purpose

    Check properties across multiple inputs while keeping exact-value regressions.

    Task
    1. Define the same fixed list of at most 20 small rectangles or non-self-intersecting triangles in both public suites. Give each explicit coordinates, clip rectangle, query point and stable case ID.
    2. Test that reversing vertex order or translating all inputs together preserves area and classification. Check clipped area lies between zero and the rectangle’s area. Explain why these relationships hold.
    3. Keep earlier exact-value assertions, identify cases and coordinates in failures, and run both language scripts plus ./scripts/test-all.sh.
    Hint

    Use 0.001 area tolerance consistently, including bounds. Relationships alone can miss an implementation that always returns zero.

    Optional hint

    Prompt ingredients: fixed cases, invariants, exact-value tests.

    Done when

    Both languages pass the same reproducible cases and retain independent expected-value tests.

  11. 11Compare language outputs automaticallyBuild differential testing: give both implementations identical inputs and report output differences.Purpose · task · result
    Purpose

    Build differential testing: give both implementations identical inputs and report output differences.

    Task
    1. Choose at least 20 fixed valid cases with IDs, polygons, clip rectangles and query points. Reuse extra 10’s cases and add enough to reach 20.
    2. Make the public-test executables write fresh build/parity-cpp.csv and build/parity-csharp.csv: columns case_id,area,classification, identical ordering, invariant decimal formatting and names Outside, Boundary, Inside.
    3. Create executable scripts/parity-diff.sh. Compare by ID; reject duplicates, missing IDs, different classifications or area differences above 0.001, returning nonzero on failure.
    4. Run the exact generation/comparison commands. Demonstrate a detected mismatch with an altered copy, then regenerate genuine outputs. Keep CSVs out of commits.
    Hint

    Resolve paths from the repository root and show absolute output paths. Prevent stale CSVs surviving failed generation. Language agreement does not replace independently justified tests.

    Optional hint

    Prompt ingredients: fresh outputs, reliable comparison, demonstrated failure.

    Done when

    Genuine outputs match or have explained differences, the comparator detects a deliberate mismatch, and normal tests still run.

  12. 12Add a small batch APIAgree on a feature’s behaviour before asking AI to implement it.Purpose · task · result
    Purpose

    Agree on a feature’s behaviour before asking AI to implement it.

    Task
    1. Choose ClassifyPoints (many points, one polygon) or ClippedAreas (many polygons, one rectangle; the default). Write exact C++/C# signatures in docs/batch-api.md: preserve input order, return an empty list for empty input, and match separate single-input calls. Areas remain independent, not a polygon union.
    2. Ask for separate API-convention and test-design passes, using bounded assistants if available or sequentially otherwise. Review the integrated plan as a team before implementation.
    3. Add the API and declarations in both languages, with empty-input and order-sensitive mixed-input tests. Run both language scripts and ./scripts/test-all.sh.
    Hint

    Keep the feature a thin layer over the existing functions; verify every assistant’s contribution.

    Optional hint

    Prompt ingredients: contract first, bounded work, verification.

    Done when

    Both APIs follow the agreed document and tests pass, including empty input and ordering.

  13. 13Prove a regression catches a bugPractise mutation testing: temporarily introduce a specific mistake and show your test detects it.Purpose · task · result
    Purpose

    Practise mutation testing: temporarily introduce a specific mistake and show your test detects it.

    Task

    Start from passing tests in your assigned language.

    1. Design a non-self-intersecting polygon whose clipped intersection has at least two separate pieces. In a temporary runner, confirm raw RectClip path count with .size() (C++) or .Count (C#). Independently calculate their combined area and add a ClippedArea regression.
    2. Show the regression passing. Save the exact current accumulation/return lines, then temporarily replace them with the incorrect return below. Run your language’s test script and demonstrate an assertion failure.
    3. Restore those exact lines and show a pass. Retain the regression and results; remove the runner and all deliberately incorrect code without losing other changes.

    C++ temporary return:

    return clipped.empty()
        ? 0.0
        : std::abs(Clipper2Lib::Area(clipped.front()));

    C# temporary return:

    return clipped.Count == 0
        ? 0.0
        : Math.Abs(Clipper.Area(clipped[0]));
    Hint

    The bug counts only the first piece. If your result variable is not clipped or the replacement boundary is unclear, ask a facilitator. A compilation failure is not proof.

    Optional hint

    Your turn: design the request.

    Done when

    You recorded at least two paths and pass → intended assertion failure → pass; the original implementation is restored.

  14. 14Reduce an input without losing its behaviourMake a surprising result easier to investigate by finding a smaller example.Purpose · task · result
    Purpose

    Make a surprising result easier to investigate by finding a smaller example.

    Task

    Use your language’s ClippedArea with Rect64(0,0,20,20) and:

    (0,0),(5,5),(10,10),(15,15),(20,20),(20,10),
    (20,0),(15,5),(10,10),(5,15),(0,20),(0,10)
    1. Create a temporary runner under build/experiments/ that reads vertices from a data file. Record its exact command and initial result in docs/minimised-case.md.
    2. Choose a fixed condition to preserve, such as that area within a stated tolerance. Remove one vertex at a time, keeping order and at least three vertices; rerun after each attempt. Record accepted and rejected removals.
    3. At the end, try every permitted single-vertex removal. Retain the final input, condition, commands and results; remove the runner. Leave wrapper and public tests unchanged.
    Hint

    The polygon crosses itself, so its result is an observation, not a specification guarantee. No further single deletion means locally minimal, not globally smallest.

    Optional hint

    Your turn: design the request.

    Done when

    The smaller input preserves your fixed condition and the final deletion attempts justify local minimality.

  15. 15Investigate precision at large coordinatesSee whether an exact integer area survives the API’s floating-point return value.Purpose · task · result
    Purpose

    See whether an exact integer area survives the API’s floating-point return value.

    Task
    1. For k = 1..9, set n = 10^k - 1. Use square (0,0),(n,0),(n,n),(0,n) and Rect64(0,0,n,n); its exact area is n × n.
    2. In a temporary runner under build/, use your language’s BigInteger, unsigned __int128 or a verified equivalent. Print nine ordered rows: k, n, exact integer area, actual ClippedArea result and exact numeric equality. Do not round the expected integer to double before comparing.
    3. Save all rows, exact command and first mismatch (if any) in docs/precision-results.md. Append an accuracy/range proposal with compatibility implications to docs/spec-proposals.md, creating it if needed. Remove the runner; leave existing specification, wrapper and tests unchanged.
    Hint

    Explain the comparison method before trusting it. This investigates exact equality, not the ordinary 0.001 test tolerance.

    Optional hint

    Your turn: design the request.

    Done when

    Your evidence preserves the exact reference and supports a clearly labelled proposal, without assuming a mismatch must occur.

  16. 16Prepare a reviewable changeMake it easy for someone else to understand and assess your work.Purpose · task · result
    Purpose

    Make it easy for someone else to understand and assess your work.

    Task
    1. Use the extra-exercise baseline from extra 1, or identify a commit immediately before your intended changes. Confirm the diff contains the right scope.
    2. Inspect git status --short and git diff. Put remaining work into focused commits without generated files, unrelated changes or rewriting shared history. Run ./scripts/test-all.sh.
    3. In a fresh AI conversation, request a review with the exact baseline/final commits, relevant specification, source and test output. Look for unsupported claims, unrelated changes, weakened assertions and missing negative cases.
    4. Assess substantive findings in docs/review-notes.md: accept or reject with evidence. Fix grounded issues, rerun affected tests and update the final revision.
    Hint

    Negative cases exercise different or empty results, or documented rejection. Treat review findings as hypotheses; do not request a quota of problems.

    Optional hint

    Your turn: design the request.

    Done when

    The scope and commit purposes are clear, findings are resolved with reasons, and final tests pass.

  17. 17Compare two models fairlyChoose which answer to trust using evidence rather than confidence or length.Purpose · task · result
    Purpose

    Choose which answer to trust using evidence rather than confidence or length.

    Task
    1. Reuse a question from extra 7 or 9. Prepare one prompt and the same code/specification snapshot for both models; include neither model’s earlier answer.
    2. For each run, use /new, /models, then Tab to select Plan (details). Record actual model names. Decline file-changing actions, compare before/after diffs, and time each complete answer with a phone timer.
    3. In docs/model-comparison.md, make two model rows with three columns: citations verified, one claim tested with actual command/result, and elapsed time. Verify claims after collecting both answers; label missing evidence honestly.
    4. Explain which answer you trust and why. Retain experiment inputs/results, then remove only temporary comparison code; preserve earlier tests.
    Hint

    Fresh conversations and identical context make the comparison meaningful. Plan alone does not guarantee files stay unchanged.

    Optional hint

    Your turn: design the request.

    Done when

    Two equivalent runs have an evidence-based comparison and no source/test changes from the experiment remain.

  18. 18Write useful instructions for your AITurn your experience into working rules you can test.Purpose · task · result
    Purpose

    Turn your experience into working rules you can test.

    Task
    1. Choose lessons from successful approaches, confusion or an optional AI mistake. Write 3–5 concise rules in docs/team-rules.md, each with an observable action and the experience behind it.
    2. Choose an earlier prompt that could benefit. In a fresh conversation, explicitly load the rules, supply the same necessary context and repeat that prompt unchanged.
    3. Record a brief before/after comparison: what did you expect to change, and what actually changed?
    Hint

    The file is not loaded automatically. Keep existing repository agent instructions intact; “no clear improvement” is a valid observation.

    Optional hint

    Your turn: design the request.

    Done when

    Your rules are specific, explicitly used in a fresh conversation, and evaluated against an earlier response.