summaryrefslogtreecommitdiff
path: root/server
diff options
context:
space:
mode:
authorKjetil Orbekk <kj@orbekk.com>2022-12-21 08:10:38 -0500
committerKjetil Orbekk <kj@orbekk.com>2022-12-21 08:10:38 -0500
commit10ecb9e30568bf20287b053a620252d7a80dbd6b (patch)
treec6a82f7cb4d24071234a1429dbb91815709052be /server
parent27f74d8c366be675e7ab64ca746496a66b3cf024 (diff)
Add struct for the player view of a hand in play
Diffstat (limited to 'server')
-rw-r--r--server/src/play.rs116
1 files changed, 87 insertions, 29 deletions
diff --git a/server/src/play.rs b/server/src/play.rs
index 79d241c..86a4e06 100644
--- a/server/src/play.rs
+++ b/server/src/play.rs
@@ -1,5 +1,9 @@
use async_trait::async_trait;
-use protocol::{bridge_engine::{GameState, Player, Bid, Deal, BiddingStatePlayerView}, simple_bots::AlwaysPassBiddingBot, bot::BiddingBot};
+use protocol::{
+ bot::BiddingBot,
+ bridge_engine::{Bid, BiddingStatePlayerView, Deal, GameState, Player},
+ simple_bots::AlwaysPassBiddingBot,
+};
use rand::random;
use serde::{Deserialize, Serialize};
use serde_json::json;
@@ -15,16 +19,23 @@ pub trait Journal {
fn next(&self) -> i64;
// Append payload to the journal at sequence number `seq`.
- async fn append(&mut self, seq: i64, payload: serde_json::Value) -> Result<(), BridgeError>;
+ async fn append(
+ &mut self,
+ seq: i64,
+ payload: serde_json::Value,
+ ) -> Result<(), BridgeError>;
// Fetch all journal entries with sequence number greater or equal to `seq`.
- async fn replay(&mut self, seq: i64) -> Result<Vec<serde_json::Value>, BridgeError>;
+ async fn replay(
+ &mut self,
+ seq: i64,
+ ) -> Result<Vec<serde_json::Value>, BridgeError>;
}
pub struct DbJournal {
db: PgPool,
id: Uuid,
- seq: i64
+ seq: i64,
}
impl DbJournal {
@@ -35,7 +46,11 @@ impl DbJournal {
#[async_trait]
impl Journal for DbJournal {
- async fn append(&mut self, seq: i64, payload: serde_json::Value) -> Result<(), BridgeError> {
+ async fn append(
+ &mut self,
+ seq: i64,
+ payload: serde_json::Value,
+ ) -> Result<(), BridgeError> {
let result = query!(
r#"
insert into object_journal (id, seq, payload)
@@ -46,18 +61,24 @@ impl Journal for DbJournal {
payload,
)
.execute(&self.db)
- .await;
+ .await;
if let Err(sqlx::Error::Database(e)) = result {
if e.constraint() == Some("journal_entry") {
- return Err(BridgeError::JournalConflict(format!("{}", self.id), seq));
+ return Err(BridgeError::JournalConflict(
+ format!("{}", self.id),
+ seq,
+ ));
}
}
self.seq += 1;
Ok(())
}
- async fn replay(&mut self, seq: i64) -> Result<Vec<serde_json::Value>, BridgeError> {
- let rows =query!(
+ async fn replay(
+ &mut self,
+ seq: i64,
+ ) -> Result<Vec<serde_json::Value>, BridgeError> {
+ let rows = query!(
r#"
select seq, payload from object_journal
where id = $1 and seq >= $2
@@ -67,8 +88,8 @@ impl Journal for DbJournal {
seq
)
.fetch_all(&self.db)
- .await?;
- let mut payloads = vec!();
+ .await?;
+ let mut payloads = vec![];
for v in rows {
payloads.push(v.payload);
self.seq = v.seq;
@@ -106,13 +127,19 @@ where
}
impl<J: Journal> Table<J> {
- pub fn game(&self) -> &GameState { &self.game }
+ pub fn game(&self) -> &GameState {
+ &self.game
+ }
}
impl<J: Journal> Table<J> {
pub async fn new(mut journal: J) -> Result<Self, BridgeError> {
let game = Self::init(&mut journal).await?;
- Ok(Table { journal, game, settings: Default::default() })
+ Ok(Table {
+ journal,
+ game,
+ settings: Default::default(),
+ })
}
async fn init(journal: &mut J) -> Result<GameState, BridgeError> {
@@ -123,7 +150,9 @@ impl<J: Journal> Table<J> {
pub async fn bid(&mut self, bid: Bid) -> Result<(), BridgeError> {
let game = self.game.clone().bid(bid)?;
- self.journal.append(self.journal.next(), json!(game)).await?;
+ self.journal
+ .append(self.journal.next(), json!(game))
+ .await?;
self.game = game;
Ok(())
}
@@ -131,10 +160,16 @@ impl<J: Journal> Table<J> {
pub async fn replay(mut journal: J) -> Result<Self, BridgeError> {
let games = journal.replay(0).await?;
if games.is_empty() {
- return Err(BridgeError::NotFound("table journal missing".to_string()));
+ return Err(BridgeError::NotFound(
+ "table journal missing".to_string(),
+ ));
}
let game = serde_json::from_value(games[games.len() - 1].clone())?;
- Ok(Table { journal, game, settings: Default::default() } )
+ Ok(Table {
+ journal,
+ game,
+ settings: Default::default(),
+ })
}
pub async fn new_or_replay(mut journal: J) -> Result<Self, BridgeError> {
@@ -142,29 +177,43 @@ impl<J: Journal> Table<J> {
if let Err(BridgeError::JournalConflict(..)) = game {
return Self::replay(journal).await;
}
- Ok(Self { journal, game: game?, settings: Default::default() } )
+ Ok(Self {
+ journal,
+ game: game?,
+ settings: Default::default(),
+ })
}
}
-
-pub async fn advance_play<J: Journal>(table: &mut Table<J>) -> Result<(), BridgeError> {
+pub async fn advance_play<J: Journal>(
+ table: &mut Table<J>,
+) -> Result<(), BridgeError> {
let current_player = match table.game().current_player() {
Some(player) => player,
None => {
info!("Could not make play. Game: {:#?}", table.game());
- return Err(BridgeError::InvalidRequest(format!("No play to make for game")));
- },
+ return Err(BridgeError::InvalidRequest(format!(
+ "No play to make for game"
+ )));
+ }
};
match table.game() {
GameState::Bidding(bidding) => {
- let player_view = BiddingStatePlayerView::from_bidding_state(bidding, current_player);
+ let player_view = BiddingStatePlayerView::from_bidding_state(
+ bidding,
+ current_player,
+ );
let bot = AlwaysPassBiddingBot {};
let bid = bot.bid(&player_view).await;
table.bid(bid).await?;
Ok(())
- },
+ }
GameState::Play(_) => todo!(),
- GameState::PassedOut { dealer, deal, bidding } => todo!(),
+ GameState::PassedOut {
+ dealer,
+ deal,
+ bidding,
+ } => Err(BridgeError::InvalidRequest(format!("The game is over"))),
}
}
@@ -185,13 +234,19 @@ mod test {
payload: serde_json::Value,
) -> Result<(), BridgeError> {
if seq != self.log.len() as i64 {
- return Err(BridgeError::UpdateConflict(self.log.len() as i64, seq));
+ return Err(BridgeError::UpdateConflict(
+ self.log.len() as i64,
+ seq,
+ ));
}
self.log.push(Some(payload));
Ok(())
}
- async fn replay(&mut self, seq: i64) -> Result<Vec<serde_json::Value>, BridgeError> {
+ async fn replay(
+ &mut self,
+ seq: i64,
+ ) -> Result<Vec<serde_json::Value>, BridgeError> {
Ok(self.log[seq as usize..]
.into_iter()
.filter_map(|e| e.clone())
@@ -218,7 +273,8 @@ mod test {
#[tokio::test]
async fn test_new_table() {
- let t1: Table<TestJournal> = Table::new(Default::default()).await.unwrap();
+ let t1: Table<TestJournal> =
+ Table::new(Default::default()).await.unwrap();
match t1.game {
GameState::Bidding { .. } => (),
_ => panic!("should be Bidding"),
@@ -227,7 +283,8 @@ mod test {
#[tokio::test]
async fn test_replay_table() {
- let t1: Table<TestJournal> = Table::new(Default::default()).await.unwrap();
+ let t1: Table<TestJournal> =
+ Table::new(Default::default()).await.unwrap();
let game = t1.game;
let journal = t1.journal;
@@ -237,7 +294,8 @@ mod test {
#[tokio::test]
async fn test_advance_play() {
- let mut t1: Table<TestJournal> = Table::new(Default::default()).await.unwrap();
+ let mut t1: Table<TestJournal> =
+ Table::new(Default::default()).await.unwrap();
let player = t1.game().current_player();
advance_play(&mut t1).await.unwrap();
assert_ne!(player, t1.game().current_player());