use crate::card::{Card, Suit}; use klondike::KlondikePile; /// A named collection of cards in a specific board position. #[derive(Debug, Clone, PartialEq, Eq)] pub struct Pile { /// Which logical Klondike pile this is. pub pile_type: KlondikePile, /// Cards in the pile, bottom-to-top stacking order. Last element is the top card. pub cards: Vec, } impl Pile { /// Creates a new empty pile of the given type. pub fn new(pile_type: KlondikePile) -> Self { Self { pile_type, cards: Vec::new(), } } /// Returns a reference to the top (last) card, or `None` if empty. pub fn top(&self) -> Option<&Card> { self.cards.last() } /// For foundation piles: returns `Some(suit)` once at least one card has /// landed (the bottom card is always an Ace of the claimed suit). /// Returns `None` for empty foundations or non-foundation piles. pub fn claimed_suit(&self) -> Option { match self.pile_type { KlondikePile::Foundation(_) => self.cards.first().map(|c| c.suit), _ => None, } } } #[cfg(test)] mod tests { use super::*; use crate::card::{Card, Rank, Suit}; #[test] fn new_pile_is_empty() { let pile = Pile::new(KlondikePile::Stock); assert!(pile.cards.is_empty()); } #[test] fn pile_top_returns_last_card() { let mut pile = Pile::new(KlondikePile::Stock); pile.cards.push(Card { id: 0, suit: Suit::Hearts, rank: Rank::Ace, face_up: true, }); pile.cards.push(Card { id: 1, suit: Suit::Clubs, rank: Rank::Two, face_up: true, }); assert_eq!(pile.top().unwrap().id, 1); } #[test] fn pile_top_on_empty_is_none() { let pile = Pile::new(KlondikePile::Stock); assert!(pile.top().is_none()); } #[test] fn claimed_suit_is_none_for_empty_foundation() { let pile = Pile::new(KlondikePile::Foundation(klondike::Foundation::Foundation1)); assert!(pile.claimed_suit().is_none()); } #[test] fn claimed_suit_is_none_for_non_foundation() { let mut pile = Pile::new(KlondikePile::Tableau(klondike::Tableau::Tableau1)); pile.cards.push(Card { id: 0, suit: Suit::Hearts, rank: Rank::Ace, face_up: true, }); assert!(pile.claimed_suit().is_none()); } #[test] fn claimed_suit_returns_bottom_card_suit() { let mut pile = Pile::new(KlondikePile::Foundation(klondike::Foundation::Foundation3)); pile.cards.push(Card { id: 0, suit: Suit::Hearts, rank: Rank::Ace, face_up: true, }); pile.cards.push(Card { id: 1, suit: Suit::Hearts, rank: Rank::Two, face_up: true, }); assert_eq!(pile.claimed_suit(), Some(Suit::Hearts)); } }