Add basic tile exchange support
Still need to support handling if the player reordered their tray
This commit is contained in:
parent
960e8c31fb
commit
ca5ab097c5
3 changed files with 132 additions and 38 deletions
98
src/game.rs
98
src/game.rs
|
@ -47,10 +47,42 @@ pub struct WordResult {
|
|||
score: u32,
|
||||
}
|
||||
|
||||
pub struct PlayerStates(pub Vec<PlayerState>);
|
||||
impl PlayerStates {
|
||||
pub fn get_player_state(&self, name: &str) -> Option<&PlayerState> {
|
||||
self.0.iter()
|
||||
.filter(|state| state.player.get_name().eq(name))
|
||||
.nth(0)
|
||||
|
||||
}
|
||||
|
||||
pub fn get_player_state_mut(&mut self, name: &str) -> Option<&mut PlayerState> {
|
||||
self.0.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.get_player_state_mut(name)?;
|
||||
|
||||
Some(&mut player.tray)
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Game{
|
||||
pub tile_pool: Vec<Letter>,
|
||||
rng: SmallRng,
|
||||
board: Board,
|
||||
pub player_states: Vec<PlayerState>,
|
||||
pub player_states: PlayerStates,
|
||||
dictionary: DictionaryImpl,
|
||||
}
|
||||
|
||||
|
@ -85,39 +117,14 @@ impl Game {
|
|||
|
||||
Game {
|
||||
tile_pool: letters,
|
||||
rng,
|
||||
board: Board::new(),
|
||||
player_states,
|
||||
player_states: PlayerStates(player_states),
|
||||
dictionary: DictionaryImpl::create_from_str(dictionary_text)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_player_state(&self, name: &str) -> Option<&PlayerState> {
|
||||
self.player_states.iter()
|
||||
.filter(|state| state.player.get_name().eq(name))
|
||||
.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.get_player_state_mut(name)?;
|
||||
|
||||
Some(&mut player.tray)
|
||||
|
||||
}
|
||||
|
||||
pub fn get_board(&self) -> &Board {&self.board}
|
||||
|
||||
|
@ -126,7 +133,7 @@ impl Game {
|
|||
}
|
||||
|
||||
pub fn fill_trays(&mut self){
|
||||
for state in self.player_states.iter_mut() {
|
||||
for state in self.player_states.0.iter_mut() {
|
||||
let tray = &mut state.tray;
|
||||
tray.fill(&mut self.tile_pool);
|
||||
}
|
||||
|
@ -139,7 +146,7 @@ impl Game {
|
|||
pub fn receive_play(&mut self, player: &str, tray_tile_locations: Vec<Option<PlayedTile>>, commit_move: bool) -> Result<Vec<WordResult>, String> {
|
||||
|
||||
let mut board_instance = self.get_board().clone();
|
||||
let mut tray = self.get_tray(player).unwrap().clone();
|
||||
let mut tray = self.player_states.get_tray(player).unwrap().clone();
|
||||
|
||||
let mut played_letters: Vec<(Letter, Coordinates)> = Vec::new();
|
||||
for (i, played_tile) in tray_tile_locations.iter().enumerate() {
|
||||
|
@ -181,7 +188,7 @@ impl Game {
|
|||
.collect();
|
||||
|
||||
if commit_move {
|
||||
let mut player_state = self.get_player_state_mut(player).unwrap();
|
||||
let mut player_state = self.player_states.get_player_state_mut(player).unwrap();
|
||||
player_state.score += x.1;
|
||||
player_state.tray = tray;
|
||||
|
||||
|
@ -193,4 +200,33 @@ impl Game {
|
|||
Ok(words)
|
||||
}
|
||||
|
||||
pub fn exchange_tiles(&mut self, player: &str, tray_tile_locations: Vec<bool>) -> Result<Tray, String> {
|
||||
let tray = match self.player_states.get_tray_mut(player) {
|
||||
None => {return Err(format!("Player {} not found", player))}
|
||||
Some(x) => {x}
|
||||
};
|
||||
|
||||
if tray.letters.len() != tray_tile_locations.len() {
|
||||
return Err("Incoming tray and existing tray have different lengths".to_string());
|
||||
}
|
||||
|
||||
let tile_pool = &mut self.tile_pool;
|
||||
|
||||
for (i, played_tile) in tray_tile_locations.iter().enumerate() {
|
||||
if *played_tile {
|
||||
let letter = tray.letters.get_mut(i).unwrap();
|
||||
if letter.is_some() {
|
||||
tile_pool.push(letter.unwrap().clone());
|
||||
*letter = None;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tile_pool.shuffle(&mut self.rng);
|
||||
tray.fill(&mut self.tile_pool);
|
||||
|
||||
Ok(tray.clone())
|
||||
|
||||
}
|
||||
|
||||
}
|
28
src/wasm.rs
28
src/wasm.rs
|
@ -34,7 +34,7 @@ impl GameWasm {
|
|||
}
|
||||
|
||||
pub fn get_tray(&self, name: &str) -> Result<JsValue, Error> {
|
||||
let tray = self.0.get_tray(name);
|
||||
let tray = self.0.player_states.get_tray(name);
|
||||
|
||||
serde_wasm_bindgen::to_value(&tray)
|
||||
}
|
||||
|
@ -91,7 +91,7 @@ impl GameWasm {
|
|||
score: u32,
|
||||
}
|
||||
|
||||
let scores: Vec<PlayerAndScore> = self.0.player_states.iter()
|
||||
let scores: Vec<PlayerAndScore> = self.0.player_states.0.iter()
|
||||
.map(|player_state| {
|
||||
PlayerAndScore {
|
||||
name: player_state.player.get_name().to_string(),
|
||||
|
@ -103,4 +103,28 @@ impl GameWasm {
|
|||
Ok(serde_wasm_bindgen::to_value(&scores)?)
|
||||
|
||||
}
|
||||
|
||||
pub fn exchange_tiles(&mut self, player: &str, tray_tile_locations: JsValue) -> Result<JsValue, Error>{
|
||||
|
||||
let tray_tile_locations: Vec<bool> = serde_wasm_bindgen::from_value(tray_tile_locations)?;
|
||||
|
||||
match self.0.exchange_tiles(player, tray_tile_locations) {
|
||||
Ok(tray) => {
|
||||
serde_wasm_bindgen::to_value(&MyResult {
|
||||
response_type: ResponseType::OK,
|
||||
value: tray
|
||||
})
|
||||
},
|
||||
Err(e) => {
|
||||
serde_wasm_bindgen::to_value(&MyResult {
|
||||
response_type: ResponseType::ERR,
|
||||
value: e
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -211,11 +211,35 @@ export function Game(props: {wasm: GameWasm, settings: Settings}) {
|
|||
}
|
||||
}, [logInfo])
|
||||
|
||||
function exchangeFunction(selectedArray: Array<boolean>) {
|
||||
|
||||
let numSelected = 0;
|
||||
selectedArray.forEach((x) => {
|
||||
if (x){
|
||||
numSelected++;
|
||||
}
|
||||
})
|
||||
|
||||
const result: MyResult<Tray | string> = props.wasm.exchange_tiles("Player", selectedArray);
|
||||
console.log({result});
|
||||
|
||||
if(result.response_type === "ERR") {
|
||||
logDispatch(<div><em>{(result.value as string)}</em></div>);
|
||||
} else {
|
||||
logDispatch(<div><em>You exchanged {numSelected} tiles.</em></div>);
|
||||
setTurnCount(turnCount + 1);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
return <>
|
||||
<TileExchangeModal playerLetters={playerLetters} isOpen={isTileExchangeOpen} setOpen={setIsTileExchangeOpen} />
|
||||
<TileExchangeModal
|
||||
playerLetters={playerLetters}
|
||||
isOpen={isTileExchangeOpen}
|
||||
setOpen={setIsTileExchangeOpen}
|
||||
exchangeFunction={exchangeFunction}
|
||||
/>
|
||||
<div className="board-log">
|
||||
<Grid cellTypes={cellTypes} playerLetters={playerLetters} boardLetters={boardLetters} dispatch={trayDispatch}/>
|
||||
<div className="message-log">
|
||||
|
@ -275,7 +299,9 @@ export function Game(props: {wasm: GameWasm, settings: Settings}) {
|
|||
|
||||
|
||||
}}>{confirmedScorePoints > -1 ? `Score ${confirmedScorePoints} points ✅` : "Check"}</button>
|
||||
<button onClick={(e) => {setIsTileExchangeOpen(true);}}>Open Tile Exchange</button>
|
||||
<button
|
||||
onClick={(e) => {setIsTileExchangeOpen(true);}}
|
||||
>Open Tile Exchange</button>
|
||||
</>;
|
||||
|
||||
|
||||
|
@ -470,7 +496,12 @@ function Scores(props: {playerScores: Array<PlayerAndScore>}){
|
|||
</div>
|
||||
}
|
||||
|
||||
function TileExchangeModal(props: {playerLetters: PlayableLetterData[], isOpen: boolean, setOpen: (isOpen: boolean) => void}) {
|
||||
function TileExchangeModal(props: {
|
||||
playerLetters: PlayableLetterData[],
|
||||
isOpen: boolean,
|
||||
setOpen: (isOpen: boolean) => void,
|
||||
exchangeFunction: (selectedArray: Array<boolean>) => void
|
||||
}) {
|
||||
|
||||
function clearExchangeTiles() {
|
||||
const array: boolean[] = [];
|
||||
|
@ -479,6 +510,9 @@ function TileExchangeModal(props: {playerLetters: PlayableLetterData[], isOpen:
|
|||
}
|
||||
|
||||
const [tilesToExchange, setTilesToExchange] = useState<boolean[]>(clearExchangeTiles);
|
||||
useEffect(() => {
|
||||
setTilesToExchange(clearExchangeTiles());
|
||||
}, [props.playerLetters])
|
||||
|
||||
let tilesExchangedSelected = 0;
|
||||
for (let i of tilesToExchange) {
|
||||
|
@ -518,8 +552,8 @@ function TileExchangeModal(props: {playerLetters: PlayableLetterData[], isOpen:
|
|||
props.setOpen(false);
|
||||
}}>Cancel</button>
|
||||
<button disabled = {tilesExchangedSelected == 0} onClick={(e) => {
|
||||
// TODO exchange code
|
||||
|
||||
props.exchangeFunction(tilesToExchange);
|
||||
props.setOpen(false);
|
||||
}}>Exchange</button>
|
||||
</div>
|
||||
</div>
|
||||
|
|
Loading…
Reference in a new issue