use crate::card::{Rank, Suit}; #[allow(unused_imports)] use log::{debug, error, info, warn}; use yew::prelude::*; pub mod bridge_engine; pub mod card; use bridge_engine::Bid; use bridge_engine::Bidding; use bridge_engine::BiddingResult; use bridge_engine::Player; use bridge_engine::Raise; 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()); yew::start_app::(); } #[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 bidding_state = use_state(|| BiddingResult::new(Player::East)); 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 table" }

{ "Bidding box" }

{ "North" }

{ "West" }

{ "South" }

{ "East" }

{ "Controls" }

} } #[function_component(Hand)] pub fn hand(props: &HandProps) -> Html { let cards: Html = props .cards .iter() .map(|c| { html! { } }) .collect(); html! {
{ cards }
} } pub fn suit_css_class(suit: Suit) -> &'static str { match suit { Suit::Club => "suit-club", Suit::Diamond => "suit-diamond", Suit::Heart => "suit-heart", Suit::Spade => "suit-spade", } } #[derive(Clone, Default, PartialEq, Properties)] pub struct HandProps { #[prop_or_default] cards: Vec, } impl> FromIterator for HandProps { fn from_iter(cards: Cards) -> Self where Cards: std::iter::IntoIterator, { HandProps { cards: cards.into_iter().map(Into::into).collect(), } } } #[function_component(Card)] pub fn wcard(props: &CardProps) -> Html { html! {
{ props.rank }
} } #[derive(PartialEq, Properties, Clone)] pub struct CardProps { suit: Suit, rank: Rank, } impl From for CardProps { fn from(card::Card(suit, rank): card::Card) -> Self { CardProps { suit, rank } } } pub fn bid_css_class(suit: Option) -> &'static str { match suit { None => "suit-notrump", Some(x) => suit_css_class(x), } } fn padding(dealer: Player) -> Html { let mut padding : Vec = vec![]; let mut player = Player::West; while player != dealer { padding.push(html! {
}); player = player.next(); } padding.into_iter().collect() } #[function_component(BiddingTable)] pub fn bidding_table(props: &BiddingTableProps) -> Html { let bid = |bid: &Bid| match bid.as_raise() { None => html!{
{ bid }
}, Some(raise) => html!{
{ raise.level }
}, }; let bids: Html = props .bidding .bids .iter() .map(|b| { bid(b) }) .collect(); let padding : Html = padding(props.bidding.dealer); html! {
{ "West" }
{ "North" }
{ "East" }
{ "South" }
{ padding } { bids }
} } #[derive(PartialEq, Properties, Clone)] pub struct BiddingTableProps { bidding: Bidding, } #[function_component(BiddingBox)] pub fn bidding_box(props: &BiddingBoxProps) -> Html { let bids: Html = Raise::all_raises() .iter() .map(|bid| { let mut class = if Some(*bid) <= props.current_bid { classes!("disabled") } else { classes!("enabled") }; class.extend(classes!(bid_css_class(bid.suit))); html! {
{ bid.level }
} }) .collect(); html! {
{ bids }
{ "Pass" }
{ "X" }
{ "XX" }
} } #[derive(PartialEq, Properties, Clone)] pub struct BiddingBoxProps { current_bid: Option, } #[cfg(test)] mod tests { pub fn test_setup() { dotenv::dotenv().ok(); let _ = env_logger::builder().is_test(true).try_init(); } }