fix(multi): resolve 14 bugs from second comprehensive review
Build and Deploy / build-and-push (push) Successful in 4m2s
Build and Deploy / build-and-push (push) Successful in 4m2s
Core (solitaire_core): - fix(scoring): apply -15 penalty for Foundation→Tableau moves when take_from_foundation is enabled; update test - fix(solver): is_won() validates full Ace→King suit sequence, not just card count — prevents hint system from emitting invalid paths Engine — animation / layout: - fix(animation): guard CardAnim advance against duration=0 to prevent NaN-poisoned Transform (analogous to CardAnimation's instant-snap path) - fix(card_plugin): align TABLEAU_FAN_FRAC (0.25→0.18) and TABLEAU_FACEDOWN_FAN_FRAC (0.20→0.14) with layout.rs so the initial layout and first dynamic update produce identical fan spacing - fix(layout): update tableau_fan_frac doc comment from 0.25→0.18 Engine — ECS / modal guards: - fix(auto_complete): drive_auto_complete now checks PausedResource so cooldown does not tick while paused (prevents instant-move on unpause) - fix(play_by_seed): handle_open_dialog checks global ModalScrim guard to prevent stacking over an existing modal - fix(win_summary): spawn_win_summary_after_delay checks global ModalScrim guard; collect_session_achievements uses .next() not .last() to avoid draining the new_games stream Engine — message registration: - fix(leaderboard): register InfoToastEvent in LeaderboardPlugin::build so opt-in/opt-out toasts work under MinimalPlugins - fix(replay_playback): register StateChangedEvent in ReplayPlaybackPlugin::build to prevent panic when used standalone Security: - fix(sync_setup): zero password SyncFieldBuffer immediately after spawning auth task — credential must not linger in ECS components Server: - fix(auth): replace MIME contains-chain with exact match for avatar upload; removes illusory starts_with guard and dead ALLOWED_IMAGE_TYPES Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -9,9 +9,11 @@ use crate::pile::PileType;
|
||||
pub fn score_move(from: &PileType, to: &PileType) -> i32 {
|
||||
match to {
|
||||
PileType::Foundation(_) => 10,
|
||||
PileType::Tableau(_) => {
|
||||
if matches!(from, PileType::Waste) { 5 } else { 0 }
|
||||
}
|
||||
PileType::Tableau(_) => match from {
|
||||
PileType::Waste => 5,
|
||||
PileType::Foundation(_) => -15,
|
||||
_ => 0,
|
||||
},
|
||||
_ => 0,
|
||||
}
|
||||
}
|
||||
@@ -71,13 +73,12 @@ mod tests {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn non_waste_to_tableau_scores_zero() {
|
||||
// Foundation → Tableau is impossible in practice but must score 0.
|
||||
assert_eq!(score_move(&PileType::Foundation(0), &PileType::Tableau(0)), 0);
|
||||
// Tableau → Tableau (restack) scores 0.
|
||||
assert_eq!(score_move(&PileType::Tableau(1), &PileType::Tableau(2)), 0);
|
||||
fn foundation_to_tableau_penalises_fifteen() {
|
||||
// Moving a card back off a foundation (take_from_foundation rule) costs -15.
|
||||
assert_eq!(score_move(&PileType::Foundation(0), &PileType::Tableau(0)), -15);
|
||||
}
|
||||
|
||||
|
||||
#[test]
|
||||
fn move_to_stock_or_waste_scores_zero() {
|
||||
// These destinations are illegal moves in practice, but the function
|
||||
|
||||
Reference in New Issue
Block a user