Add AI tile count and total tile counts, other UI tweaks

This commit is contained in:
Joel Therrien 2023-09-16 21:08:10 -07:00
parent e7c46c8efd
commit 0d30ac0b46
6 changed files with 162 additions and 67 deletions

View file

@ -361,6 +361,23 @@ impl Game {
} }
pub fn get_remaining_tiles(&self) -> usize {
self.tile_pool.len()
}
pub fn get_player_tile_count(&self, player: &str) -> Result<usize, String> {
let tray = match self.player_states.get_tray(&player) {
None => {return Err(format!("Player {} not found", player))}
Some(x) => {x}
};
Ok(
tray.letters.iter()
.filter(|l| l.is_some())
.count()
)
}
} }
#[derive(Serialize, Deserialize, Tsify, Debug)] #[derive(Serialize, Deserialize, Tsify, Debug)]

View file

@ -155,4 +155,25 @@ impl GameWasm {
self.0.current_player_name() self.0.current_player_name()
} }
pub fn get_remaining_tiles(&self) -> usize {
self.0.get_remaining_tiles()
}
pub fn get_player_tile_count(&self, player: &str) -> Result<JsValue, Error> {
match self.0.get_player_tile_count(player) {
Ok(count) => {
Ok(serde_wasm_bindgen::to_value(&MyResult{
response_type: ResponseType::OK,
value: count,
})?)
},
Err(msg) => {
Ok(serde_wasm_bindgen::to_value(&MyResult{
response_type: ResponseType::OK,
value: msg,
})?)
}
}
}
} }

View file

@ -108,7 +108,7 @@ export function Game(props: {
function runAI() { function runAI() {
const result: TurnAdvanceResult = props.wasm.advance_turn(); const result: TurnAdvanceResult = props.wasm.advance_turn();
if(result.type == "AIMove"){ if(result.type == "AIMove"){
handlePlayerAction(result.action, "AI"); handlePlayerAction(result.action, props.settings.aiName);
} else { } else {
// this would be quite surprising // this would be quite surprising
console.error({result}); console.error({result});
@ -179,6 +179,21 @@ export function Game(props: {
} }
}, [logInfo]); }, [logInfo]);
const remainingTiles = useMemo(() => {
return props.wasm.get_remaining_tiles();
}, [turnCount]);
const remainingAITiles = useMemo(() => {
let result = props.wasm.get_player_tile_count(props.settings.aiName) as MyResult<number | String>;
if(result.response_type == "OK") {
return result.value as number;
} else {
console.error(result.value);
return -1;
}
}, [turnCount]);
function handlePlayerAction(action: TurnAction, playerName: string) { function handlePlayerAction(action: TurnAction, playerName: string) {
if (action.type == "PlayTiles"){ if (action.type == "PlayTiles"){
@ -213,9 +228,23 @@ export function Game(props: {
</div> </div>
</div> </div>
</div> </div>
<div className="tray-row">
<div>
<div>
{remainingTiles} letters remaining
</div>
<div>
{props.settings.aiName} has {remainingAITiles} tiles
</div>
<button onClick={() => {
trayDispatch({action: TileDispatchActionType.RETURN}); // want all tiles back on tray for tile exchange
setIsTileExchangeOpen(true);
}}>Open Tile Exchange</button>
</div>
<TileTray letters={playerLetters} trayLength={props.settings.trayLength} dispatch={trayDispatch}/> <TileTray letters={playerLetters} trayLength={props.settings.trayLength} dispatch={trayDispatch}/>
<button onClick={() => { <div className="player-controls">
<button className="check" onClick={() => {
const playedTiles = playerLetters.map((i) => { const playedTiles = playerLetters.map((i) => {
if (i === undefined) { if (i === undefined) {
return null; return null;
@ -265,21 +294,19 @@ export function Game(props: {
}}>{confirmedScorePoints > -1 ? `Score ${confirmedScorePoints} points ✅` : "Check"}</button> }}>{confirmedScorePoints > -1 ? `Score ${confirmedScorePoints} points` : "Check"}</button>
<button <button className="return" onClick={() => {
onClick={() => {
trayDispatch({action: TileDispatchActionType.RETURN}); // want all tiles back on tray for tile exchange
setIsTileExchangeOpen(true);
}}
>Open Tile Exchange</button>
<button onClick={() => {
trayDispatch({action: TileDispatchActionType.RETURN}); trayDispatch({action: TileDispatchActionType.RETURN});
}}>Return Tiles</button> }}>Return Tiles</button>
<button onClick={() => { <button className="pass" onClick={() => {
props.wasm.skip_turn(); props.wasm.skip_turn();
handlePlayerAction({type: "Pass"}, props.settings.playerName); handlePlayerAction({type: "Pass"}, props.settings.playerName);
setTurnCount(turnCount + 1); setTurnCount(turnCount + 1);
}}>Skip Turn</button> }}>Pass</button>
</div>
</div>
</>; </>;
} }

View file

@ -51,6 +51,7 @@ async function run() {
root.render(<Menu dictionary_text={dictionary_text} settings={{ root.render(<Menu dictionary_text={dictionary_text} settings={{
trayLength: 7, trayLength: 7,
playerName: 'Player', playerName: 'Player',
aiName: 'AI',
}}/>); }}/>);

View file

@ -3,6 +3,11 @@
@board-length: 15; @board-length: 15;
@tile-star-size: 45px; @tile-star-size: 45px;
.tray-row {
display: grid;
grid-template-columns: 1fr 1fr 1fr;
width: @board-length*@tile-width;
.tray { .tray {
display: grid; display: grid;
grid-template-columns: repeat(7, @tile-width); grid-template-columns: repeat(7, @tile-width);
@ -13,6 +18,29 @@
margin: 10px; margin: 10px;
} }
.player-controls {
display: grid;
grid-template-areas: "check return"
"check pass";
grid-template-rows: 1fr 1fr;
grid-template-columns: 1fr 1fr;
.check {
grid-area: check;
}
.return {
grid-area: return;
}
.pass {
grid-area: pass;
}
}
}
.board-grid { .board-grid {
//grid-area: grid; //grid-area: grid;
display: grid; display: grid;

View file

@ -1,4 +1,4 @@
import {Letter as LetterData, Letter} from "word_grid"; import {Letter as LetterData, Letter} from "../../pkg/word_grid";
import * as React from "react"; import * as React from "react";
export enum CellType { export enum CellType {
@ -14,6 +14,7 @@ export enum CellType {
export interface Settings { export interface Settings {
trayLength: number; trayLength: number;
playerName: string; playerName: string;
aiName: string;
} }
export enum LocationType { export enum LocationType {