You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
232 lines
8.2 KiB
232 lines
8.2 KiB
use crate::hand_view::HandView;
|
|
use crate::remote_view::RemoteGameView;
|
|
use crate::tile_view::PlacedTileView;
|
|
use crate::types::SelectedTile;
|
|
use board_shared::board::Board;
|
|
use board_shared::deck::RngDeck;
|
|
use board_shared::expr::is_valid_guess;
|
|
use board_shared::game::Game;
|
|
use board_shared::position::Grid2d;
|
|
use board_shared::tile::Tile;
|
|
use futures::StreamExt;
|
|
use gloo_dialogs::alert;
|
|
use gloo_net::websocket::futures::WebSocket;
|
|
use std::cell::RefCell;
|
|
use std::rc::Rc;
|
|
use web_sys::HtmlInputElement;
|
|
use yew::prelude::*;
|
|
|
|
#[derive(Properties, PartialEq)]
|
|
pub struct BoardViewProps {
|
|
pub board: Board,
|
|
pub on_click: Callback<(usize, usize)>,
|
|
}
|
|
|
|
#[function_component(BoardView)]
|
|
pub fn board_view(BoardViewProps { board, on_click }: &BoardViewProps) -> Html {
|
|
html! {
|
|
<table class="board">
|
|
{ (0..board.height()).map(|y| html! {
|
|
<tr class="board-row">
|
|
{ (0..board.width()).map(|x| html! {
|
|
<PlacedTileView x={x} y={y} key={x} tile={board.get(x, y)} on_click={on_click.clone()} />
|
|
}).collect::<Html>() }
|
|
</tr>
|
|
}).collect::<Html>() }
|
|
</table>
|
|
}
|
|
}
|
|
|
|
#[function_component(GameView)]
|
|
pub fn game_view() -> Html {
|
|
let game = use_state(Game::default);
|
|
let current_game = use_state(Game::default);
|
|
|
|
let selected_tile = use_state(|| SelectedTile::None);
|
|
let on_tile_click = {
|
|
let game = current_game.clone();
|
|
let selected_tile = selected_tile.clone();
|
|
Callback::from(move |(x, y)| {
|
|
if let SelectedTile::InHand(idx) = *selected_tile {
|
|
let mut in_hand = game.in_hand.clone();
|
|
let tile = in_hand.tiles.remove(idx);
|
|
let mut board = game.board.clone();
|
|
board.set(x, y, tile);
|
|
game.set(Game { board, in_hand });
|
|
selected_tile.set(SelectedTile::None);
|
|
} else if let SelectedTile::Equals = *selected_tile {
|
|
let mut board = game.board.clone();
|
|
board.set(x, y, Tile::Equals);
|
|
game.set(Game {
|
|
board,
|
|
in_hand: game.in_hand.clone(),
|
|
});
|
|
selected_tile.set(SelectedTile::None);
|
|
}
|
|
})
|
|
};
|
|
let on_tile_select = {
|
|
let selected_tile = selected_tile.clone();
|
|
Callback::from(move |idx| {
|
|
selected_tile.set(SelectedTile::InHand(idx));
|
|
})
|
|
};
|
|
let on_equals_select = {
|
|
Callback::from(move |_| {
|
|
selected_tile.set(SelectedTile::Equals);
|
|
})
|
|
};
|
|
let on_continue_click = {
|
|
let current_game = current_game.clone();
|
|
Callback::from(move |_| {
|
|
let diff = game.board.difference(¤t_game.board);
|
|
let mut deck = RngDeck::new_complete();
|
|
if let Some(true) = Board::is_contiguous(&diff) {
|
|
if let Ok(true) = is_valid_guess(¤t_game.board, &diff) {
|
|
alert("Valid move!");
|
|
let mut in_hand = current_game.in_hand.clone();
|
|
if in_hand.complete(&mut deck).is_err() {
|
|
alert("No more tiles left in deck!");
|
|
}
|
|
game.set(Game {
|
|
board: current_game.board.clone(),
|
|
in_hand: in_hand.clone(),
|
|
});
|
|
current_game.set(Game {
|
|
board: current_game.board.clone(),
|
|
in_hand,
|
|
});
|
|
} else {
|
|
alert("Invalid move! (invalid expressions)");
|
|
current_game.set(Game {
|
|
board: game.board.clone(),
|
|
in_hand: game.in_hand.clone(),
|
|
});
|
|
}
|
|
} else {
|
|
if !diff.is_empty() {
|
|
alert("Invalid move! (not contiguous)");
|
|
}
|
|
let mut in_hand = game.in_hand.clone();
|
|
if in_hand.complete(&mut deck).is_err() {
|
|
alert("No more tiles left in deck!");
|
|
}
|
|
current_game.set(Game {
|
|
board: game.board.clone(),
|
|
in_hand,
|
|
});
|
|
}
|
|
})
|
|
};
|
|
html! {
|
|
<main>
|
|
<BoardView board={current_game.board.clone()} on_click={on_tile_click} />
|
|
<HandView hand={current_game.in_hand.clone()} on_select={on_tile_select} />
|
|
<div class="row">
|
|
<button onclick={on_equals_select} class="button">{"="}</button>
|
|
<button onclick={on_continue_click} class="button">{if current_game.in_hand.tiles.is_empty() { "Start" } else { "Continue" }}</button>
|
|
</div>
|
|
</main>
|
|
}
|
|
}
|
|
|
|
#[function_component(App)]
|
|
pub fn app() -> Html {
|
|
let remote = use_state(|| "ws://localhost:8081/ws".to_string());
|
|
let player_name = use_state(|| None);
|
|
let room_name = use_state(|| None);
|
|
|
|
let remote_ref = use_node_ref();
|
|
let player_name_ref = use_node_ref();
|
|
let room_name_ref = use_node_ref();
|
|
let on_create_click = {
|
|
let remote = remote.clone();
|
|
let remote_ref = remote_ref.clone();
|
|
let player_name = player_name.clone();
|
|
let player_name_ref = player_name_ref.clone();
|
|
Callback::from(move |_| {
|
|
remote.set(
|
|
remote_ref
|
|
.cast::<HtmlInputElement>()
|
|
.expect("remote_ref is not attached to a input element")
|
|
.value(),
|
|
);
|
|
player_name.set(Some(
|
|
player_name_ref
|
|
.cast::<HtmlInputElement>()
|
|
.expect("player_name_ref is not attached to a input element")
|
|
.value(),
|
|
));
|
|
})
|
|
};
|
|
let on_join_click = {
|
|
let remote = remote.clone();
|
|
let remote_ref = remote_ref.clone();
|
|
let player_name = player_name.clone();
|
|
let player_name_ref = player_name_ref.clone();
|
|
let room_name = room_name.clone();
|
|
let room_name_ref = room_name_ref.clone();
|
|
Callback::from(move |_| {
|
|
remote.set(
|
|
remote_ref
|
|
.cast::<HtmlInputElement>()
|
|
.expect("remote_ref is not attached to a input element")
|
|
.value(),
|
|
);
|
|
player_name.set(Some(
|
|
player_name_ref
|
|
.cast::<HtmlInputElement>()
|
|
.expect("player_name_ref is not attached to a input element")
|
|
.value(),
|
|
));
|
|
room_name.set(Some(
|
|
room_name_ref
|
|
.cast::<HtmlInputElement>()
|
|
.expect("room_name_ref is not attached to a input element")
|
|
.value(),
|
|
));
|
|
})
|
|
};
|
|
|
|
if let Some(player_name) = (*player_name).as_ref() {
|
|
let ws = WebSocket::open(remote.as_ref()).unwrap();
|
|
let (write, read) = ws.split();
|
|
|
|
return html! {
|
|
<div class="app">
|
|
<RemoteGameView
|
|
write={Rc::new(RefCell::new(write))}
|
|
read={Rc::new(RefCell::new(read))}
|
|
player_name={player_name.clone()}
|
|
room_name={(*room_name).clone()} />
|
|
</div>
|
|
};
|
|
}
|
|
|
|
html! {
|
|
<main>
|
|
<div>
|
|
<label>{"Server: "}</label>
|
|
<input type="text" required={true} value={"ws://localhost:8081"} ref={remote_ref} />
|
|
</div>
|
|
<div>
|
|
<label>{"Player name: "}</label>
|
|
<input type="text" required={true} value={"test"} ref={player_name_ref} />
|
|
</div>
|
|
|
|
<div style="display: grid; grid-template-columns: 2fr 2fr;">
|
|
<div>
|
|
<button onclick={on_create_click}>{"Create"}</button>
|
|
</div>
|
|
<div>
|
|
<div>
|
|
<label>{"Room name: "}</label>
|
|
<input type="text" ref={room_name_ref} />
|
|
</div>
|
|
<button onclick={on_join_click}>{"Join"}</button>
|
|
</div>
|
|
</div>
|
|
</main>
|
|
}
|
|
}
|