summaryrefslogtreecommitdiff
path: root/webapp
diff options
context:
space:
mode:
authorKjetil Orbekk <kj@orbekk.com>2022-09-07 21:03:07 -0400
committerKjetil Orbekk <kj@orbekk.com>2022-09-07 21:05:17 -0400
commitf92ca7acbf6998f8cd2cb6b7e1116fcbd29767e4 (patch)
tree597eb56bfda5a11fddded9a1e739e42abe0a435d /webapp
parent1fa6d19a698f62ea2e57164fa1e5f088a8e2ac62 (diff)
Add game component integrated with bidding component
Diffstat (limited to 'webapp')
-rw-r--r--webapp/src/components.rs2
-rw-r--r--webapp/src/components/bidding.rs78
-rw-r--r--webapp/src/components/game.rs68
-rw-r--r--webapp/src/main.rs43
4 files changed, 115 insertions, 76 deletions
diff --git a/webapp/src/components.rs b/webapp/src/components.rs
index e13d372..6d9a5ec 100644
--- a/webapp/src/components.rs
+++ b/webapp/src/components.rs
@@ -5,11 +5,13 @@ mod hand;
mod bidding_table;
mod bidding_box;
mod bidding;
+mod game;
pub use self::card::*;
pub use self::bidding_box::*;
pub use self::bidding_table::*;
pub use self::bidding::*;
+pub use self::game::*;
pub use self::hand::*;
pub fn suit_css_class(suit: Suit) -> &'static str {
diff --git a/webapp/src/components/bidding.rs b/webapp/src/components/bidding.rs
index b8fd893..26a4426 100644
--- a/webapp/src/components/bidding.rs
+++ b/webapp/src/components/bidding.rs
@@ -1,50 +1,58 @@
-use crate::bridge_engine::{Bid, BiddingResult, Player};
+use crate::bridge_engine::{self, Bid, BiddingResult, Contract, Player};
use crate::components::{BiddingBox, BiddingTable};
+use log::{info, error};
use yew::prelude::*;
-#[derive(Debug)]
-pub enum Msg {
- Bid(Bid),
-}
-
-pub struct Bidding {
- bidding: BiddingResult,
-}
-#[derive(PartialEq, Properties)]
+#[derive(PartialEq, Properties, Clone)]
pub struct BiddingProperties {
pub dealer: Player,
+ pub on_contract: Callback<(Contract, bridge_engine::Bidding)>,
}
-impl Component for Bidding {
- type Message = Msg;
- type Properties = BiddingProperties;
+#[function_component(Bidding)]
+pub fn bidding(props: &BiddingProperties) -> Html {
+ let bidding = use_state(|| bridge_engine::Bidding::new(props.dealer));
- fn create(ctx: &Context<Self>) -> Self {
- Self {
- bidding: BiddingResult::new(ctx.props().dealer),
- }
+ {
+ let bidding = bidding.clone();
+ let dealer = props.dealer.clone();
+ use_effect_with_deps(
+ move |_| {
+ bidding.set(bridge_engine::Bidding::new(dealer));
+ || ()
+ },
+ dealer,
+ );
}
- fn update(&mut self, _ctx: &Context<Self>, msg: Self::Message) -> bool {
- match msg {
- Msg::Bid(bid) => {
- self.bidding = self.bidding.bidding().clone().bid(bid).unwrap();
- true
+ let on_bid = {
+ let bidding = bidding.clone();
+ let on_contract = props.on_contract.clone();
+ Callback::from(move |bid| {
+ match (*bidding).clone().bid(bid) {
+ Ok(BiddingResult::Contract(contract, bidding)) => {
+ on_contract.emit((contract, bidding));
+ },
+ Ok(BiddingResult::InProgress(new_bidding)) => {
+ bidding.set(new_bidding);
+ }
+ Err(err) => {
+ error!("Failed to place bid: {:?}", err);
+ }
}
- }
- }
+ })
+ };
- fn view(&self, ctx: &Context<Self>) -> Html {
- html! {
- <>
- <p>{ "Bidding table" }</p>
- <BiddingTable bidding={ self.bidding.bidding().clone() } />
- <p>{ "Bidding box" }</p>
- <BiddingBox
- current_bid={ self.bidding.bidding().highest_bid().clone() }
- on_bid={ ctx.link().callback(|bid| Msg::Bid(bid)) } />
- </>
- }
+ html! {
+ <>
+ <p>{ "Bidding table" }</p>
+ <BiddingTable bidding={ (*bidding).clone() } />
+ <p>{ "Bidding box" }</p>
+ <BiddingBox
+ current_bid={ bidding.highest_bid().clone() }
+ { on_bid }
+ />
+ </>
}
}
diff --git a/webapp/src/components/game.rs b/webapp/src/components/game.rs
new file mode 100644
index 0000000..d31433d
--- /dev/null
+++ b/webapp/src/components/game.rs
@@ -0,0 +1,68 @@
+use crate::bridge_engine::{self, Contract, Player};
+use crate::card;
+use crate::card::Suit;
+use crate::components::{Bidding, Hand, HandProps};
+use yew::prelude::*;
+
+pub const SUIT_DISPLAY_ORDER: [Suit; 4] = [Suit::Diamond, Suit::Club, Suit::Heart, Suit::Spade];
+
+#[function_component(Game)]
+pub fn game() -> Html {
+ let mut rng = rand::thread_rng();
+ let mut deal = card::deal(&mut rng);
+ deal.sort(&SUIT_DISPLAY_ORDER, card::RankOrder::Descending);
+
+ 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<(Contract, bridge_engine::Bidding)>> = use_state(|| None);
+ let on_contract = {
+ let contract = contract.clone();
+ Callback::from(move |c| contract.set(Some(c)))
+ };
+
+ let shuffle = {
+ let north = north.clone();
+ let west = west.clone();
+ let south = south.clone();
+ let east = east.clone();
+ let dealer = dealer.clone();
+
+ Callback::from(move |_| {
+ let mut rng = rand::thread_rng();
+ let mut deal = card::deal(&mut rng);
+ deal.sort(&SUIT_DISPLAY_ORDER, card::RankOrder::Descending);
+ north.set(deal.north.into_iter().collect());
+ west.set(deal.west.into_iter().collect());
+ south.set(deal.south.into_iter().collect());
+ east.set(deal.east.into_iter().collect());
+
+ dealer.set(dealer.next());
+ })
+ };
+
+ html! {
+ <>
+ <p>{ format!("Dealer: {:?}", *dealer) }</p>
+ if let Some((contract, bidding)) = &*contract {
+ { format!("Got contract {:?}. Bidding was {:?}", contract, bidding) }
+ } else {
+ <Bidding {on_contract} dealer={ *dealer } />
+ }
+ <p>{ "North" }</p>
+ <Hand ..(*north).clone() />
+ <p>{ "West" }</p>
+ <Hand ..(*west).clone() />
+ <p>{ "South" }</p>
+ <Hand ..(*south).clone() />
+ <p>{ "East" }</p>
+ <Hand ..(*east).clone() />
+ <p>{ "Controls" }</p>
+ <button onclick={shuffle}>{ "Shuffle" }</button>
+ </>
+ }
+}
diff --git a/webapp/src/main.rs b/webapp/src/main.rs
index 3e77598..b6d75ee 100644
--- a/webapp/src/main.rs
+++ b/webapp/src/main.rs
@@ -5,16 +5,13 @@ use yew::prelude::*;
pub mod bridge_engine;
pub mod card;
pub mod components;
-use bridge_engine::Player;
-use components::{Bidding, Hand, HandProps};
+use components::Game;
extern crate wee_alloc;
// Use `wee_alloc` as the global allocator.
#[global_allocator]
static ALLOC: wee_alloc::WeeAlloc = wee_alloc::WeeAlloc::INIT;
-pub const SUIT_DISPLAY_ORDER: [Suit; 4] = [Suit::Diamond, Suit::Club, Suit::Heart, Suit::Spade];
-
fn main() {
std::panic::set_hook(Box::new(console_error_panic_hook::hook));
wasm_logger::init(wasm_logger::Config::default());
@@ -23,45 +20,9 @@ fn main() {
#[function_component(App)]
pub fn app() -> Html {
- let mut rng = rand::thread_rng();
- let mut deal = card::deal(&mut rng);
- deal.sort(&SUIT_DISPLAY_ORDER, card::RankOrder::Descending);
-
- 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 shuffle = {
- let north = north.clone();
- let west = west.clone();
- let south = south.clone();
- let east = east.clone();
-
- Callback::from(move |_| {
- let mut rng = rand::thread_rng();
- let mut deal = card::deal(&mut rng);
- deal.sort(&SUIT_DISPLAY_ORDER, card::RankOrder::Descending);
- north.set(deal.north.into_iter().collect());
- west.set(deal.west.into_iter().collect());
- south.set(deal.south.into_iter().collect());
- east.set(deal.east.into_iter().collect());
- })
- };
-
html! {
<>
- <Bidding dealer={ Player::East } />
- <p>{ "North" }</p>
- <Hand ..(*north).clone() />
- <p>{ "West" }</p>
- <Hand ..(*west).clone() />
- <p>{ "South" }</p>
- <Hand ..(*south).clone() />
- <p>{ "East" }</p>
- <Hand ..(*east).clone() />
- <p>{ "Controls" }</p>
- <button onclick={shuffle}>{ "Shuffle" }</button>
+ <Game />
</>
}
}