use serde::{Deserialize, Serialize}; use serde_wasm_bindgen::Error; use tsify::Tsify; use wasm_bindgen::JsValue; use wasm_bindgen::prelude::wasm_bindgen; use crate::board::{Board, CellType, Coordinates, Letter}; use crate::game::Game; #[wasm_bindgen] pub struct GameWasm(Game); #[derive(Serialize, Deserialize, Tsify)] #[tsify(from_wasm_abi)] pub enum ResponseType { OK, ERR, } #[derive(Serialize, Deserialize, Tsify)] #[tsify(from_wasm_abi)] pub struct MyResult { response_type: ResponseType, value: E, } #[derive(Deserialize, Tsify, Copy, Clone)] #[tsify(from_wasm_abi)] pub struct PlayedTile { index: usize, character: Option, } #[wasm_bindgen] impl GameWasm { #[wasm_bindgen(constructor)] pub fn new(seed: u64, dictionary_text: &str) -> GameWasm { GameWasm(Game::new(seed, dictionary_text, vec!["Player".to_string(), "AI".to_string()])) } pub fn get_tray(&self, name: &str) -> Result { let tray = self.0.get_tray(name); serde_wasm_bindgen::to_value(&tray) } pub fn get_board_cell_types(&self) -> Result { let board = self.0.get_board(); let cell_types: Vec = board.cells.iter().map(|cell| -> CellType { cell.cell_type.clone() }).collect(); serde_wasm_bindgen::to_value(&cell_types) } pub fn get_board_letters(&self) -> Result { let board = self.0.get_board(); let letters: Vec> = board.cells.iter().map(|cell| -> Option { cell.value.clone() }).collect(); serde_wasm_bindgen::to_value(&letters) } pub fn receive_play(&mut self, player: &str, tray_tile_locations: JsValue, commit_move: bool) -> Result { let tray_tile_locations: Vec> = serde_wasm_bindgen::from_value(tray_tile_locations)?; let mut board_instance = self.0.get_board().clone(); let mut tray = self.0.get_tray(player).unwrap().clone(); let mut played_letters: Vec<(Letter, Coordinates)> = Vec::new(); for (i, played_tile) in tray_tile_locations.iter().enumerate() { if played_tile.is_some() { let played_tile = played_tile.unwrap(); let mut letter: Letter = tray.letters.get(i).unwrap().unwrap(); *tray.letters.get_mut(i).unwrap() = None; let coord = Coordinates::new_from_index(played_tile.index); if letter.is_blank { match played_tile.character { None => { panic!("You can't play a blank character without providing a letter value") } Some(x) => { // TODO - I should check that the character is a valid letter letter.text = x; } } } played_letters.push((letter, coord)); } } match board_instance.receive_play(played_letters) { Err(e) => { return Ok(serde_wasm_bindgen::to_value( &MyResult { response_type: ResponseType::ERR, value: e }).unwrap()); }, Ok(_) => {} } #[derive(Debug, Serialize, Deserialize, Tsify)] #[tsify(from_wasm_abi)] struct WordResult { word: String, score: u32, } let result = board_instance.calculate_scores(self.0.get_dictionary()); let result = match result { Ok(x) => { let words: Vec = x.0.iter() .map(|(word, score)| { WordResult { word: word.to_string(), score: *score } }) .collect(); if commit_move { let mut player_state = self.0.get_player_state_mut(player).unwrap(); player_state.score += x.1; player_state.tray = tray; board_instance.fix_tiles(); self.0.set_board(board_instance); self.0.fill_trays() } serde_wasm_bindgen::to_value( &MyResult { response_type: ResponseType::OK, value: words }).unwrap() }, Err(e) => { serde_wasm_bindgen::to_value( &MyResult { response_type: ResponseType::ERR, value: e }).unwrap() } }; Ok(result) } pub fn get_scores(&self) -> Result { #[derive(Serialize, Deserialize, Tsify)] #[tsify(from_wasm_abi)] pub struct PlayerAndScore { name: String, score: u32, } let scores: Vec = self.0.player_states.iter() .map(|player_state| { PlayerAndScore { name: player_state.player.get_name().to_string(), score: player_state.score, } }) .collect(); Ok(serde_wasm_bindgen::to_value(&scores)?) } }