diff --git a/src/board.rs b/src/board.rs index f038ac9..77ffc6f 100644 --- a/src/board.rs +++ b/src/board.rs @@ -1,11 +1,13 @@ use std::collections::HashSet; use std::fmt; use std::fmt::{Formatter, Write}; +use std::borrow::BorrowMut; use serde::{Deserialize, Serialize}; use tsify::Tsify; use crate::constants::{ALL_LETTERS_BONUS, GRID_LENGTH, TRAY_LENGTH}; use crate::dictionary::DictionaryImpl; + #[derive(Clone, Copy)] enum Direction { Row, Column @@ -458,6 +460,16 @@ impl Board { Ok(()) } + pub fn fix_tiles(&mut self) { + for cell in self.cells.iter_mut() { + match cell.value.borrow_mut() { + None => {} + Some(x) => { + x.ephemeral = false; + } + } + } + } } impl fmt::Display for Board { diff --git a/src/game.rs b/src/game.rs index 1752d37..a4abc0a 100644 --- a/src/game.rs +++ b/src/game.rs @@ -28,11 +28,11 @@ impl Player { pub struct PlayerState { pub player: Player, pub score: u32, - tray: Tray + pub tray: Tray } pub struct Game{ - tile_pool: Vec, + pub tile_pool: Vec, board: Board, pub player_states: Vec, dictionary: DictionaryImpl, @@ -75,19 +75,29 @@ impl Game { } } - pub fn get_tray(&self, name: &str) -> Option<&Tray> { - let player = self.player_states.iter() + pub fn get_player_state(&self, name: &str) -> Option<&PlayerState> { + self.player_states.iter() .filter(|state| state.player.get_name().eq(name)) - .nth(0)?; + .nth(0) + + } + + pub fn get_player_state_mut(&mut self, name: &str) -> Option<&mut PlayerState> { + self.player_states.iter_mut() + .filter(|state| state.player.get_name().eq(name)) + .nth(0) + + } + + pub fn get_tray(&self, name: &str) -> Option<&Tray> { + let player = self.get_player_state(name)?; Some(&player.tray) } pub fn get_tray_mut(&mut self, name: &str) -> Option<&mut Tray> { - let player = self.player_states.iter_mut() - .filter(|state| state.player.get_name().eq(name)) - .nth(0)?; + let player = self.get_player_state_mut(name)?; Some(&mut player.tray) @@ -95,8 +105,15 @@ impl Game { pub fn get_board(&self) -> &Board {&self.board} - pub fn get_board_mut(&mut self) -> &mut Board { - &mut self.board + pub fn set_board(&mut self, new_board: Board) { + self.board = new_board; + } + + pub fn fill_trays(&mut self){ + for state in self.player_states.iter_mut() { + let tray = &mut state.tray; + tray.fill(&mut self.tile_pool); + } } pub fn get_dictionary(&self) -> &DictionaryImpl { @@ -104,5 +121,4 @@ impl Game { } - } \ No newline at end of file diff --git a/src/player_interaction.rs b/src/player_interaction.rs index efa325c..5f18a9d 100644 --- a/src/player_interaction.rs +++ b/src/player_interaction.rs @@ -5,7 +5,7 @@ use crate::board::Letter; pub mod ai; -#[derive(Debug, Serialize, Deserialize, Tsify)] +#[derive(Debug, Serialize, Deserialize, Tsify, Clone)] #[tsify(from_wasm_abi)] pub struct Tray { pub letters: Vec> diff --git a/src/wasm.rs b/src/wasm.rs index fe9d9ef..59e7984 100644 --- a/src/wasm.rs +++ b/src/wasm.rs @@ -58,13 +58,14 @@ impl GameWasm { let tray_tile_locations: Vec> = serde_wasm_bindgen::from_value(tray_tile_locations)?; let mut board_instance = self.0.get_board().clone(); - let tray = self.0.get_tray(player).unwrap().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 { @@ -113,7 +114,16 @@ impl GameWasm { }) .collect(); - //let total_score = x.1; + + 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 { diff --git a/ui/src/elements.tsx b/ui/src/elements.tsx index f66ae2f..bd36f30 100644 --- a/ui/src/elements.tsx +++ b/ui/src/elements.tsx @@ -1,6 +1,6 @@ import * as React from "react"; import {GameWasm, Letter as LetterData, MyResult, PlayedTile, PlayerAndScore, Tray, WordResult} from "word_grid"; -import {useMemo, useReducer, useState} from "react"; +import {useEffect, useMemo, useReducer, useState} from "react"; export enum LocationType { GRID, @@ -72,10 +72,15 @@ function matchCoordinate(playerLetters: PlayableLetterData[], coords: Coordinate } -type TileDispatch = React.Dispatch<{start: CoordinateData, end: CoordinateData}>; +enum TileDispatchActionType { + MOVE, + RETRIEVE, +} +type TileDispatchAction = {action: TileDispatchActionType, start?: CoordinateData, end?: CoordinateData}; +type TileDispatch = React.Dispatch; function addLogInfo(existingLog: React.JSX.Element[], newItem: React.JSX.Element) { - newItem.key = existingLog.length; + newItem = React.cloneElement(newItem, { key: existingLog.length }) existingLog.push(newItem); return existingLog.slice(); } @@ -86,31 +91,48 @@ export function Game(props: {wasm: GameWasm}) { return props.wasm.get_board_cell_types(); }, []); - const [checkPerformed, setCheckPerformed] = useState(false); + const [confirmedScorePoints, setConfirmedScorePoints] = useState(-1); - function movePlayableLetters(playerLetters: PlayableLetterData[], update: {start: CoordinateData, end: CoordinateData}) { + function movePlayableLetters(playerLetters: PlayableLetterData[], update: TileDispatchAction) { - let startIndex = matchCoordinate(playerLetters, update.start); - let endIndex = matchCoordinate(playerLetters, update.end); + if(update.action === TileDispatchActionType.RETRIEVE) { + let tray: Tray = props.wasm.get_tray("Player"); - if(startIndex != null) { - let startLetter = playerLetters[startIndex]; - startLetter.location = update.end.location; - startLetter.index = update.end.index; + // initial state + let letters: PlayableLetterData[] = tray.letters.map((ld, i) => { + ld["location"] = LocationType.TRAY; + ld["index"] = i; + return ld as PlayableLetterData; + }) + return letters; + } else if (update.action === TileDispatchActionType.MOVE) { + + let startIndex = matchCoordinate(playerLetters, update.start); + let endIndex = matchCoordinate(playerLetters, update.end); + + if(startIndex != null) { + let startLetter = playerLetters[startIndex]; + startLetter.location = update.end.location; + startLetter.index = update.end.index; + } + + if(endIndex != null) { + let endLetter = playerLetters[endIndex]; + endLetter.location = update.start.location; + endLetter.index = update.start.index; + } + + setConfirmedScorePoints(-1); + + return playerLetters.slice(); + } else { + console.error("Unknown tray update"); + console.error({update}); } - if(endIndex != null) { - let endLetter = playerLetters[endIndex]; - endLetter.location = update.start.location; - endLetter.index = update.start.index; - } - - setCheckPerformed(false); - - return playerLetters.slice(); } - const [playerLetters, dispatch] = useReducer(movePlayableLetters, null, (_) => { + const [playerLetters, trayDispatch] = useReducer(movePlayableLetters, null, (_) => { let tray: Tray = props.wasm.get_tray("Player"); // initial state @@ -127,14 +149,22 @@ export function Game(props: {wasm: GameWasm}) { const [logInfo, logDispatch] = useReducer(addLogInfo, []); - const [turnCount, setTurnCount] = useState(0); + const [turnCount, setTurnCount] = useState(1); const playerAndScores: PlayerAndScore[] = useMemo(() => { return props.wasm.get_scores(); }, [turnCount]) + useEffect(() => { + logDispatch(

Turn {turnCount}

); + setConfirmedScorePoints(-1); + trayDispatch({action: TileDispatchActionType.RETRIEVE}); + + }, [turnCount]); + + return <>
- +
@@ -143,7 +173,7 @@ export function Game(props: {wasm: GameWasm}) {
- + + }}>{confirmedScorePoints > -1 ? `Score ${confirmedScorePoints} points ✅` : "Check"} ; @@ -205,7 +241,7 @@ export function TileSlot(props: { tile: React.JSX.Element | undefined, location: const startLocation: CoordinateData = JSON.parse(e.dataTransfer.getData("wordGrid/coords")); const thisLocation = props.location; - props.dispatch({start: startLocation, end: thisLocation}); + props.dispatch({action: TileDispatchActionType.MOVE, start: startLocation, end: thisLocation}); } let className = "tileSpot";