summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKjetil Orbekk <kj@orbekk.com>2022-09-17 19:52:01 -0400
committerKjetil Orbekk <kj@orbekk.com>2022-09-17 19:52:01 -0400
commitcad8f84e88c1816fb4f852a1aea3c98026627c70 (patch)
tree93edbe7068ba805679beb2130127de9d6755e436
parent435272c941d6cb8e7e18312cac16e319b16e8f50 (diff)
Add state machine for gameplay
-rw-r--r--webapp/src/card.rs2
-rw-r--r--webapp/src/components/game.rs123
-rw-r--r--webapp/src/components/hand.rs2
3 files changed, 84 insertions, 43 deletions
diff --git a/webapp/src/card.rs b/webapp/src/card.rs
index 58e322d..621bae1 100644
--- a/webapp/src/card.rs
+++ b/webapp/src/card.rs
@@ -240,7 +240,7 @@ mod tests {
}
}
-#[derive(Debug, PartialEq, Eq)]
+#[derive(Debug, PartialEq, Eq, Clone)]
pub struct Deal {
pub north: Vec<Card>,
pub west: Vec<Card>,
diff --git a/webapp/src/components/game.rs b/webapp/src/components/game.rs
index d6341ac..21b0966 100644
--- a/webapp/src/components/game.rs
+++ b/webapp/src/components/game.rs
@@ -1,5 +1,6 @@
use crate::bridge_engine::{self, Contract, Player};
use crate::card;
+use crate::card::Deal;
use crate::card::Suit;
use crate::components::{Bidding, Hand, ShowBid};
use log::info;
@@ -13,6 +14,35 @@ enum Phase {
Cardplay,
}
+#[derive(Debug)]
+enum GameState {
+ Bidding {
+ dealer: Player,
+ deal: Deal,
+ },
+ PassedOut {
+ dealer: Player,
+ deal: Deal,
+ bidding: bridge_engine::Bidding,
+ },
+ Play {
+ dealer: Player,
+ deal: Deal,
+ contract: Contract,
+ bidding: bridge_engine::Bidding,
+ },
+}
+
+impl GameState {
+ fn deal(&self) -> &Deal {
+ match self {
+ Self::Bidding { deal, .. } => deal,
+ Self::PassedOut { deal, .. } => deal,
+ Self::Play { deal, .. } => deal,
+ }
+ }
+}
+
pub fn deal() -> card::Deal {
let mut rng = rand::thread_rng();
let mut deal = card::deal(&mut rng);
@@ -20,78 +50,89 @@ pub fn deal() -> card::Deal {
deal
}
+fn init_state() -> GameState {
+ let dealer = Player::East;
+ let deal = deal();
+ GameState::Bidding { dealer, deal }
+}
+
#[function_component(Game)]
pub fn game() -> Html {
- let dealt_cards = use_state(|| deal());
-
- // let north = use_state(|| HandProps::from_iter(deal.north.into_iter()));
- // let west = use_state(|| HandProps::from_iter(deal.west.into_iter()));
- // let south = use_state(|| HandProps::from_iter(deal.south.into_iter()));
- // let east = use_state(|| HandProps::from_iter(deal.east.into_iter()));
-
- let dealer = use_state(|| Player::East);
-
- let contract: UseStateHandle<Option<(Option<Contract>, bridge_engine::Bidding)>> =
- use_state(|| None);
- let on_contract = {
- let contract = contract.clone();
- Callback::from(move |c| contract.set(Some(c)))
- };
-
- let phase = if contract.is_none() {
- Phase::Bidding
- } else {
- Phase::Cardplay
- };
+ let state = use_state(|| init_state());
let shuffle = {
- let dealt_cards = dealt_cards.clone();
- let dealer = dealer.clone();
- let contract = contract.clone();
-
+ let state = state.clone();
Callback::from(move |_| {
- dealt_cards.set(deal());
- dealer.set(dealer.next());
- contract.set(None);
+ state.set(init_state());
})
};
let on_card_clicked = { Callback::from(move |card| info!("Card clicked: {}", card)) };
+ let center = match &*state {
+ GameState::Bidding { dealer, deal } => {
+ let on_contract = {
+ let state = state.clone();
+ let dealer = dealer.clone();
+ let deal = deal.clone();
+ Callback::from(move |(contract, bidding)| {
+ state.set(match contract {
+ Some(contract) => GameState::Play {
+ dealer: dealer,
+ deal: deal.clone(),
+ contract,
+ bidding,
+ },
+ None => GameState::PassedOut {
+ dealer: dealer,
+ deal: deal.clone(),
+ bidding,
+ },
+ });
+ })
+ };
+ html! {
+ <Bidding {on_contract} dealer={dealer.clone()} />
+ }
+ }
+ GameState::Play {
+ dealer,
+ deal,
+ contract,
+ bidding,
+ } => html! { <p>{ "Time to play" }</p> },
+ GameState::PassedOut { .. } => html! { <p>{ "Everyone passed" }</p> },
+ };
+
html! {
<>
<div class="nav">
- if let Some((contract, bidding)) = &*contract {
+ if let GameState::Play { contract, bidding, .. } = &*state {
<ShowBid contract={contract.clone()} bidding={bidding.clone()}/>
- }
- <p>{ format!("Phase: {:?}", phase) }</p>
+ }
+ <p>{ format!("Phase: {:?}", &*state) }</p>
<button onclick={shuffle}>{ "Shuffle" }</button>
</div>
<div class="center">
- <p>{ format!("Dealer: {:?}", *dealer) }</p>
- if let Some(_) = &*contract {
- { "Let's play." }
- } else {
- <Bidding {on_contract} dealer={ *dealer } />
- }
+ { center }
</div>
<div class="hand west">
- <Hand cards={ dealt_cards.west.clone() }
+ <Hand cards={ state.deal().west.clone() }
on_card_clicked={ on_card_clicked.clone() }
/>
</div>
<div class="hand north">
- <Hand cards={ dealt_cards.north.clone() }
+ <Hand cards={ state.deal().north.clone() }
on_card_clicked={ on_card_clicked.clone() }
/>
</div>
<div class="hand east">
- <Hand cards={ dealt_cards.east.clone() }
+ <Hand cards={ state.deal().east.clone() }
on_card_clicked={ on_card_clicked.clone() }
/>
</div>
<div class="hand south">
- <Hand cards={ dealt_cards.south.clone() }
+ <Hand cards={ state.deal().south.clone() }
on_card_clicked={ on_card_clicked.clone() }
/>
</div>
diff --git a/webapp/src/components/hand.rs b/webapp/src/components/hand.rs
index 9e1f993..411a173 100644
--- a/webapp/src/components/hand.rs
+++ b/webapp/src/components/hand.rs
@@ -1,4 +1,4 @@
-use crate::components::card::{Card, CardProps};
+use crate::components::card::{Card};
use crate::card;
use yew::prelude::*;