summaryrefslogtreecommitdiff
path: root/server/src/table.rs
blob: cc00327142833b36689ead28458135491f154cb6 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
use async_trait::async_trait;
use protocol::{
    bot::{BiddingBot, PlayingBot},
    bridge_engine::{
        BiddingStatePlayerView, GameState, PlayStatePlayerView, TableState,
    },
    card::Card,
    simple_bots::{AlwaysPassBiddingBot, RandomPlayingBot}, actions::Bid,
};
use rand::random;

use crate::error::BridgeError;

#[async_trait]
pub trait Table {
    fn state(&self) -> &TableState;
    async fn bid(
        self: Box<Self>,
        bid: Bid,
    ) -> Result<Box<dyn Table>, BridgeError>;
    async fn play(
        self: Box<Self>,
        card: Card,
    ) -> Result<Box<dyn Table>, BridgeError>;
    async fn new_deal(self: Box<Self>) -> Result<Box<dyn Table>, BridgeError>;
}

pub struct InMemoryTable {
    pub state: TableState,
}

impl InMemoryTable {
    pub fn new() -> Self {
        Self {
            state: TableState::Unknown,
        }
    }
}

#[async_trait]
impl Table for InMemoryTable {
    fn state(&self) -> &TableState {
        &self.state
    }

    async fn bid(
        self: Box<Self>,
        bid: Bid,
    ) -> Result<Box<dyn Table>, BridgeError> {
        let game = match self.state {
            TableState::Game(game) => game,
            _ => {
                return Err(BridgeError::InvalidRequest("no game".to_string()))
            }
        };
        let game = game.bid(bid)?;
        Ok(Box::new(Self { state: game.into() }))
    }

    async fn play(
        self: Box<Self>,
        card: Card,
    ) -> Result<Box<dyn Table>, BridgeError> {
        let game = match self.state {
            TableState::Game(game) => game,
            _ => {
                return Err(BridgeError::InvalidRequest("no game".to_string()))
            }
        };
        let game = game.play(card)?;
        Ok(Box::new(Self { state: game.into() }))
    }

    async fn new_deal(self: Box<Self>) -> Result<Box<dyn Table>, BridgeError> {
        Ok(Box::new(Self {
            state: GameState::new(random(), random()).into(),
        }))
    }
}

pub async fn advance_play(
    table: Box<dyn Table>,
) -> Result<Box<dyn Table>, BridgeError> {
    let game = match table.state() {
        TableState::Game(game) => game,
        _ => return Err(BridgeError::InvalidRequest("no game".to_string())),
    };
    let table = match game {
        GameState::Bidding(ref bidding) => {
            let player_view = BiddingStatePlayerView::from_bidding_state(
                &bidding,
                game.current_player(),
            );
            let bot = AlwaysPassBiddingBot {};
            let bid = bot.bid(&player_view).await;
            table.bid(bid).await
        }
        GameState::Play(game) => {
            let player_view = PlayStatePlayerView::from_play_state(
                &game,
                game.current_player(),
            );
            let bot = RandomPlayingBot {};
            let card = bot.play(&player_view).await;
            table.play(card).await
        }
    };
    table
}

// pub struct DbTable
// {
//     db: PgPool,
//     pub state: TableState,
// }