diff options
author | Kjetil Orbekk <kj@orbekk.com> | 2022-12-23 21:29:46 -0500 |
---|---|---|
committer | Kjetil Orbekk <kj@orbekk.com> | 2022-12-23 21:33:50 -0500 |
commit | 0f3c580176ee50795908bf16b4abf9f6faa0565c (patch) | |
tree | 92a5d80e7c4bf24753a2710698d0e1824722c009 | |
parent | 8f72f1dcdf2309484b1c5e933984bb6215c14999 (diff) |
Fix winning trick implementation
-rw-r--r-- | protocol/src/bridge_engine.rs | 52 |
1 files changed, 43 insertions, 9 deletions
diff --git a/protocol/src/bridge_engine.rs b/protocol/src/bridge_engine.rs index 70dcda4..fb4efa7 100644 --- a/protocol/src/bridge_engine.rs +++ b/protocol/src/bridge_engine.rs @@ -92,9 +92,28 @@ pub struct Trick { } impl Trick { - pub fn winner(&self) -> Player { - error!("XXX: Returning incorrect result for winner"); - self.leader + pub fn suit(&self) -> Option<Suit> { + self.cards_played.iter().next().map(|&Card(suit, _)| suit) + } + + // TODO: This should be moved somewhere we can guarantee that cards are non-empty. + pub fn winner(&self, trump_suit: Option<Suit>) -> Player { + let suit = self.suit(); + let value = |c: &Card| { + if Some(c.suit()) == trump_suit { + 14 + c.rank() as i8 + } else if Some(c.suit()) == suit { + c.rank() as i8 + } else { + 0 + } + }; + + let (i, _) = self.cards_played + .iter() + .enumerate() + .max_by(|&(_, c1), &(_, c2)| value(c1).cmp(&value(c2))).unwrap(); + self.leader.many_next(i) } } @@ -151,6 +170,7 @@ impl TurnInPlay { #[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)] pub struct DealInPlay { deal: Deal, + trump_suit: Option<Suit>, tricks_played: Vec<Trick>, in_progress: TurnInPlay, } @@ -162,9 +182,14 @@ pub enum DealInPlayResult { } impl DealInPlay { - pub fn new(leader: Player, deal: Deal) -> DealInPlay { + pub fn new( + leader: Player, + trump_suit: Option<Suit>, + deal: Deal, + ) -> DealInPlay { DealInPlay { deal, + trump_suit, tricks_played: Vec::with_capacity(13), in_progress: TurnInPlay::new(leader), } @@ -199,7 +224,9 @@ impl DealInPlay { let player_cards = player.get_cards_mut(&mut self.deal); if let Some(suit) = self.in_progress.suit() { - if card.suit() != suit && player_cards.iter().find(|c| c.suit() == suit).is_some() { + if card.suit() != suit + && player_cards.iter().find(|c| c.suit() == suit).is_some() + { return Err(anyhow!("Must follow {suit} suit")); } } @@ -223,7 +250,7 @@ impl DealInPlay { }) } TurnInPlayResult::Trick(trick) => { - let trick_winner = trick.winner(); + let trick_winner = trick.winner(self.trump_suit); let mut tricks = self.tricks_played; tricks.push(trick); @@ -231,6 +258,7 @@ impl DealInPlay { DealInPlayResult::PlayFinished(tricks) } else { DealInPlayResult::InProgress(Self { + trump_suit: self.trump_suit, in_progress: TurnInPlay::new(trick_winner), tricks_played: tricks, deal: self.deal, @@ -636,8 +664,11 @@ pub struct PlayState { impl PlayState { pub fn new(deal: Deal, contract: Contract, bidding: Bidding) -> Self { - let playing_deal = - DealInPlay::new(contract.declarer.many_next(3), deal.clone()); + let playing_deal = DealInPlay::new( + contract.declarer.many_next(3), + contract.highest_bid.suit, + deal.clone(), + ); Self { deal, contract, @@ -1329,7 +1360,7 @@ mod tests { #[test] fn play_hand() { - let deal = DealInPlay::new(Player::West, mini_deal()); + let deal = DealInPlay::new(Player::West, None, mini_deal()); assert_eq!(deal.tricks_played, vec!()); { let err = deal.clone().play(mkcard("♥9")).unwrap_err().to_string(); @@ -1354,5 +1385,8 @@ mod tests { cards_played: mkcards("♢A ♢Q ♢7 ♡10"), }) ); + let trick = &deal.tricks_played[0]; + assert_eq!(trick.winner(None), Player::West); + assert_eq!(trick.winner(Some(Suit::Heart)), Player::South); } } |