From feedfe951f673c5d542a09201977d7f8cc2f3d75 Mon Sep 17 00:00:00 2001 From: Cal Corum Date: Wed, 8 Apr 2026 07:31:51 -0500 Subject: [PATCH] feat: add RARITY_LADDER, rarity_is_downgrade, and next_rarity helpers (#59) Closes #59 Co-Authored-By: Claude Sonnet 4.6 --- rarity_thresholds.py | 40 ++++++++++++++++++++++++++++++++++++---- 1 file changed, 36 insertions(+), 4 deletions(-) diff --git a/rarity_thresholds.py b/rarity_thresholds.py index ac91961..5305b26 100644 --- a/rarity_thresholds.py +++ b/rarity_thresholds.py @@ -146,16 +146,24 @@ def get_batter_thresholds(season: int) -> BatterRarityThresholds: return BATTER_THRESHOLDS_2024 -# Ordered from worst to best rarity. Used for ladder comparisons such as the -# T4 refractor guard — do not change the order. -RARITY_LADDER = [5, 4, 3, 2, 1, 99] # Common → Bronze → Silver → Gold → Diamond → HoF +# Ordered from least to most prestigious. Used for ladder comparisons (T4 +# rarity upgrade, downgrade guard). Do not change the order. +RARITY_LADDER: list[int] = [ + 5, + 4, + 3, + 2, + 1, + 99, +] # Common → Bronze → Silver → Gold → Diamond → HoF def rarity_is_downgrade(current_rarity_id: int, new_rarity_id: int) -> bool: """Return True if new_rarity_id is a less prestigious tier than current_rarity_id. - Uses the RARITY_LADDER ordering. Unknown IDs are treated as position 0 + Uses the RARITY_LADDER ordering. Unknown IDs are treated as position 0 (worst), so an unknown current rarity will never trigger a downgrade guard. + An unknown new_rarity_id also returns False. """ try: current_pos = RARITY_LADDER.index(current_rarity_id) @@ -166,3 +174,27 @@ def rarity_is_downgrade(current_rarity_id: int, new_rarity_id: int) -> bool: except ValueError: return False return current_pos > new_pos + + +def next_rarity(current_rarity_id: int) -> int | None: + """Return the next more-prestigious rarity ID, or None if already at HoF. + + Uses the RARITY_LADDER ordering. Returns None when current_rarity_id is + Hall of Fame (99) — the T4 rarity upgrade is a no-op at the top tier. + Returns None for any unrecognised rarity ID. + + Examples: + next_rarity(5) → 4 (Common → Bronze) + next_rarity(4) → 3 (Bronze → Silver) + next_rarity(3) → 2 (Silver → Gold) + next_rarity(2) → 1 (Gold → Diamond) + next_rarity(1) → 99 (Diamond → HoF) + next_rarity(99) → None (HoF: already at max) + """ + try: + pos = RARITY_LADDER.index(current_rarity_id) + except ValueError: + return None + if pos == len(RARITY_LADDER) - 1: + return None # Already at HoF + return RARITY_LADDER[pos + 1]