summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKjetil Orbekk <kj@orbekk.com>2023-01-07 16:23:56 -0500
committerKjetil Orbekk <kj@orbekk.com>2023-01-07 16:23:56 -0500
commit1f52e2e448b464e95530cab9e1b7d9177ada3279 (patch)
tree9290facc77bfb77b078e973e325f2e3d62216464
parent0f7dacea15d6e22123c3290c52515a772fc7ee92 (diff)
Add dealer and vulnerability to the Deal struct
-rw-r--r--protocol/src/bridge_engine.rs36
-rw-r--r--protocol/src/core.rs45
-rw-r--r--protocol/src/simple_bots.rs12
3 files changed, 65 insertions, 28 deletions
diff --git a/protocol/src/bridge_engine.rs b/protocol/src/bridge_engine.rs
index 73a8bf4..4b3d889 100644
--- a/protocol/src/bridge_engine.rs
+++ b/protocol/src/bridge_engine.rs
@@ -1,7 +1,7 @@
use crate::{
card::{Card, Suit},
move_result::MoveResult,
- core::{Player, Deal}, actions::Bid, contract::{LevelAndSuit, Contract, ContractModifier}
+ core::{Player, Deal, Vulnerability}, actions::Bid, contract::{LevelAndSuit, Contract, ContractModifier}
};
use anyhow::{anyhow, bail};
use log::info;
@@ -273,14 +273,12 @@ 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,
@@ -292,12 +290,10 @@ impl BiddingStatePlayerView {
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(),
@@ -329,7 +325,7 @@ impl PlayState {
}
pub fn dealer(&self) -> Player {
- self.bidding.dealer
+ self.deal.dealer
}
pub fn current_player(&self) -> Player {
@@ -347,6 +343,7 @@ impl PlayState {
}),
MoveResult::Next(tricks) => {
MoveResult::Next(PlayResult::Played(PlayedResult {
+ vulnerability: self.deal.vulnerability,
bidding: self.bidding,
contract: self.contract,
tricks,
@@ -370,6 +367,7 @@ impl PassedOutResult {
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
pub struct PlayedResult {
+ pub vulnerability: Vulnerability,
pub bidding: Bidding,
pub contract: Contract,
pub tricks: Vec<Trick>,
@@ -377,7 +375,7 @@ pub struct PlayedResult {
impl PlayedResult {
pub fn deal(&self) -> Cow<Deal> {
- let mut deal = Deal::empty();
+ let mut deal = Deal::empty(self.bidding.dealer, self.vulnerability);
let mut leader = self.contract.leader();
let trump_suit = self.contract.highest_bid.suit;
for trick in &self.tricks {
@@ -427,9 +425,9 @@ impl From<PlayState> for GameState {
}
impl GameState {
- pub fn new(deal: Deal, dealer: Player) -> Self {
+ pub fn new(deal: Deal) -> Self {
+ let dealer = deal.dealer;
Self::Bidding(BiddingState {
- dealer,
deal,
bidding: Bidding::new(dealer),
})
@@ -444,7 +442,7 @@ impl GameState {
pub fn dealer(&self) -> Player {
match self {
- Self::Bidding(BiddingState { dealer, .. }) => *dealer,
+ Self::Bidding(BiddingState { deal, .. }) => deal.dealer,
Self::Play(play_state) => play_state.dealer(),
}
}
@@ -483,14 +481,12 @@ impl GameState {
bid: Bid,
) -> Result<MoveResult<GameState, PlayResult>, anyhow::Error> {
let BiddingState {
- dealer,
deal,
bidding,
} = self.bidding()?.clone();
Ok(match bidding.bid(bid)? {
BiddingResult::InProgress(bidding) => {
MoveResult::Current(GameState::Bidding(BiddingState {
- dealer,
deal,
bidding,
}))
@@ -868,6 +864,8 @@ mod tests {
fn example_deal() -> Deal {
Deal {
+ dealer: Player::North,
+ vulnerability: Vulnerability::None,
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"),
@@ -877,6 +875,8 @@ mod tests {
fn mini_deal() -> Deal {
Deal {
+ dealer: Player::North,
+ vulnerability: Vulnerability::None,
west: mkcards("♢A ♡Q"),
north: mkcards("♢Q ♡9"),
east: mkcards("♢7 ♡K"),
@@ -905,7 +905,7 @@ mod tests {
#[test]
fn game_state() {
crate::tests::test_setup();
- let game_state = GameState::new(mini_deal(), Player::North);
+ let game_state = GameState::new(mini_deal());
assert_eq!(game_state.deal(), &mini_deal());
assert_eq!(game_state.dealer(), Player::North);
assert!(game_state.is_bidding());
@@ -935,18 +935,18 @@ mod tests {
#[test]
fn table_view() {
crate::tests::test_setup();
- let game_state = GameState::new(mini_deal(), Player::East);
+ let game_state = GameState::new(mini_deal());
info!("Game state: {game_state:?}");
for p in Player::iter() {
info!("Testing view for {p:?}");
let view = GameStatePlayerView::from_game_state(&game_state, p);
match view {
GameStatePlayerView::Bidding(BiddingStatePlayerView {
- dealer,
+ bidding,
hand,
..
}) => {
- assert_eq!(dealer, Player::East);
+ assert_eq!(bidding.dealer, Player::North);
assert_eq!(&hand, p.get_cards(&mini_deal()));
}
_ => panic!("expected bidding: {view:#?}"),
@@ -956,7 +956,7 @@ mod tests {
fn some_play_state() -> PlayState {
crate::tests::test_setup();
- let deal = random();
+ let deal: Deal = random();
let raise1c = LevelAndSuit {
level: ContractLevel::One,
suit: Some(Suit::Club),
@@ -967,7 +967,7 @@ mod tests {
modifier: ContractModifier::Doubled,
};
let bidding = Bidding {
- dealer: random(),
+ dealer: deal.dealer,
bids: vec![Bid::Raise(raise1c), Bid::Pass, Bid::Pass, Bid::Pass],
};
PlayState::new(deal, contract, bidding)
diff --git a/protocol/src/core.rs b/protocol/src/core.rs
index 7939fb2..7d055ac 100644
--- a/protocol/src/core.rs
+++ b/protocol/src/core.rs
@@ -1,9 +1,9 @@
-use rand::{prelude::Distribution, distributions::Standard, seq::SliceRandom};
+use rand::{distributions::Standard, prelude::Distribution, seq::SliceRandom, random};
+use serde::{Deserialize, Serialize};
use strum::EnumCount;
-use strum_macros::{EnumCount, FromRepr, EnumIter};
-use serde::{Serialize, Deserialize};
+use strum_macros::{EnumCount, EnumIter, FromRepr};
-use crate::card::{Card, Suit, RankOrder, sort_cards, make_deck};
+use crate::card::{make_deck, sort_cards, Card, RankOrder, Suit};
#[derive(
PartialEq,
@@ -71,8 +71,39 @@ impl Distribution<Player> for Standard {
}
}
+#[derive(
+ PartialEq,
+ Eq,
+ Clone,
+ Copy,
+ Debug,
+ FromRepr,
+ EnumCount,
+ Serialize,
+ Deserialize,
+ EnumIter,
+)]
+#[repr(u8)]
+pub enum Vulnerability {
+ None,
+ NorthSouth,
+ EastWest,
+ All,
+}
+
+impl Distribution<Vulnerability> for Standard {
+ fn sample<R: rand::Rng + ?Sized>(&self, rng: &mut R) -> Vulnerability {
+ let min = Vulnerability::None as u8;
+ let max = Vulnerability::All as u8;
+ let v = rng.gen_range(min..=max);
+ Vulnerability::from_repr(v).unwrap()
+ }
+}
+
#[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize)]
pub struct Deal {
+ pub dealer: Player,
+ pub vulnerability: Vulnerability,
pub north: Vec<Card>,
pub west: Vec<Card>,
pub south: Vec<Card>,
@@ -80,8 +111,10 @@ pub struct Deal {
}
impl Deal {
- pub fn empty() -> Self {
+ pub fn empty(dealer: Player, vulnerability: Vulnerability) -> Self {
Self {
+ dealer,
+ vulnerability,
north: Vec::with_capacity(13),
west: Vec::with_capacity(13),
south: Vec::with_capacity(13),
@@ -107,6 +140,8 @@ impl Distribution<Deal> for Standard {
let south = deck.by_ref().take(13).cloned().collect();
let east = deck.by_ref().take(13).cloned().collect();
Deal {
+ dealer: random(),
+ vulnerability: random(),
north,
west,
south,
diff --git a/protocol/src/simple_bots.rs b/protocol/src/simple_bots.rs
index 3df50fb..ce2fdec 100644
--- a/protocol/src/simple_bots.rs
+++ b/protocol/src/simple_bots.rs
@@ -50,7 +50,7 @@ mod tests {
bridge_engine::SUIT_DISPLAY_ORDER,
card::RankOrder,
contract::{Contract, ContractLevel, ContractModifier, LevelAndSuit},
- core::{Deal, Player},
+ core::{Deal, Player, Vulnerability},
move_result::MoveResult,
};
use std::str::FromStr;
@@ -115,6 +115,8 @@ mod tests {
fn example_deal() -> Deal {
Deal {
+ dealer: Player::North,
+ vulnerability: Vulnerability::None,
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"),
@@ -134,7 +136,7 @@ mod tests {
modifier: ContractModifier::Doubled,
};
let bidding = Bidding {
- dealer: random(),
+ dealer: deal.dealer,
bids: vec![Bid::Raise(raise1c), Bid::Pass, Bid::Pass, Bid::Pass],
};
PlayState::new(deal, contract, bidding)
@@ -143,11 +145,11 @@ mod tests {
#[tokio::test]
async fn always_passing_bot_passes() {
crate::tests::test_setup();
- let dealer = random();
+ let deal: Deal = random();
+ let dealer = deal.dealer;
let player_position = random();
let bidding_state = BiddingState {
- dealer,
- deal: random(),
+ deal,
bidding: Bidding::new(dealer),
};
let player_view = BiddingStatePlayerView::from_bidding_state(