Add 'Return Tiles' button

This commit is contained in:
Joel Therrien 2023-08-23 20:23:58 -07:00
parent ca5ab097c5
commit e8cff060b0
2 changed files with 57 additions and 42 deletions

View file

@ -2,7 +2,7 @@ import * as React from "react";
import {GameWasm, Letter as LetterData, MyResult, PlayedTile, PlayerAndScore, Tray, WordResult} from "word_grid"; import {GameWasm, Letter as LetterData, MyResult, PlayedTile, PlayerAndScore, Tray, WordResult} from "word_grid";
import {ChangeEvent, JSX, useEffect, useMemo, useReducer, useRef, useState} from "react"; import {ChangeEvent, JSX, useEffect, useMemo, useReducer, useRef, useState} from "react";
import {Modal} from "./Modal"; import {Modal} from "./Modal";
import {addNTimes} from "./utils"; import {addNTimes, mergeTrays} from "./utils";
export interface Settings { export interface Settings {
trayLength: number; trayLength: number;
@ -82,6 +82,7 @@ enum TileDispatchActionType {
MOVE, MOVE,
RETRIEVE, RETRIEVE,
SET_BLANK, SET_BLANK,
RETURN,
} }
type TileDispatchAction = {action: TileDispatchActionType, start?: CoordinateData, end?: CoordinateData, newBlankValue?: string, blankIndex?: number}; type TileDispatchAction = {action: TileDispatchActionType, start?: CoordinateData, end?: CoordinateData, newBlankValue?: string, blankIndex?: number};
type TileDispatch = React.Dispatch<TileDispatchAction>; type TileDispatch = React.Dispatch<TileDispatchAction>;
@ -103,49 +104,10 @@ export function Game(props: {wasm: GameWasm, settings: Settings}) {
function movePlayableLetters(playerLetters: PlayableLetterData[], update: TileDispatchAction) { function movePlayableLetters(playerLetters: PlayableLetterData[], update: TileDispatchAction) {
if(update.action === TileDispatchActionType.RETRIEVE) { if(update.action === TileDispatchActionType.RETRIEVE) {
let tray: Tray = props.wasm.get_tray("Player"); let tray: Tray = props.wasm.get_tray("Player");
return mergeTrays(playerLetters, tray.letters);
// we may need to check against the existing tray to retain whatever user reorderings there are
const freeSpots = new Array<number | null>();
for (let i = 0; i<props.settings.trayLength; i++) {
freeSpots.push(i);
}
playerLetters.filter((x) => {
return x !== undefined && x !== null;
}).forEach((x) => {
if (x.location === LocationType.TRAY) {
freeSpots[x.index] = null;
}
});
const firstNotNull = (): number => {
for (let i of freeSpots) {
if (i !== null) {
freeSpots[i] = null;
return i;
}
}
return null;
}
// initial state
let letters: PlayableLetterData[] = tray.letters.map((ld, i) => {
if(ld !== undefined) {
ld["location"] = LocationType.TRAY;
if (playerLetters[i] !== undefined && playerLetters[i] !== null && playerLetters[i].location === LocationType.TRAY) {
ld["index"] = playerLetters[i].index;
} else {
ld["index"] = firstNotNull();
}
}
return ld as PlayableLetterData;
});
return letters;
} else if (update.action === TileDispatchActionType.MOVE) { } else if (update.action === TileDispatchActionType.MOVE) {
let startIndex = matchCoordinate(playerLetters, update.start); let startIndex = matchCoordinate(playerLetters, update.start);
@ -175,6 +137,8 @@ export function Game(props: {wasm: GameWasm, settings: Settings}) {
} }
} }
return playerLetters.slice(); return playerLetters.slice();
} else if (update.action === TileDispatchActionType.RETURN) {
return mergeTrays(playerLetters, playerLetters);
} else { } else {
console.error("Unknown tray update"); console.error("Unknown tray update");
console.error({update}); console.error({update});
@ -182,6 +146,8 @@ export function Game(props: {wasm: GameWasm, settings: Settings}) {
} }
const [playerLetters, trayDispatch] = useReducer(movePlayableLetters, []); const [playerLetters, trayDispatch] = useReducer(movePlayableLetters, []);
const [logInfo, logDispatch] = useReducer(addLogInfo, []); const [logInfo, logDispatch] = useReducer(addLogInfo, []);
@ -302,6 +268,9 @@ export function Game(props: {wasm: GameWasm, settings: Settings}) {
<button <button
onClick={(e) => {setIsTileExchangeOpen(true);}} onClick={(e) => {setIsTileExchangeOpen(true);}}
>Open Tile Exchange</button> >Open Tile Exchange</button>
<button onClick={(e) => {
trayDispatch({action: TileDispatchActionType.RETURN});
}}>Return Tiles</button>
</>; </>;

View file

@ -1,6 +1,52 @@
import {Letter} from "word_grid";
import {LocationType, PlayableLetterData} from "./elements";
export function addNTimes<T>(array: T[], toAdd: T, times: number) { export function addNTimes<T>(array: T[], toAdd: T, times: number) {
for (let i=0; i<times; i++) { for (let i=0; i<times; i++) {
array.push(toAdd); array.push(toAdd);
} }
} }
export function mergeTrays(existing: PlayableLetterData[], newer: (Letter | undefined)[]): PlayableLetterData[] {
let trayLength = Math.max(existing.length, newer.length);
// we may need to check against the existing tray to retain whatever user reorderings there are
const freeSpots = new Array<number | null>();
for (let i = 0; i<trayLength; i++) {
freeSpots.push(i);
}
existing.filter((x) => {
return x !== undefined && x !== null;
}).forEach((x) => {
if (x.location === LocationType.TRAY) {
freeSpots[x.index] = null;
}
});
const firstNotNull = (): number => {
for (let i of freeSpots) {
if (i !== null) {
freeSpots[i] = null;
return i;
}
}
return null;
}
return newer.map((ld, i) => {
if (ld !== undefined) {
if (existing[i] !== undefined && existing[i] !== null && existing[i].location === LocationType.TRAY) {
ld["index"] = existing[i].index;
} else {
ld["index"] = firstNotNull();
}
ld["location"] = LocationType.TRAY;
}
return ld as PlayableLetterData;
});
}