17bbec054c
Implements PileType/Pile, MoveError (thiserror), Deck with seeded shuffle, deal_klondike layout, foundation/tableau placement rules, and Windows XP Standard scoring — 41 tests, clippy clean. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
74 lines
1.9 KiB
Rust
74 lines
1.9 KiB
Rust
use crate::pile::PileType;
|
|
|
|
/// Score delta for moving cards from `from` to `to`.
|
|
///
|
|
/// Windows XP Standard scoring:
|
|
/// - +10 for any card reaching a foundation pile
|
|
/// - +5 for a waste → tableau move
|
|
/// - 0 for all other moves
|
|
pub fn score_move(from: &PileType, to: &PileType) -> i32 {
|
|
match to {
|
|
PileType::Foundation(_) => 10,
|
|
PileType::Tableau(_) => {
|
|
if matches!(from, PileType::Waste) { 5 } else { 0 }
|
|
}
|
|
_ => 0,
|
|
}
|
|
}
|
|
|
|
/// Score penalty applied when the player uses undo: -15.
|
|
pub fn score_undo() -> i32 {
|
|
-15
|
|
}
|
|
|
|
/// Time bonus added to the score on a win: `700_000 / elapsed_seconds`.
|
|
/// Returns 0 when `elapsed_seconds` is 0 to avoid division by zero.
|
|
pub fn compute_time_bonus(elapsed_seconds: u64) -> i32 {
|
|
if elapsed_seconds == 0 {
|
|
return 0;
|
|
}
|
|
(700_000u64 / elapsed_seconds).min(i32::MAX as u64) as i32
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use super::*;
|
|
use crate::card::Suit;
|
|
|
|
#[test]
|
|
fn move_to_foundation_scores_ten() {
|
|
assert_eq!(score_move(&PileType::Waste, &PileType::Foundation(Suit::Hearts)), 10);
|
|
assert_eq!(score_move(&PileType::Tableau(0), &PileType::Foundation(Suit::Clubs)), 10);
|
|
}
|
|
|
|
#[test]
|
|
fn waste_to_tableau_scores_five() {
|
|
assert_eq!(score_move(&PileType::Waste, &PileType::Tableau(3)), 5);
|
|
}
|
|
|
|
#[test]
|
|
fn tableau_to_tableau_scores_zero() {
|
|
assert_eq!(score_move(&PileType::Tableau(0), &PileType::Tableau(1)), 0);
|
|
}
|
|
|
|
#[test]
|
|
fn undo_penalty_is_negative_fifteen() {
|
|
assert_eq!(score_undo(), -15);
|
|
}
|
|
|
|
#[test]
|
|
fn time_bonus_at_100_seconds() {
|
|
assert_eq!(compute_time_bonus(100), 7000);
|
|
}
|
|
|
|
#[test]
|
|
fn time_bonus_at_zero_is_zero() {
|
|
assert_eq!(compute_time_bonus(0), 0);
|
|
}
|
|
|
|
#[test]
|
|
fn time_bonus_at_one_second() {
|
|
assert_eq!(compute_time_bonus(1), 700_000);
|
|
}
|
|
}
|