summaryrefslogtreecommitdiff
path: root/protocol/src/bridge_engine.rs
diff options
context:
space:
mode:
authorKjetil Orbekk <kj@orbekk.com>2022-12-22 08:31:35 -0500
committerKjetil Orbekk <kj@orbekk.com>2022-12-22 08:31:35 -0500
commit42f6ef6d44e893b47e5e2a49496b5dd2122df232 (patch)
treedff2f84bbc41295b27deb2397071cb16bb742058 /protocol/src/bridge_engine.rs
parent10ecb9e30568bf20287b053a620252d7a80dbd6b (diff)
Add a simple bot that plays random (legal) cards
- Leads random cards - Follows suit if possible
Diffstat (limited to 'protocol/src/bridge_engine.rs')
-rw-r--r--protocol/src/bridge_engine.rs97
1 files changed, 73 insertions, 24 deletions
diff --git a/protocol/src/bridge_engine.rs b/protocol/src/bridge_engine.rs
index 50f619b..35eb90f 100644
--- a/protocol/src/bridge_engine.rs
+++ b/protocol/src/bridge_engine.rs
@@ -3,7 +3,8 @@ use anyhow::{anyhow, bail};
use log::{error, info};
use rand::{
distributions::Standard,
- prelude::{Distribution, SliceRandom}, random,
+ prelude::{Distribution, SliceRandom},
+ random,
};
use regex::Regex;
use serde::{Deserialize, Serialize};
@@ -140,7 +141,7 @@ impl TurnInPlay {
TurnInPlayResult::InProgress(self)
}
- pub fn next_player(&self) -> Player {
+ pub fn current_player(&self) -> Player {
self.trick.leader.many_next(self.trick.cards_played.len())
}
}
@@ -179,11 +180,15 @@ impl DealInPlay {
&self.deal
}
+ pub fn current_player(&self) -> Player {
+ self.in_progress.current_player()
+ }
+
pub fn play(
mut self: Self,
card: Card,
) -> Result<DealInPlayResult, anyhow::Error> {
- let player = self.in_progress.next_player();
+ let player = self.current_player();
let player_cards = player.get_cards_mut(&mut self.deal);
info!(
@@ -604,8 +609,8 @@ 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), deal.clone());
Self {
deal,
contract,
@@ -617,6 +622,36 @@ impl PlayState {
pub fn dealer(&self) -> Player {
self.bidding.dealer
}
+
+ pub fn current_player(&self) -> Player {
+ self.playing_deal.current_player()
+ }
+
+ pub fn play(
+ mut self,
+ card: Card,
+ ) -> Result<PlayStateResult, anyhow::Error> {
+ Ok(match self.playing_deal.play(card)? {
+ DealInPlayResult::InProgress(playing_deal) => {
+ PlayStateResult::InProgress(Self {
+ playing_deal,
+ ..self
+ })
+ }
+ DealInPlayResult::PlayFinished(_) => {
+ PlayStateResult::PlayFinished(PlayResult)
+ }
+ })
+ }
+}
+
+#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
+pub struct PlayResult;
+
+#[derive(Debug)]
+pub enum PlayStateResult {
+ InProgress(PlayState),
+ PlayFinished(PlayResult),
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
@@ -708,8 +743,7 @@ impl GameState {
bidding,
},
BiddingResult::Contract(Some(contract), bidding) => {
- GameState::Play(
- PlayState::new(deal, contract, bidding))
+ GameState::Play(PlayState::new(deal, contract, bidding))
}
})
}
@@ -752,15 +786,15 @@ impl Distribution<Deal> for Standard {
#[derive(Serialize, Deserialize, PartialEq, Eq, Clone, Debug)]
pub struct PlayStatePlayerView {
- player_position: Player,
- bidding: Bidding,
- contract: Contract,
+ pub player_position: Player,
+ pub bidding: Bidding,
+ pub contract: Contract,
// If None, the lead has not been played.
- dummy: Option<Vec<Card>>,
- declarer_tricks: u8,
- hand: Vec<Card>,
- previous_trick: Trick,
- current_trick: TurnInPlay,
+ pub dummy: Option<Vec<Card>>,
+ pub declarer_tricks: u8,
+ pub hand: Vec<Card>,
+ pub previous_trick: Trick,
+ pub current_trick: TurnInPlay,
}
impl PlayStatePlayerView {
@@ -774,11 +808,22 @@ impl PlayStatePlayerView {
contract: play_state.contract,
dummy: None,
declarer_tricks: 0,
- hand: vec!(),
- previous_trick: Trick { leader: random(), cards_played: vec!() },
- current_trick: TurnInPlay::new(random()),
+ hand: player_position.get_cards(&play_state.deal).clone(),
+ previous_trick: Trick {
+ leader: random(),
+ cards_played: vec![],
+ },
+ current_trick: play_state.playing_deal.in_progress.clone(),
}
}
+
+ pub fn dealer(&self) -> Player {
+ self.bidding.dealer
+ }
+
+ pub fn current_player(&self) -> Player {
+ self.current_trick.current_player()
+ }
}
#[derive(Serialize, Deserialize, PartialEq, Eq, Clone, Debug)]
@@ -1001,13 +1046,13 @@ mod tests {
#[test]
fn play_turn() {
let turn = TurnInPlay::new(Player::South);
- assert_eq!(turn.next_player(), Player::South);
+ assert_eq!(turn.current_player(), Player::South);
let turn = as_turn(turn.play("♣4".parse().unwrap()));
- assert_eq!(turn.next_player(), Player::West);
+ assert_eq!(turn.current_player(), Player::West);
let turn = as_turn(turn.play("♥A".parse().unwrap()));
- assert_eq!(turn.next_player(), Player::North);
+ assert_eq!(turn.current_player(), Player::North);
let turn = as_turn(turn.play("♣4".parse().unwrap()));
- assert_eq!(turn.next_player(), Player::East);
+ assert_eq!(turn.current_player(), Player::East);
let trick = as_trick(turn.play("♣A".parse().unwrap()));
assert_eq!(
trick,
@@ -1147,8 +1192,12 @@ mod tests {
fn play_state_player_view() {
crate::tests::test_setup();
let play_state = some_play_state();
- let player_deal =
- PlayStatePlayerView::from_play_state(&play_state, random());
+ let player = random();
+ let player_state =
+ PlayStatePlayerView::from_play_state(&play_state, player);
+ assert_eq!(play_state.dealer(), player_state.dealer());
+ assert_eq!(player_state.player_position, player);
+ assert_eq!(player_state.current_player(), play_state.current_player());
}
fn as_playing_hand(result: DealInPlayResult) -> DealInPlay {