Add 'Return Tiles' button
This commit is contained in:
parent
ca5ab097c5
commit
e8cff060b0
2 changed files with 57 additions and 42 deletions
|
@ -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>
|
||||||
</>;
|
</>;
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in a new issue