diff --git a/solitaire_core/src/game_state.rs b/solitaire_core/src/game_state.rs index 341a52a..edf2b4a 100644 --- a/solitaire_core/src/game_state.rs +++ b/solitaire_core/src/game_state.rs @@ -191,7 +191,7 @@ impl GameState { is_auto_completable: false, undo_count: 0, recycle_count: 0, - take_from_foundation: false, + take_from_foundation: true, schema_version: GAME_STATE_SCHEMA_VERSION, undo_stack: VecDeque::new(), } @@ -1306,9 +1306,18 @@ mod tests { } #[test] - fn take_from_foundation_blocked_by_default() { + fn take_from_foundation_allowed_by_default() { let mut g = setup_take_from_foundation_game(); - assert!(!g.take_from_foundation); + assert!(g.take_from_foundation, "standard Klondike allows take-from-foundation by default"); + g.move_cards(PileType::Foundation(0), PileType::Tableau(0), 1).unwrap(); + assert_eq!(g.piles[&PileType::Foundation(0)].cards.len(), 1); + assert_eq!(g.piles[&PileType::Tableau(0)].cards.len(), 2); + } + + #[test] + fn take_from_foundation_blocked_when_disabled() { + let mut g = setup_take_from_foundation_game(); + g.take_from_foundation = false; let err = g .move_cards(PileType::Foundation(0), PileType::Tableau(0), 1) .unwrap_err(); @@ -1321,6 +1330,7 @@ mod tests { #[test] fn take_from_foundation_allowed_when_enabled() { let mut g = setup_take_from_foundation_game(); + // already true by default; explicit set confirms the behaviour holds g.take_from_foundation = true; g.move_cards(PileType::Foundation(0), PileType::Tableau(0), 1).unwrap(); // Foundation slot 0 should now hold only the Ace. diff --git a/solitaire_data/src/settings.rs b/solitaire_data/src/settings.rs index 5ddcef4..c4beaa9 100644 --- a/solitaire_data/src/settings.rs +++ b/solitaire_data/src/settings.rs @@ -239,11 +239,11 @@ pub struct Settings { /// field existed deserialize cleanly to `None` via `#[serde(default)]`. #[serde(default)] pub leaderboard_display_name: Option, - /// When `true`, the player may drag the top card of a completed foundation - /// pile back onto a compatible tableau column — a non-standard house rule. - /// Off by default. Older `settings.json` files deserialize cleanly to - /// `false` via `#[serde(default)]`. - #[serde(default)] + /// When `true`, the player may drag the top card of a foundation pile back + /// onto a compatible tableau column. Enabled by default (standard Klondike + /// rules). Older `settings.json` files without this key deserialize to + /// `true` via the custom serde default. + #[serde(default = "default_take_from_foundation")] pub take_from_foundation: bool, /// When `true`, anonymous game-play events (game start, game won, etc.) /// are sent to the configured Matomo instance. Opt-in; defaults to `false`. @@ -332,6 +332,10 @@ fn default_matomo_site_id() -> u32 { 1 } +fn default_take_from_foundation() -> bool { + true +} + /// Lower bound of the player-tunable replay-playback per-move interval, /// in seconds. Below this the cards barely register visually before /// the next move fires; the cap keeps the playback legible. @@ -384,7 +388,7 @@ impl Default for Settings { replay_move_interval_secs: default_replay_move_interval_secs(), last_difficulty: None, leaderboard_display_name: None, - take_from_foundation: false, + take_from_foundation: true, analytics_enabled: false, matomo_url: None, matomo_site_id: default_matomo_site_id(),