Add support for blank characters

This commit is contained in:
Joel Therrien 2023-08-17 18:30:55 -07:00
parent c61b2e3f75
commit cd8a4b73a9
2 changed files with 91 additions and 16 deletions

View file

@ -1,6 +1,6 @@
import * as React from "react";
import {GameWasm, Letter as LetterData, MyResult, PlayedTile, PlayerAndScore, Tray, WordResult} from "word_grid";
import {JSX, useEffect, useMemo, useReducer, useState} from "react";
import {ChangeEvent, JSX, useEffect, useMemo, useReducer, useState} from "react";
export enum LocationType {
GRID,
@ -75,8 +75,9 @@ function matchCoordinate(playerLetters: PlayableLetterData[], coords: Coordinate
enum TileDispatchActionType {
MOVE,
RETRIEVE,
SET_BLANK,
}
type TileDispatchAction = {action: TileDispatchActionType, start?: CoordinateData, end?: CoordinateData};
type TileDispatchAction = {action: TileDispatchActionType, start?: CoordinateData, end?: CoordinateData, newBlankValue?: string, blankIndex?: number};
type TileDispatch = React.Dispatch<TileDispatchAction>;
function addLogInfo(existingLog: React.JSX.Element[], newItem: React.JSX.Element) {
@ -124,6 +125,15 @@ export function Game(props: {wasm: GameWasm}) {
setConfirmedScorePoints(-1);
return playerLetters.slice();
} if (update.action === TileDispatchActionType.SET_BLANK) {
const blankLetter = playerLetters[update.blankIndex];
if(blankLetter.text !== update.newBlankValue) {
blankLetter.text = update.newBlankValue;
if (blankLetter.location == LocationType.GRID) {
setConfirmedScorePoints(-1);
}
}
return playerLetters.slice();
} else {
console.error("Unknown tray update");
@ -221,7 +231,7 @@ export function Game(props: {wasm: GameWasm}) {
export function TileSlot(props: { tile: React.JSX.Element | undefined, location: CoordinateData, dispatch: TileDispatch }): React.JSX.Element {
export function TileSlot(props: { tile?: React.JSX.Element | undefined, location: CoordinateData, dispatch: TileDispatch }): React.JSX.Element {
let isDraggable = props.tile !== undefined;
function onDragStart(e: React.DragEvent<HTMLDivElement>) {
@ -252,11 +262,51 @@ export function TileSlot(props: { tile: React.JSX.Element | undefined, location:
}
export function Letter(props: { data: LetterData }): React.JSX.Element {
return <div className="letter">
<div className="text">{props.data.text}</div>
<div className="letter-points">{props.data.points}</div>
</div>
export function Letter(props: { data: LetterData, letterUpdater?: (value: string) => void }): React.JSX.Element {
function modifyThisLetter(value:string){
props.letterUpdater(value);
}
function onBlankInput(e: ChangeEvent<HTMLInputElement>){
let value = e.target.value.toUpperCase();
if(value.length > 1){
value = value[value.length - 1];
} else if(value.length == 0){
modifyThisLetter(value);
return;
}
// Now check that it's a letter
let is_letter = value.match("[A-Z]") != null;
if(is_letter){
modifyThisLetter(value);
} else {
// Cancel and do nothing
e.preventDefault();
}
}
if(props.data.is_blank && props.data.ephemeral) {
return <div className="letter">
<input className="blank-input" type="text" onChange={onBlankInput} value={props.data.text} />
<div className="letter-points">{props.data.points}</div>
</div>
} else {
let className = "text";
if (props.data.is_blank) { // not ephemeral
className += " prev-blank";
}
return <div className="letter">
<div className={className}>{props.data.text}</div>
<div className="letter-points">{props.data.points}</div>
</div>
}
}
@ -266,24 +316,28 @@ export function TileTray(props: { letters: Array<PlayableLetterData>, trayLength
for (let i=0; i<props.trayLength; i++) {
elements.push(
<TileSlot
tile={undefined}
key={"empty" + i}
location={{location: LocationType.TRAY, index: i}}
dispatch={props.dispatch} />
);
}
for (let letter of props.letters) {
props.letters.forEach((letter, i) => {
if (letter.location === LocationType.TRAY) {
elements[letter.index] =
<TileSlot
tile={<Letter data={letter} />}
tile={<Letter
data={letter}
letterUpdater={(value) => {
props.dispatch({action: TileDispatchActionType.SET_BLANK, blankIndex: i, newBlankValue: value})
}}
/>}
key={"letter" + letter.index}
location={{location: LocationType.TRAY, index: letter.index}}
dispatch={props.dispatch} />
}
}
});
return (
<div className="tray">
@ -309,7 +363,6 @@ function Grid(props: {
tileElement = <>
<span>{text}</span>
<TileSlot
tile={undefined}
location={{location: LocationType.GRID, index: i}}
dispatch={props.dispatch} /></>;
}
@ -320,7 +373,7 @@ function Grid(props: {
</div>;
});
for (let letter of props.playerLetters) {
props.playerLetters.forEach((letter, i) => {
if (letter.location === LocationType.GRID) {
const ct = props.cellTypes[letter.index];
const {className, text} = cell_type_to_details(ct);
@ -328,14 +381,19 @@ function Grid(props: {
elements[letter.index] =
<div key={"letter" + letter.index} className={"grid-spot " + className}>
<TileSlot
tile={<Letter data={letter} />}
tile={<Letter
data={letter}
letterUpdater={(value) => {
props.dispatch({action: TileDispatchActionType.SET_BLANK, blankIndex: i, newBlankValue: value});
}}
/>}
location={{location: LocationType.GRID, index: letter.index}}
dispatch={props.dispatch} />
</div>;
}
}
});
return <div className="board-grid">
{elements}

View file

@ -105,6 +105,23 @@
padding-right: 5px;
}
input {
position: absolute;
width: 100%;
top: 5px;
text-align: center;
font-size: @tile-font-size;
background: none;
border: none;
padding: 0;
font-style: italic;
left: 0; /* Fixes a weird display bug where the input is shifted to the right when the tile is on the grid */
}
.prev-blank {
font-style: italic;
}
}
.board-log {