Skip to content

Add label to DifficultyBudget.Rating; guard zero player count in rating factory#25

Merged
gwillish merged 2 commits into
mainfrom
claude/confident-hoover-cd026a
Apr 25, 2026
Merged

Add label to DifficultyBudget.Rating; guard zero player count in rating factory#25
gwillish merged 2 commits into
mainfrom
claude/confident-hoover-cd026a

Conversation

@gwillish
Copy link
Copy Markdown
Owner

@gwillish gwillish commented Apr 25, 2026

Summary

Closes #24.

  • DifficultyBudget.Rating.Category — new nested enum with six typed cases (tooEasy, wellMatched, onBudget, challenging, dangerous, likelyTPK), each carrying its display string as the raw value. Category.displayName returns rawValue.
  • DifficultyBudget.Rating.category: Category — computed property that maps remaining to the enum case using the authoritative thresholds from DifficultyAssessorView.
  • DifficultyBudget.Rating.displayName: String — convenience shim; equivalent to category.displayName.
  • rating(adversaryTypes:playerCount:budgetAdjustment:) returns Rating? — guards playerCount > 0; returns nil for zero or negative player counts. Callers decide how to render the absence.

Breaking change

rating(adversaryTypes:playerCount:budgetAdjustment:) now returns Rating? instead of Rating. A semver major version bump is required on the next release.

Test plan

  • Existing ratingWithinBudgetIsBalanced, ratingOverBudgetShowsNegativeRemaining, ratingWithBudgetAdjustment updated to throws + try #require(...)
  • ratingReturnsNilForZeroPlayers — nil for playerCount: 0
  • ratingReturnsNilForNegativePlayers — nil for playerCount: -1
  • categoryTooEasy through categoryLikelyTPK — two boundary values each, comparing against typed enum cases (not strings)
  • displayNameMatchesCategoryRawValue — verifies displayName == category.rawValue
  • swift test --filter DHModelsTests — 94 tests, 0 failures
  • ./Scripts/format.sh — clean lint

Follow-up (Encounter repo)

DifficultyAssessorView and EncounterLibraryRow can now replace their local switch rating.remaining with rating.category (for branching) or rating.displayName (for display). Tracked in Encounter #91.

…count

Moves the difficulty label switch from DifficultyAssessorView into the
model so any view gets the canonical label without a local switch. Also
guards against a zero-player party, which produces a meaningless budget,
by returning nil from the rating factory.

Closes #24
…ount

- Nest `Category: String, Sendable` enum inside `Rating` with six cases
  (tooEasy, wellMatched, onBudget, challenging, dangerous, likelyTPK)
  and a `displayName` property that returns the raw-value string
- Replace `label: String` (extension) with `category: Category` and
  `displayName: String` as struct members; drop the trailing extension
- Extend nil guard in `rating(...)` to cover negative playerCount
- Update tests: rename labelXxx → categoryXxx, compare against enum
  cases instead of string literals, add negative-playerCount nil test
  and displayName round-trip test
@gwillish gwillish merged commit 478fdd8 into main Apr 25, 2026
2 checks passed
@gwillish gwillish deleted the claude/confident-hoover-cd026a branch April 25, 2026 18:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add label: String to DifficultyBudget.Rating

1 participant