diff options
author | Kjetil Orbekk <kj@orbekk.com> | 2022-11-27 16:45:07 -0500 |
---|---|---|
committer | Kjetil Orbekk <kj@orbekk.com> | 2022-11-27 17:23:11 -0500 |
commit | d8de16a7187d2a05fd043946cf4cb32449a5aa3b (patch) | |
tree | 6c1a212232203dbb6a9da48c192e10bef5d3b932 /protocol/src/bridge_engine.rs | |
parent | 854f247b6b7bf1106f31d7f23a326c0904d4f87e (diff) |
Add basic bot trait for bot bidding
Diffstat (limited to 'protocol/src/bridge_engine.rs')
-rw-r--r-- | protocol/src/bridge_engine.rs | 151 |
1 files changed, 95 insertions, 56 deletions
diff --git a/protocol/src/bridge_engine.rs b/protocol/src/bridge_engine.rs index 5c7ce4d..6b3cf7d 100644 --- a/protocol/src/bridge_engine.rs +++ b/protocol/src/bridge_engine.rs @@ -1,6 +1,7 @@ use crate::card::{Card, Deal, RankOrder, Suit}; use anyhow::{anyhow, bail}; use log::{error, info}; +use rand::{prelude::Distribution, distributions::Standard}; use regex::Regex; use serde::{Deserialize, Serialize}; use std::cmp::Ordering; @@ -59,6 +60,15 @@ impl Player { } } +impl Distribution<Player> for Standard { + fn sample<R: rand::Rng + ?Sized>(&self, rng: &mut R) -> Player { + let min = Player::West as u8; + let max = Player::South as u8; + let v = rng.gen_range(min..=max); + Player::from_repr(v).unwrap() + } +} + #[derive(PartialEq, Eq, Debug, Clone, Serialize, Deserialize)] pub struct Trick { pub leader: Player, @@ -484,47 +494,78 @@ impl BiddingResult { } #[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] +pub struct BiddingState { + pub dealer: Player, + pub deal: Deal, + pub bidding: Bidding, +} + +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] +pub struct BiddingStatePlayerView { + pub dealer: Player, + pub player_position: Player, + pub hand: Vec<Card>, + pub bidding: Bidding, +} + +impl BiddingStatePlayerView { + pub fn from_bidding_state(bidding_state: &BiddingState, player_position: Player) -> Self { + let BiddingState { + dealer, + deal, + bidding, + } = bidding_state; + Self { + dealer: *dealer, + player_position, + hand: player_position.get_cards(deal).clone(), + bidding: bidding.clone(), + } + } +} + +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] +pub struct PlayState { + dealer: Player, + deal: Deal, + contract: Contract, + bidding: Bidding, + playing_deal: DealInPlay, +} + +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] pub enum GameState { - Bidding { - dealer: Player, - deal: Deal, - bidding: Bidding, - }, + Bidding(BiddingState), + Play(PlayState), PassedOut { dealer: Player, deal: Deal, bidding: Bidding, }, - Play { - dealer: Player, - playing_deal: DealInPlay, - contract: Contract, - bidding: Bidding, - }, } impl GameState { pub fn new(deal: Deal, dealer: Player) -> Self { - Self::Bidding { + Self::Bidding(BiddingState { dealer, deal, bidding: Bidding::new(dealer), - } + }) } pub fn deal(&self) -> &Deal { match self { - Self::Bidding { deal, .. } => deal, + Self::Bidding(BiddingState { deal, .. }) => deal, Self::PassedOut { deal, .. } => deal, - Self::Play { playing_deal, .. } => &playing_deal.deal(), + Self::Play(PlayState { playing_deal, .. }) => &playing_deal.deal(), } } pub fn dealer(&self) -> Player { match *self { - Self::Bidding { dealer, .. } => dealer, + Self::Bidding(BiddingState { dealer, .. }) => dealer, Self::PassedOut { dealer, .. } => dealer, - Self::Play { dealer, .. } => dealer, + Self::Play(PlayState { dealer, .. }) => dealer, } } @@ -546,30 +587,31 @@ impl GameState { pub fn bid(self, bid: Bid) -> Result<Self, anyhow::Error> { let (dealer, deal, bidding) = match self { - GameState::Bidding { + GameState::Bidding(BiddingState { dealer, deal, bidding, - } => (dealer, deal, bidding), + }) => (dealer, deal, bidding), _ => bail!("not currently bidding: {self:?}"), }; Ok(match bidding.bid(bid)? { - BiddingResult::InProgress(bidding) => GameState::Bidding { + BiddingResult::InProgress(bidding) => GameState::Bidding(BiddingState { dealer, deal, bidding, - }, + }), BiddingResult::Contract(None, bidding) => GameState::PassedOut { dealer, deal, bidding, }, - BiddingResult::Contract(Some(contract), bidding) => GameState::Play { + BiddingResult::Contract(Some(contract), bidding) => GameState::Play(PlayState { + deal: deal.clone(), dealer, playing_deal: DealInPlay::new(contract.declarer, deal), contract, bidding, - }, + }), }) } } @@ -583,12 +625,7 @@ pub fn deal() -> Deal { #[derive(Serialize, Deserialize, PartialEq, Eq, Clone, Debug)] pub enum GameStatePlayerView { - Bidding { - dealer: Player, - player_position: Player, - hand: Vec<Card>, - bidding: Bidding, - }, + Bidding(BiddingStatePlayerView), PassedOut { dealer: Player, player_position: Player, @@ -614,33 +651,17 @@ pub enum GameStatePlayerView { impl GameStatePlayerView { pub fn from_game_state(game_state: &GameState, player_position: Player) -> Self { match game_state { - GameState::Bidding { - dealer, - deal, - bidding, - } => GameStatePlayerView::Bidding { - dealer: *dealer, - player_position, - bidding: bidding.clone(), - hand: player_position.get_cards(deal).clone(), - }, - GameState::PassedOut { - dealer, - deal, - bidding, - } => todo!(), - GameState::Play { - dealer, - playing_deal, - contract, - bidding, - } => todo!(), + GameState::Bidding(bidding_state) => GameStatePlayerView::Bidding( + BiddingStatePlayerView::from_bidding_state(bidding_state, player_position), + ), + GameState::PassedOut { .. } => todo!(), + GameState::Play { .. } => todo!(), } } pub fn hand(&self) -> &Vec<Card> { match self { - GameStatePlayerView::Bidding { hand, .. } => hand, + GameStatePlayerView::Bidding(BiddingStatePlayerView { hand, .. }) => hand, GameStatePlayerView::PassedOut { deal, player_position, @@ -840,10 +861,10 @@ mod tests { fn example_deal() -> Deal { Deal { - west: mkcards("♠5 ♦10 ♥K ♣4 ♥J ♣5 ♦5 ♠9 ♦3 ♠2 ♣2 ♥4 ♠Q"), - north: mkcards("♦Q ♥9 ♠7 ♠8 ♠A ♥A ♥5 ♠6 ♦9 ♣3 ♥3 ♣9 ♦J"), - east: mkcards("♣10 ♥7 A ♣6 ♥8 ♣Q ♠K ♥10 ♣K ♠3 ♥Q ♣J ♦4"), - south: mkcards("♦K ♥6 ♣8 ♦6 ♦7 ♦8 ♣A ♥2 ♣7 ♠10 ♠4 ♠J ♦2"), + west: mkcards("♠Q ♠9 ♠5 ♠2 ♥K ♥J ♥4 ♣5 ♣4 ♣2 ♦10 ♦5 ♦3"), + north: mkcards("♠A ♠8 ♠7 ♠6 ♥A ♥9 ♥5 ♥3 ♣9 ♣3 ♦Q ♦J ♦9"), + east: mkcards("♠K ♠3 ♥Q ♥10 ♥8 ♥7 ♣K ♣Q ♣J ♣10 ♣6 ♦A ♦4"), + south: mkcards("♠J ♠10 ♠4 ♥6 ♥2 ♣A ♣8 ♣7 ♦K ♦8 ♦7 ♦6 ♦2"), } } @@ -857,6 +878,24 @@ mod tests { } #[test] + fn example_deal_is_sorted() { + crate::tests::test_setup(); + let mut sorted = example_deal(); + sorted.sort(&SUIT_DISPLAY_ORDER, RankOrder::Descending); + let pp = |hand: &[Card]| { + hand.iter() + .map(|c| format!("{}", c)) + .collect::<Vec<_>>() + .join(" ") + }; + info!("{}", pp(&sorted.west)); + info!("{}", pp(&sorted.north)); + info!("{}", pp(&sorted.east)); + info!("{}", pp(&sorted.south)); + assert_eq!(example_deal(), sorted); + } + + #[test] fn game_state() { crate::tests::test_setup(); let game_state = GameState::new(mini_deal(), Player::North); @@ -889,7 +928,7 @@ mod tests { info!("Testing view for {p:?}"); let view = GameStatePlayerView::from_game_state(&game_state, p); match view { - GameStatePlayerView::Bidding { dealer, hand, .. } => { + GameStatePlayerView::Bidding(BiddingStatePlayerView { dealer, hand, .. }) => { assert_eq!(dealer, Player::East); assert_eq!(&hand, p.get_cards(&mini_deal())); } |