use serde::{Deserialize, Serialize};
-use std::cell::Cell;
+use std::cell::{Cell, RefCell};
use std::collections::hash_set::HashSet;
use std::fmt::Display;
use std::rc::Rc;
-#[derive(Copy, Clone, Debug, PartialEq, Eq)]
+#[derive(Clone, Debug, PartialEq, Eq)]
pub enum GameState {
MainMenu,
SinglePlayer(Turn, AIDifficulty),
paired: bool,
current_side: Option<Turn>,
current_turn: Turn,
+ phrase: Option<String>,
},
PostGameResults(BoardState),
}
impl GameState {
- pub fn is_networked_multiplayer(self) -> bool {
+ pub fn is_networked_multiplayer(&self) -> bool {
matches!(
- self,
+ *self,
GameState::NetworkedMultiplayer {
paired: _,
current_side: _,
- current_turn: _
+ current_turn: _,
+ phrase: _,
}
)
}
ref mut paired,
current_side: _,
current_turn: _,
+ phrase: _,
} = self
{
*paired = true;
paired: _,
current_side,
current_turn: _,
+ phrase: _,
} = *self
{
current_side
paired: _,
ref mut current_side,
current_turn: _,
+ phrase: _,
} = self
{
*current_side = side;
paired: _,
current_side: _,
current_turn,
+ phrase: _,
} = *self
{
current_turn
paired: _,
current_side,
current_turn: _,
+ phrase: _,
} = *self
{
current_side
paired: _,
current_side: _,
ref mut current_turn,
+ phrase: _,
} = self
{
*current_turn = turn;
}
}
+
+ pub fn get_phrase(&self) -> Option<String> {
+ if let GameState::NetworkedMultiplayer {
+ paired: _,
+ current_side: _,
+ current_turn: _,
+ phrase,
+ } = self
+ {
+ phrase.clone()
+ } else {
+ None
+ }
+ }
}
impl Default for GameState {
match msg {
MainMenuMessage::SinglePlayer(t, ai) => GameState::SinglePlayer(t, ai),
MainMenuMessage::LocalMultiplayer => GameState::LocalMultiplayer,
- MainMenuMessage::NetworkedMultiplayer => GameState::NetworkedMultiplayer {
+ MainMenuMessage::NetworkedMultiplayer(phrase) => GameState::NetworkedMultiplayer {
paired: false,
current_side: None,
current_turn: Turn::CyanPlayer,
+ phrase,
},
}
}
#[derive(Clone, Debug, PartialEq)]
pub struct SharedState {
pub board: BoardType,
- pub game_state: Rc<Cell<GameState>>,
+ pub game_state: Rc<RefCell<GameState>>,
pub turn: Rc<Cell<Turn>>,
pub placed: PlacedType,
}
Self {
// cannot use [<type>; 56] because Rc does not impl Copy
board: new_empty_board(),
- game_state: Rc::new(Cell::new(GameState::default())),
+ game_state: Rc::new(RefCell::new(GameState::default())),
turn: Rc::new(Cell::new(Turn::CyanPlayer)),
placed: new_placed(),
}
// This enum moved from yew_components module so that this module would have no
// dependencies on the yew_components module
-#[derive(Copy, Clone, Debug, PartialEq, Eq)]
+#[derive(Clone, Debug, PartialEq, Eq)]
pub enum MainMenuMessage {
SinglePlayer(Turn, AIDifficulty),
LocalMultiplayer,
- NetworkedMultiplayer,
+ NetworkedMultiplayer(Option<String>),
}
pub fn new_string_board() -> String {
paired: false,
current_side: None,
current_turn: Turn::CyanPlayer,
+ phrase: None,
};
assert!(state.is_networked_multiplayer());
let state = GameState::NetworkedMultiplayer {
paired: true,
current_side: Some(Turn::CyanPlayer),
current_turn: Turn::MagentaPlayer,
+ phrase: None,
};
+ assert!(state.is_networked_multiplayer());
}
}
};
use crate::game_logic::{check_win_draw, WinType};
use crate::html_helper::{
- append_to_info_text, create_json_request, element_append_class, element_has_class,
- element_remove_class, get_window_document, send_to_backend,
+ append_to_info_text, element_append_class, element_has_class, element_remove_class,
+ get_window_document, send_to_backend,
};
use crate::random_helper::get_seeded_random;
use crate::state::{
- board_from_string, BoardState, BoardType, GameState, GameStateResponse, MainMenuMessage,
+ board_from_string, BoardState, GameState, GameStateResponse, MainMenuMessage,
NetworkedGameState, PairingRequestResponse, PairingStatusResponse, PlaceTokenResponse,
PlacedEnum, SharedState, Turn,
};
use std::rc::Rc;
use js_sys::{Function, Promise};
-use wasm_bindgen::JsCast;
-use web_sys::{AddEventListenerOptions, Document, Response};
-
-use serde_json::Value as SerdeJSONValue;
+use web_sys::{AddEventListenerOptions, Document, HtmlInputElement};
use wasm_bindgen_futures::JsFuture;
let onclick_networked_multiplayer = ctx
.link()
- .callback(|_| MainMenuMessage::NetworkedMultiplayer);
+ .callback(|_| MainMenuMessage::NetworkedMultiplayer(None));
- let menu_class = if shared.game_state.get() == GameState::MainMenu {
+ let menu_class = if shared.game_state.borrow().eq(&GameState::MainMenu) {
"menu"
} else {
"hidden_menu"
<button class={"menuLocalMultiplayer"} onclick={onclick_local_multiplayer}>
{"Local Multiplayer"}
</button>
- <button class={"menuMultiplayer"} onclick={onclick_networked_multiplayer}>
- {"Networked Multiplayer"}
- </button>
+ <div class={"multiplayerMenu"}>
+ <button class={"networkedMultiplayer"} onclick={onclick_networked_multiplayer}>
+ {"Networked Multiplayer"}
+ </button>
+ <button class={"NMPhrase"} onclick={ctx.link().callback(|_| {
+ let (_window, document) = get_window_document().expect("Should be able to get window/document");
+ let input = HtmlInputElement::from(wasm_bindgen::JsValue::from(document.get_element_by_id("NMPhraseText").expect("Should be able to get NMPhrase input element")));
+ MainMenuMessage::NetworkedMultiplayer(Some(input.value()))
+ })}>
+ {"NMultiplayer with Phrase"}
+ </button>
+ <input class={"NMPhrase"} id={"NMPhraseText"} placeholder={"input phrase here"} autofocus=true />
+ </div>
</div>
}
}
let document = window.document().expect("window should have a document");
shared.game_state.replace(msg.into());
- if shared.game_state.get() != GameState::MainMenu {
+ if !shared.game_state.borrow().eq(&GameState::MainMenu) {
let mainmenu = document
.get_element_by_id("mainmenu")
.expect("mainmenu should exist");
mainmenu.set_class_name("hidden_menu");
- match shared.game_state.get() {
+ match shared.game_state.borrow().clone() {
GameState::SinglePlayer(turn, _) => {
if shared.turn.get() == turn {
append_to_info_text(
paired: _,
current_side: _,
current_turn: _,
+ phrase: _,
} => {
append_to_info_text(
&document,
.context::<SharedState>(Callback::noop())
.expect("state to be set");
- match shared.game_state.get() {
+ match shared.game_state.borrow().clone() {
GameState::MainMenu => return false,
GameState::SinglePlayer(_, _) | GameState::LocalMultiplayer => (),
GameState::NetworkedMultiplayer {
paired,
current_side,
current_turn,
+ phrase: _,
} => {
if paired && current_side.is_some() {
if current_side.as_ref().unwrap() == ¤t_turn {
}
GameState::PostGameResults(_) => return false,
}
- if shared.game_state.get() == GameState::MainMenu {
+ if shared.game_state.borrow().eq(&GameState::MainMenu) {
return false;
}
}
fn get_networked_player_id(&mut self, ctx: &Context<Self>) {
+ let (shared, _) = ctx
+ .link()
+ .context::<SharedState>(Callback::noop())
+ .expect("state to be set");
+ let phrase_clone: Option<String> = shared.game_state.borrow().get_phrase();
+
// make a request to get the player_id
- ctx.link().send_future(async {
+ ctx.link().send_future(async move {
let mut json_entries = HashMap::new();
json_entries.insert("type".into(), "pairing_request".into());
+ if let Some(phrase_string) = phrase_clone {
+ json_entries.insert("phrase".into(), phrase_string);
+ }
let send_to_backend_result = send_to_backend(json_entries).await;
if let Err(e) = send_to_backend_result {
// check if player can make a move
if !msg.is_ai_pressed() {
- match shared.game_state.get() {
+ match shared.game_state.borrow().clone() {
GameState::MainMenu => (),
GameState::SinglePlayer(turn, _) => {
if current_player != turn {
paired,
current_side,
current_turn,
+ phrase: _,
} => {
if paired {
if let Some(current_side) = current_side {
// info text right of the grid
{
let turn = shared.turn.get();
- let output_str =
- if let GameState::SinglePlayer(player_turn, _) = shared.game_state.get() {
- if shared.turn.get() == player_turn {
- format!(
- "<b class=\"{}\">It is {}'s (player) turn</b>",
- turn.get_color(),
- turn
- )
- } else {
- format!(
- "<b class=\"{}\">It is {}'s (ai) turn</b>",
- turn.get_color(),
- turn
- )
- }
+ let output_str = if let GameState::SinglePlayer(player_turn, _) =
+ shared.game_state.borrow().clone()
+ {
+ if shared.turn.get() == player_turn {
+ format!(
+ "<b class=\"{}\">It is {}'s (player) turn</b>",
+ turn.get_color(),
+ turn
+ )
} else {
format!(
- "<b class=\"{}\">It is {}'s Turn</b>",
+ "<b class=\"{}\">It is {}'s (ai) turn</b>",
turn.get_color(),
turn
)
- };
+ }
+ } else {
+ format!(
+ "<b class=\"{}\">It is {}'s Turn</b>",
+ turn.get_color(),
+ turn
+ )
+ };
let text_append_result =
append_to_info_text(&document, "info_text1", &output_str, 1);
// check if it is AI's turn
if let GameState::SinglePlayer(player_type, _ai_difficulty) =
- shared.game_state.get()
+ shared.game_state.borrow().clone()
{
if shared.turn.get() != player_type {
ctx.link().send_message(WrapperMsg::AIChoice);
}
WrapperMsg::AIChoiceImpl => {
// get AI's choice
- if let GameState::SinglePlayer(player_type, ai_difficulty) = shared.game_state.get()
+ if let GameState::SinglePlayer(player_type, ai_difficulty) =
+ shared.game_state.borrow().clone()
{
if shared.turn.get() != player_type {
let choice =
ctx.link().send_message(WrapperMsg::BackendTick);
}
WrapperMsg::BackendTick => {
- if !self.do_backend_tick || !shared.game_state.get().is_networked_multiplayer() {
+ let is_networked_multiplayer =
+ shared.game_state.borrow().is_networked_multiplayer();
+ if !self.do_backend_tick || !is_networked_multiplayer {
// disconnect id if backend tick is to be stopped
if let Some(id) = self.player_id.take() {
let function = Function::new_no_args(&format!(
self.get_networked_player_id(ctx);
} else if shared
.game_state
- .get()
+ .borrow()
.get_networked_current_side()
.is_none()
{
self.get_networked_player_type(ctx);
- } else if !matches!(shared.game_state.get(), GameState::PostGameResults(_)) {
+ } else if !matches!(
+ shared.game_state.borrow().clone(),
+ GameState::PostGameResults(_)
+ ) {
if self.place_request.is_some() {
let placement = self.place_request.take().unwrap();
self.send_place_request(ctx, placement);
});
self.player_id = Some(id);
- let mut game_state = shared.game_state.get();
+ let mut game_state = shared.game_state.borrow().clone();
game_state.set_networked_paired();
game_state.set_networked_current_side(turn_opt);
- shared.game_state.set(game_state);
+ shared.game_state.replace(game_state);
if let Some(turn_type) = turn_opt {
append_to_info_text(
&document,
}
}
BREnum::GotPairing(turn_opt) => {
- let mut game_state = shared.game_state.get();
+ let mut game_state = shared.game_state.borrow().clone();
game_state.set_networked_current_side(turn_opt);
- shared.game_state.set(game_state);
+ shared.game_state.replace(game_state);
if let Some(turn_type) = turn_opt {
append_to_info_text(
&document,
self.update_board_from_string(&shared, &document, board_string);
}
- let mut current_game_state = shared.game_state.get();
+ let mut current_game_state: GameState = shared.game_state.borrow().clone();
match networked_game_state {
NetworkedGameState::CyanTurn => {
if current_game_state.get_current_turn() != Turn::CyanPlayer {
current_game_state.set_networked_current_turn(Turn::CyanPlayer);
- shared.game_state.set(current_game_state);
+ shared.game_state.replace(current_game_state.clone());
append_to_info_text(
&document,
"info_text1",
if current_game_state.get_current_turn() != Turn::MagentaPlayer {
current_game_state
.set_networked_current_turn(Turn::MagentaPlayer);
- shared.game_state.set(current_game_state);
+ shared.game_state.replace(current_game_state.clone());
append_to_info_text(
&document,
"info_text1",
.ok();
shared
.game_state
- .set(GameState::PostGameResults(BoardState::CyanWin));
+ .replace(GameState::PostGameResults(BoardState::CyanWin));
self.do_backend_tick = false;
}
NetworkedGameState::MagentaWon => {
.ok();
shared
.game_state
- .set(GameState::PostGameResults(BoardState::MagentaWin));
+ .replace(GameState::PostGameResults(BoardState::MagentaWin));
self.do_backend_tick = false;
}
NetworkedGameState::Draw => {
.ok();
shared
.game_state
- .set(GameState::PostGameResults(BoardState::Empty));
+ .replace(GameState::PostGameResults(BoardState::Empty));
self.do_backend_tick = false;
}
NetworkedGameState::Disconnected => {
.ok();
shared
.game_state
- .set(GameState::PostGameResults(BoardState::Empty));
+ .replace(GameState::PostGameResults(BoardState::Empty));
self.do_backend_tick = false;
}
NetworkedGameState::InternalError => {
.ok();
shared
.game_state
- .set(GameState::PostGameResults(BoardState::Empty));
+ .replace(GameState::PostGameResults(BoardState::Empty));
self.do_backend_tick = false;
}
NetworkedGameState::NotPaired => (),
.ok();
shared
.game_state
- .set(GameState::PostGameResults(BoardState::Empty));
+ .replace(GameState::PostGameResults(BoardState::Empty));
self.do_backend_tick = false;
}
}
.ok();
shared
.game_state
- .set(GameState::PostGameResults(BoardState::CyanWin));
+ .replace(GameState::PostGameResults(BoardState::CyanWin));
self.do_backend_tick = false;
}
NetworkedGameState::MagentaWon => {
1,
)
.ok();
- shared
- .game_state
- .set(GameState::PostGameResults(BoardState::MagentaWin));
+ shared.game_state.replace(GameState::PostGameResults(
+ BoardState::MagentaWin,
+ ));
self.do_backend_tick = false;
}
NetworkedGameState::Draw => {
.ok();
shared
.game_state
- .set(GameState::PostGameResults(BoardState::Empty));
+ .replace(GameState::PostGameResults(BoardState::Empty));
self.do_backend_tick = false;
}
NetworkedGameState::Disconnected => {
.ok();
shared
.game_state
- .set(GameState::PostGameResults(BoardState::Empty));
+ .replace(GameState::PostGameResults(BoardState::Empty));
self.do_backend_tick = false;
}
NetworkedGameState::InternalError => {
.ok();
shared
.game_state
- .set(GameState::PostGameResults(BoardState::Empty));
+ .replace(GameState::PostGameResults(BoardState::Empty));
self.do_backend_tick = false;
}
NetworkedGameState::NotPaired => (),
.ok();
shared
.game_state
- .set(GameState::PostGameResults(BoardState::Empty));
+ .replace(GameState::PostGameResults(BoardState::Empty));
self.do_backend_tick = false;
}
},
}
}
WrapperMsg::Reset => {
- shared.game_state.set(GameState::default());
+ shared.game_state.replace(GameState::default());
shared.turn.set(Turn::CyanPlayer);
for idx in 0..((ROWS * COLS) as usize) {
shared.placed[idx].set(false);
}
}
1 => {
- if shared.game_state.get() == GameState::MainMenu {
+ if shared.game_state.borrow().eq(&GameState::MainMenu) {
html! {
<div id={format!("info_text{}", ctx.props().id)} class={format!("info_text{}", ctx.props().id)}>
<p>