refactor(core,engine,wasm): canonical FOUNDATIONS/TABLEAUS consts; adopt upstream SUITS/RANKS

Review findings 1+2 (Quat-underuse lens, 2026-07-06):

- solitaire_core gains pub const FOUNDATIONS / TABLEAUS — the canonical
  iteration source for the upstream pile enums (upstream klondike has no
  Foundation::ALL, and inherent impls cannot be added to foreign types).
  Deletes three identical private const-fn copies (radial_menu,
  table_plugin, input_plugin) and the hand-enumerated variants in
  card_plugin::sync::all_cards and solitaire_wasm.

- Hand-rolled [Suit; 4] / [Rank; 13] arrays replaced with upstream
  Suit::SUITS / Rank::RANKS. The order-sensitive CardImageSet indexing
  is re-keyed through canonical card_plugin::{suit_index, rank_index}
  helpers that match upstream order, with regression tests asserting
  the correspondence — one ordering everywhere instead of three
  divergent local ones.

Net -177 lines. No behaviour change; all consumers go through the
canonical helpers.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
funman300
2026-07-06 19:58:33 -07:00
parent 15bb136c79
commit 7a5f03987d
11 changed files with 120 additions and 297 deletions
+21 -2
View File
@@ -137,6 +137,23 @@ pub const RED_SUIT_COLOUR_HC: Color = Color::srgb(1.000, 0.408, 0.408);
/// high-contrast boost path.
pub const BLACK_SUIT_COLOUR: Color = Color::srgb(0.910, 0.910, 0.910);
/// Canonical outer index of `s` in [`CardImageSet::faces`].
///
/// Derived from the upstream `card_game::Suit` discriminants (0..=3 in
/// `Suit::SUITS` order), so every reader and writer of `faces` computes
/// the same layout from the same source. Three hand-rolled copies of this
/// mapping once lived in card_plugin and theme/plugin and were one
/// reorder away from drawing the wrong art.
pub(crate) const fn suit_index(s: solitaire_core::Suit) -> usize {
s as usize
}
/// Canonical inner index of `r` in [`CardImageSet::faces`] — upstream
/// `card_game::Rank` discriminants are 1..=13 in `Rank::RANKS` order.
pub(crate) const fn rank_index(r: solitaire_core::Rank) -> usize {
r as usize - 1
}
/// Pre-loaded [`Handle<Image>`]s for card face and back PNG textures.
///
/// Loaded once at startup by [`load_card_images`]. When this resource is
@@ -146,8 +163,10 @@ pub const BLACK_SUIT_COLOUR: Color = Color::srgb(0.910, 0.910, 0.910);
pub struct CardImageSet {
/// Per-card face images indexed by `[suit][rank]`.
///
/// Suit order: Clubs=0, Diamonds=1, Hearts=2, Spades=3.
/// Rank order: Ace=0, Two=1 … King=12.
/// Layout is pinned to the upstream declaration order — index with
/// [`suit_index`] / [`rank_index`], never a hand-rolled match.
/// Suit order: `Suit::SUITS` (Spades=0, Hearts=1, Clubs=2, Diamonds=3).
/// Rank order: `Rank::RANKS` (Ace=0 … King=12).
pub faces: [[Handle<Image>; 13]; 4],
/// One handle per unlockable card-back design (indices 04). These
/// correspond to the legacy `assets/cards/backs/back_N.png` art, indexed