summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKjetil Orbekk <kj@orbekk.com>2022-12-30 10:27:10 -0500
committerKjetil Orbekk <kj@orbekk.com>2022-12-30 10:27:10 -0500
commitdbe316d8b337eadff5518585dfc163f2724d0810 (patch)
tree6e2d772c7e4db77671cadb7ae240b6a44105b883
parent83ffcc667999879197508aba0d1f910ca7cb000b (diff)
Utility method to reconstruct Deal from tricks played
-rw-r--r--protocol/src/bridge_engine.rs45
-rw-r--r--protocol/src/simple_bots.rs14
2 files changed, 56 insertions, 3 deletions
diff --git a/protocol/src/bridge_engine.rs b/protocol/src/bridge_engine.rs
index 708d9ae..75a51ba 100644
--- a/protocol/src/bridge_engine.rs
+++ b/protocol/src/bridge_engine.rs
@@ -10,7 +10,7 @@ use rand::{
};
use regex::Regex;
use serde::{Deserialize, Serialize};
-use std::cmp::Ordering;
+use std::{cmp::Ordering, borrow::Cow};
use std::fmt;
use std::str::FromStr;
use strum::{EnumCount, IntoEnumIterator};
@@ -682,6 +682,7 @@ impl PlayState {
MoveResult::Next(tricks) => {
MoveResult::Next(PlayResult::Played(PlayedResult {
bidding: self.bidding,
+ contract: self.contract,
tricks,
}))
}
@@ -695,18 +696,51 @@ pub struct PassedOutResult {
pub bidding: Bidding,
}
+impl PassedOutResult {
+ pub fn deal(&self) -> Cow<Deal> {
+ Cow::Borrowed(&self.deal)
+ }
+}
+
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
pub struct PlayedResult {
pub bidding: Bidding,
+ pub contract: Contract,
pub tricks: Vec<Trick>,
}
+impl PlayedResult {
+ pub fn deal(&self) -> Cow<Deal> {
+ let mut deal = Deal::empty();
+ let mut leader = self.contract.leader();
+ let trump_suit = self.contract.highest_bid.suit;
+ for trick in &self.tricks {
+ let mut player = leader;
+ for card in &trick.cards_played {
+ player.get_cards_mut(&mut deal).push(*card);
+ player = player.next();
+ }
+ leader = trick.winner(trump_suit);
+ }
+ Cow::Owned(deal)
+ }
+}
+
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
pub enum PlayResult {
PassedOut(PassedOutResult),
Played(PlayedResult),
}
+impl PlayResult {
+ pub fn deal(&self) -> Cow<Deal> {
+ match self {
+ PlayResult::PassedOut(r) => r.deal(),
+ PlayResult::Played(r) => r.deal(),
+ }
+ }
+}
+
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
pub enum GameState {
Bidding(BiddingState),
@@ -824,6 +858,15 @@ pub struct Deal {
}
impl Deal {
+ pub fn empty() -> Self {
+ Self {
+ north: Vec::with_capacity(13),
+ west: Vec::with_capacity(13),
+ south: Vec::with_capacity(13),
+ east: Vec::with_capacity(13),
+ }
+ }
+
pub fn sort(&mut self, suits: &[Suit; 4], ord: RankOrder) {
sort_cards(suits, ord, self.north.as_mut_slice());
sort_cards(suits, ord, self.west.as_mut_slice());
diff --git a/protocol/src/simple_bots.rs b/protocol/src/simple_bots.rs
index 45d1a5b..182229f 100644
--- a/protocol/src/simple_bots.rs
+++ b/protocol/src/simple_bots.rs
@@ -46,7 +46,7 @@ impl PlayingBot for RandomPlayingBot {
#[cfg(test)]
mod tests {
use std::str::FromStr;
- use crate::move_result::MoveResult;
+ use crate::{move_result::MoveResult, bridge_engine::SUIT_DISPLAY_ORDER, card::RankOrder};
use super::*;
use crate::{
@@ -159,7 +159,9 @@ mod tests {
async fn play_until_completion() {
crate::tests::test_setup();
let bot = RandomPlayingBot {};
- let mut result = MoveResult::Current(example_play_state());
+ let play_state = example_play_state();
+ let mut deal = play_state.deal.clone();
+ let mut result = MoveResult::Current(play_state);
while let MoveResult::Current(play_state) = result {
info!("Play state: {play_state:#?}");
let player_state = PlayStatePlayerView::from_play_state(
@@ -169,5 +171,13 @@ mod tests {
let card = bot.play(&player_state).await;
result = play_state.play(card).unwrap();
}
+ let play_result = result.next().unwrap();
+
+ // Verify that the deal is intact.
+ deal.sort(&SUIT_DISPLAY_ORDER, RankOrder::Descending);
+ let mut result_deal = play_result.deal().into_owned();
+ result_deal.sort(&SUIT_DISPLAY_ORDER, RankOrder::Descending);
+
+ assert_eq!(result_deal, deal);
}
}