Add arrow for fast play
This commit is contained in:
parent
a34ad8cd12
commit
2fa28ce3d4
4 changed files with 234 additions and 54 deletions
165
ui/src/Game.tsx
165
ui/src/Game.tsx
|
@ -1,15 +1,22 @@
|
||||||
import * as React from "react";
|
import * as React from "react";
|
||||||
|
import {useEffect, useMemo, useReducer, useRef, useState} from "react";
|
||||||
import {
|
import {
|
||||||
GameState,
|
GameState,
|
||||||
GameWasm, Letter,
|
GameWasm,
|
||||||
Letter as LetterData,
|
|
||||||
MyResult,
|
MyResult,
|
||||||
PlayedTile,
|
PlayedTile,
|
||||||
PlayerAndScore,
|
PlayerAndScore,
|
||||||
ScoreResult,
|
ScoreResult,
|
||||||
Tray, TurnAction, TurnAdvanceResult
|
Tray,
|
||||||
|
TurnAction,
|
||||||
|
TurnAdvanceResult
|
||||||
} from "../../pkg/word_grid";
|
} from "../../pkg/word_grid";
|
||||||
import {
|
import {
|
||||||
|
Direction,
|
||||||
|
GRID_LENGTH,
|
||||||
|
GridArrowData,
|
||||||
|
GridArrowDispatchAction,
|
||||||
|
GridArrowDispatchActionType,
|
||||||
HighlightableLetterData,
|
HighlightableLetterData,
|
||||||
LocationType,
|
LocationType,
|
||||||
matchCoordinate,
|
matchCoordinate,
|
||||||
|
@ -19,7 +26,6 @@ import {
|
||||||
TileDispatchAction,
|
TileDispatchAction,
|
||||||
TileDispatchActionType
|
TileDispatchActionType
|
||||||
} from "./utils";
|
} from "./utils";
|
||||||
import {useEffect, useMemo, useReducer, useRef, useState} from "react";
|
|
||||||
import {TileExchangeModal} from "./TileExchange";
|
import {TileExchangeModal} from "./TileExchange";
|
||||||
import {Grid, Scores, TileTray} from "./UI";
|
import {Grid, Scores, TileTray} from "./UI";
|
||||||
|
|
||||||
|
@ -42,6 +48,94 @@ export function Game(props: {
|
||||||
const [isGameOver, setGameOver] = useState<boolean>(false);
|
const [isGameOver, setGameOver] = useState<boolean>(false);
|
||||||
const [confirmedScorePoints, setConfirmedScorePoints] = useState<number>(-1);
|
const [confirmedScorePoints, setConfirmedScorePoints] = useState<number>(-1);
|
||||||
|
|
||||||
|
const [boardLetters, setBoardLetters] = useState<HighlightableLetterData[]>(() => {
|
||||||
|
const newLetterData = [] as HighlightableLetterData[];
|
||||||
|
for(let i=0; i<GRID_LENGTH * GRID_LENGTH; i++) {
|
||||||
|
newLetterData.push(undefined);
|
||||||
|
}
|
||||||
|
return newLetterData;
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
function adjustGridArrow(existing: GridArrowData, update: GridArrowDispatchAction): GridArrowData {
|
||||||
|
console.log({update});
|
||||||
|
|
||||||
|
if(update.action == GridArrowDispatchActionType.CLEAR) {
|
||||||
|
return null;
|
||||||
|
} else if (update.action == GridArrowDispatchActionType.CYCLE) {
|
||||||
|
// if there's nothing where the user clicked, we create a right arrow.
|
||||||
|
if(existing == null || existing.position != update.position) {
|
||||||
|
return {
|
||||||
|
direction: Direction.RIGHT, position: update.position
|
||||||
|
}
|
||||||
|
// if there's a right arrow, we shift to downwards
|
||||||
|
} else if(existing.direction == Direction.RIGHT) {
|
||||||
|
return {
|
||||||
|
direction: Direction.DOWN, position: existing.position
|
||||||
|
}
|
||||||
|
// if there's a down arrow, we clear it
|
||||||
|
} else if (existing.direction == Direction.DOWN){
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
} else if (update.action == GridArrowDispatchActionType.SHIFT) {
|
||||||
|
if(existing == null) {
|
||||||
|
// no arrow to shift
|
||||||
|
return null;
|
||||||
|
} else {
|
||||||
|
let current_x = existing.position % GRID_LENGTH;
|
||||||
|
let current_y = Math.floor(existing.position / GRID_LENGTH);
|
||||||
|
|
||||||
|
// we loop because we want to skip over letters that are already set
|
||||||
|
while (current_x < GRID_LENGTH && current_y < GRID_LENGTH) {
|
||||||
|
if(existing.direction == Direction.RIGHT) {
|
||||||
|
current_x += 1;
|
||||||
|
} else {
|
||||||
|
current_y += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
const new_position = current_x + current_y * GRID_LENGTH;
|
||||||
|
if(current_x < GRID_LENGTH && current_y < GRID_LENGTH && boardLetters[new_position] == null) {
|
||||||
|
return {
|
||||||
|
direction: existing.direction,
|
||||||
|
position: new_position,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// if we reached this point without returning then we went off the board, remove arrow
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function exchangeFunction(selectedArray: Array<boolean>) {
|
||||||
|
|
||||||
|
const result: MyResult<TurnAction | string> = props.wasm.exchange_tiles(selectedArray);
|
||||||
|
|
||||||
|
if(result.response_type === "ERR") {
|
||||||
|
logDispatch(<div><em>{(result.value as string)}</em></div>);
|
||||||
|
} else {
|
||||||
|
handlePlayerAction(result.value as TurnAction, props.settings.playerName);
|
||||||
|
setTurnCount(turnCount + 1);
|
||||||
|
|
||||||
|
if(result.game_state.type === "Ended") {
|
||||||
|
endGame(result.game_state);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function addWordFn(word: string) {
|
||||||
|
props.wasm.add_word(word);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const [gridArrow, gridArrowDispatch] = useReducer(adjustGridArrow, null);
|
||||||
|
const [logInfo, logDispatch] = useReducer(addLogInfo, []);
|
||||||
|
|
||||||
|
|
||||||
function movePlayableLetters(playerLetters: PlayableLetterData[], update: TileDispatchAction) {
|
function movePlayableLetters(playerLetters: PlayableLetterData[], update: TileDispatchAction) {
|
||||||
|
|
||||||
if(update.action === TileDispatchActionType.RETRIEVE) {
|
if(update.action === TileDispatchActionType.RETRIEVE) {
|
||||||
|
@ -79,7 +173,26 @@ export function Game(props: {
|
||||||
}
|
}
|
||||||
return playerLetters.slice();
|
return playerLetters.slice();
|
||||||
} else if (update.action === TileDispatchActionType.RETURN) {
|
} else if (update.action === TileDispatchActionType.RETURN) {
|
||||||
|
gridArrowDispatch({action: GridArrowDispatchActionType.CLEAR});
|
||||||
return mergeTrays(playerLetters, playerLetters);
|
return mergeTrays(playerLetters, playerLetters);
|
||||||
|
} else if (update.action === TileDispatchActionType.MOVE_TO_ARROW) {
|
||||||
|
// let's verify that the arrow is defined, otherwise do nothing
|
||||||
|
if(gridArrow != null) {
|
||||||
|
const end_position = {
|
||||||
|
location: LocationType.GRID,
|
||||||
|
index: gridArrow.position,
|
||||||
|
};
|
||||||
|
gridArrowDispatch({
|
||||||
|
action: GridArrowDispatchActionType.SHIFT,
|
||||||
|
});
|
||||||
|
return movePlayableLetters(playerLetters, {
|
||||||
|
action: TileDispatchActionType.MOVE,
|
||||||
|
start: update.start,
|
||||||
|
end: end_position,
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
return playerLetters;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
console.error("Unknown tray update");
|
console.error("Unknown tray update");
|
||||||
console.error({update});
|
console.error({update});
|
||||||
|
@ -87,44 +200,14 @@ export function Game(props: {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function exchangeFunction(selectedArray: Array<boolean>) {
|
|
||||||
|
|
||||||
const result: MyResult<TurnAction | string> = props.wasm.exchange_tiles(selectedArray);
|
|
||||||
|
|
||||||
if(result.response_type === "ERR") {
|
|
||||||
logDispatch(<div><em>{(result.value as string)}</em></div>);
|
|
||||||
} else {
|
|
||||||
handlePlayerAction(result.value as TurnAction, props.settings.playerName);
|
|
||||||
setTurnCount(turnCount + 1);
|
|
||||||
|
|
||||||
if(result.game_state.type === "Ended") {
|
|
||||||
endGame(result.game_state);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
function addWordFn(word: string) {
|
|
||||||
props.wasm.add_word(word);
|
|
||||||
}
|
|
||||||
|
|
||||||
const [playerLetters, trayDispatch] = useReducer(movePlayableLetters, []);
|
const [playerLetters, trayDispatch] = useReducer(movePlayableLetters, []);
|
||||||
const [logInfo, logDispatch] = useReducer(addLogInfo, []);
|
|
||||||
|
|
||||||
const [turnCount, setTurnCount] = useState<number>(1);
|
const [turnCount, setTurnCount] = useState<number>(1);
|
||||||
const playerAndScores: PlayerAndScore[] = useMemo(() => {
|
const playerAndScores: PlayerAndScore[] = useMemo(() => {
|
||||||
return props.wasm.get_scores();
|
return props.wasm.get_scores();
|
||||||
}, [turnCount, isGameOver]);
|
}, [turnCount, isGameOver]);
|
||||||
|
|
||||||
const [boardLetters, setBoardLetters] = useState<HighlightableLetterData[]>(() => {
|
|
||||||
const newLetterData = [] as HighlightableLetterData[];
|
|
||||||
for(let i=0; i<15*15; i++) {
|
|
||||||
newLetterData.push(undefined);
|
|
||||||
}
|
|
||||||
return newLetterData;
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const newLetterData = props.wasm.get_board_letters() as HighlightableLetterData[];
|
const newLetterData = props.wasm.get_board_letters() as HighlightableLetterData[];
|
||||||
|
@ -188,6 +271,9 @@ export function Game(props: {
|
||||||
else if(action.type == "Pass"){
|
else if(action.type == "Pass"){
|
||||||
logDispatch(<div>{playerName} passed.</div>);
|
logDispatch(<div>{playerName} passed.</div>);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Clear any on-screen arrows
|
||||||
|
gridArrowDispatch({action: GridArrowDispatchActionType.CLEAR});
|
||||||
}
|
}
|
||||||
|
|
||||||
function endGame(state: GameState) {
|
function endGame(state: GameState) {
|
||||||
|
@ -303,7 +389,14 @@ export function Game(props: {
|
||||||
exchangeFunction={exchangeFunction}
|
exchangeFunction={exchangeFunction}
|
||||||
/>
|
/>
|
||||||
<div className="board-log">
|
<div className="board-log">
|
||||||
<Grid cellTypes={cellTypes} playerLetters={playerLetters} boardLetters={boardLetters} dispatch={trayDispatch}/>
|
<Grid
|
||||||
|
cellTypes={cellTypes}
|
||||||
|
playerLetters={playerLetters}
|
||||||
|
boardLetters={boardLetters}
|
||||||
|
tileDispatch={trayDispatch}
|
||||||
|
arrow={gridArrow}
|
||||||
|
arrowDispatch={gridArrowDispatch}
|
||||||
|
/>
|
||||||
<div className="message-log">
|
<div className="message-log">
|
||||||
<button className="end-game"
|
<button className="end-game"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
|
@ -334,7 +427,7 @@ export function Game(props: {
|
||||||
}}>Open Tile Exchange</button>
|
}}>Open Tile Exchange</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<TileTray letters={playerLetters} trayLength={props.settings.trayLength} dispatch={trayDispatch}/>
|
<TileTray letters={playerLetters} trayLength={props.settings.trayLength} trayDispatch={trayDispatch}/>
|
||||||
<div className="player-controls">
|
<div className="player-controls">
|
||||||
<button className="check" onClick={() => {
|
<button className="check" onClick={() => {
|
||||||
const playedTiles = playerLetters.map((i) => {
|
const playedTiles = playerLetters.map((i) => {
|
||||||
|
|
|
@ -1,16 +1,27 @@
|
||||||
import * as React from "react";
|
import * as React from "react";
|
||||||
import {Letter as LetterData, PlayerAndScore} from "word_grid";
|
|
||||||
import {ChangeEvent, JSX} from "react";
|
import {ChangeEvent, JSX} from "react";
|
||||||
|
import {PlayerAndScore} from "word_grid";
|
||||||
import {
|
import {
|
||||||
cellTypeToDetails,
|
|
||||||
CellType,
|
CellType,
|
||||||
|
cellTypeToDetails,
|
||||||
|
CoordinateData,
|
||||||
|
GridArrowData,
|
||||||
|
GridArrowDispatch,
|
||||||
|
GridArrowDispatchActionType,
|
||||||
|
HighlightableLetterData,
|
||||||
LocationType,
|
LocationType,
|
||||||
PlayableLetterData,
|
PlayableLetterData,
|
||||||
CoordinateData, TileDispatchActionType, TileDispatch, HighlightableLetterData,
|
TileDispatch,
|
||||||
|
TileDispatchActionType,
|
||||||
} from "./utils";
|
} from "./utils";
|
||||||
|
|
||||||
|
|
||||||
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,
|
||||||
|
tileDispatch: TileDispatch,
|
||||||
|
arrowDispatch?: GridArrowDispatch,
|
||||||
|
}): React.JSX.Element {
|
||||||
let isDraggable = props.tile !== undefined;
|
let isDraggable = props.tile !== undefined;
|
||||||
|
|
||||||
function onDragStart(e: React.DragEvent<HTMLDivElement>) {
|
function onDragStart(e: React.DragEvent<HTMLDivElement>) {
|
||||||
|
@ -22,7 +33,7 @@ export function TileSlot(props: { tile?: React.JSX.Element | undefined, location
|
||||||
const startLocation: CoordinateData = JSON.parse(e.dataTransfer.getData("wordGrid/coords"));
|
const startLocation: CoordinateData = JSON.parse(e.dataTransfer.getData("wordGrid/coords"));
|
||||||
const thisLocation = props.location;
|
const thisLocation = props.location;
|
||||||
|
|
||||||
props.dispatch({action: TileDispatchActionType.MOVE, start: startLocation, end: thisLocation});
|
props.tileDispatch({action: TileDispatchActionType.MOVE, start: startLocation, end: thisLocation});
|
||||||
}
|
}
|
||||||
|
|
||||||
let className = "tileSpot";
|
let className = "tileSpot";
|
||||||
|
@ -30,10 +41,24 @@ export function TileSlot(props: { tile?: React.JSX.Element | undefined, location
|
||||||
className += " ephemeral";
|
className += " ephemeral";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let onClick: () => void;
|
||||||
|
if(props.arrowDispatch != null && props.location.location == LocationType.GRID) {
|
||||||
|
onClick = () => {
|
||||||
|
props.arrowDispatch({action: GridArrowDispatchActionType.CYCLE, position: props.location.index});
|
||||||
|
}
|
||||||
|
} else if(props.location.location == LocationType.TRAY && props.tile != null && props.tile.props.data.text != ' ' && props.tile.props.data.text != '') {
|
||||||
|
onClick = () => {
|
||||||
|
props.tileDispatch({
|
||||||
|
action: TileDispatchActionType.MOVE_TO_ARROW, end: undefined, start: props.location,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return <div className={className}
|
return <div className={className}
|
||||||
draggable={isDraggable}
|
draggable={isDraggable}
|
||||||
onDragStart={onDragStart}
|
onDragStart={onDragStart}
|
||||||
onDrop={onDrop}
|
onDrop={onDrop}
|
||||||
|
onClick={onClick}
|
||||||
onDragOver={(e) => {e.preventDefault()}}
|
onDragOver={(e) => {e.preventDefault()}}
|
||||||
>
|
>
|
||||||
{props.tile}
|
{props.tile}
|
||||||
|
@ -92,7 +117,7 @@ export function Letter(props: { data: HighlightableLetterData, letterUpdater?: (
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function TileTray(props: { letters: Array<PlayableLetterData>, trayLength: number, dispatch: TileDispatch }): React.JSX.Element {
|
export function TileTray(props: { letters: Array<PlayableLetterData>, trayLength: number, trayDispatch: TileDispatch }): React.JSX.Element {
|
||||||
|
|
||||||
let elements: JSX.Element[] = [];
|
let elements: JSX.Element[] = [];
|
||||||
for (let i=0; i<props.trayLength; i++) {
|
for (let i=0; i<props.trayLength; i++) {
|
||||||
|
@ -100,7 +125,7 @@ export function TileTray(props: { letters: Array<PlayableLetterData>, trayLength
|
||||||
<TileSlot
|
<TileSlot
|
||||||
key={"empty" + i}
|
key={"empty" + i}
|
||||||
location={{location: LocationType.TRAY, index: i}}
|
location={{location: LocationType.TRAY, index: i}}
|
||||||
dispatch={props.dispatch} />
|
tileDispatch={props.trayDispatch} />
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -111,14 +136,14 @@ export function TileTray(props: { letters: Array<PlayableLetterData>, trayLength
|
||||||
elements[letter.index] =
|
elements[letter.index] =
|
||||||
<TileSlot
|
<TileSlot
|
||||||
tile={<Letter
|
tile={<Letter
|
||||||
data={letter}
|
data={{...letter, highlight: false}}
|
||||||
letterUpdater={(value) => {
|
letterUpdater={(value) => {
|
||||||
props.dispatch({action: TileDispatchActionType.SET_BLANK, blankIndex: i, newBlankValue: value})
|
props.trayDispatch({action: TileDispatchActionType.SET_BLANK, blankIndex: i, newBlankValue: value})
|
||||||
}}
|
}}
|
||||||
/>}
|
/>}
|
||||||
key={"letter" + letter.index}
|
key={"letter" + letter.index}
|
||||||
location={{location: LocationType.TRAY, index: letter.index}}
|
location={{location: LocationType.TRAY, index: letter.index}}
|
||||||
dispatch={props.dispatch} />
|
tileDispatch={props.trayDispatch} />
|
||||||
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -131,11 +156,27 @@ export function TileTray(props: { letters: Array<PlayableLetterData>, trayLength
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function Arrow(props: {
|
||||||
|
data: GridArrowData,
|
||||||
|
dispatch: GridArrowDispatch,
|
||||||
|
}) {
|
||||||
|
|
||||||
|
return <div
|
||||||
|
className={`arrow ${props.data.direction}`}
|
||||||
|
>
|
||||||
|
➡
|
||||||
|
</div>;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
export function Grid(props: {
|
export function Grid(props: {
|
||||||
cellTypes: CellType[],
|
cellTypes: CellType[],
|
||||||
playerLetters: Array<PlayableLetterData>,
|
playerLetters: Array<PlayableLetterData>,
|
||||||
boardLetters: HighlightableLetterData[],
|
boardLetters: HighlightableLetterData[],
|
||||||
dispatch: TileDispatch}) {
|
tileDispatch: TileDispatch,
|
||||||
|
arrow: GridArrowData,
|
||||||
|
arrowDispatch: GridArrowDispatch,
|
||||||
|
}) {
|
||||||
|
|
||||||
const elements = props.cellTypes.map((ct, i) => {
|
const elements = props.cellTypes.map((ct, i) => {
|
||||||
const {className, text} = cellTypeToDetails(ct);
|
const {className, text} = cellTypeToDetails(ct);
|
||||||
|
@ -147,13 +188,22 @@ export function Grid(props: {
|
||||||
tileElement = <>
|
tileElement = <>
|
||||||
<span>{text}</span>
|
<span>{text}</span>
|
||||||
<TileSlot
|
<TileSlot
|
||||||
location={{location: LocationType.GRID, index: i}}
|
location={{location: LocationType.GRID, index: i}}
|
||||||
dispatch={props.dispatch} /></>;
|
tileDispatch={props.tileDispatch}
|
||||||
|
arrowDispatch={props.arrowDispatch}
|
||||||
|
/>
|
||||||
|
|
||||||
|
</>;
|
||||||
|
}
|
||||||
|
|
||||||
|
let arrowElement: JSX.Element;
|
||||||
|
if(props.arrow != null && props.arrow.position == i) {
|
||||||
|
arrowElement = <Arrow data={props.arrow} dispatch={props.arrowDispatch} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
return <div key={i} className={"grid-spot " + className}>
|
return <div key={i} className={"grid-spot " + className}>
|
||||||
|
|
||||||
{tileElement}
|
{tileElement}
|
||||||
|
{arrowElement}
|
||||||
</div>;
|
</div>;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -168,13 +218,13 @@ export function Grid(props: {
|
||||||
<div key={"letter" + letter.index} className={"grid-spot " + className}>
|
<div key={"letter" + letter.index} className={"grid-spot " + className}>
|
||||||
<TileSlot
|
<TileSlot
|
||||||
tile={<Letter
|
tile={<Letter
|
||||||
data={letter}
|
data={{...letter, highlight: false}}
|
||||||
letterUpdater={(value) => {
|
letterUpdater={(value) => {
|
||||||
props.dispatch({action: TileDispatchActionType.SET_BLANK, blankIndex: i, newBlankValue: value});
|
props.tileDispatch({action: TileDispatchActionType.SET_BLANK, blankIndex: i, newBlankValue: value});
|
||||||
}}
|
}}
|
||||||
/>}
|
/>}
|
||||||
location={{location: LocationType.GRID, index: letter.index}}
|
location={{location: LocationType.GRID, index: letter.index}}
|
||||||
dispatch={props.dispatch} />
|
tileDispatch={props.tileDispatch} />
|
||||||
</div>;
|
</div>;
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -67,9 +67,23 @@
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 0;
|
top: 0;
|
||||||
left: 0;
|
left: 0;
|
||||||
|
z-index: 2;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
.arrow {
|
||||||
|
color: red;
|
||||||
|
font-size: @tile-font-size+10;
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 10px;
|
||||||
z-index: 1;
|
z-index: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.down {
|
||||||
|
transform: rotate(90deg);
|
||||||
|
}
|
||||||
|
|
||||||
.ephemeral {
|
.ephemeral {
|
||||||
opacity: 75%;
|
opacity: 75%;
|
||||||
}
|
}
|
||||||
|
@ -108,6 +122,8 @@
|
||||||
.tileSpot {
|
.tileSpot {
|
||||||
height: @tile-width;
|
height: @tile-width;
|
||||||
width: @tile-width;
|
width: @tile-width;
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.letter {
|
.letter {
|
||||||
|
|
|
@ -35,10 +35,29 @@ export enum TileDispatchActionType {
|
||||||
RETRIEVE,
|
RETRIEVE,
|
||||||
SET_BLANK,
|
SET_BLANK,
|
||||||
RETURN,
|
RETURN,
|
||||||
|
MOVE_TO_ARROW,
|
||||||
}
|
}
|
||||||
export type TileDispatchAction = {action: TileDispatchActionType, start?: CoordinateData, end?: CoordinateData, newBlankValue?: string, blankIndex?: number};
|
export type TileDispatchAction = {action: TileDispatchActionType, start?: CoordinateData, end?: CoordinateData, newBlankValue?: string, blankIndex?: number};
|
||||||
export type TileDispatch = React.Dispatch<TileDispatchAction>;
|
export type TileDispatch = React.Dispatch<TileDispatchAction>;
|
||||||
|
|
||||||
|
export enum Direction {
|
||||||
|
RIGHT = "right",
|
||||||
|
DOWN = "down",
|
||||||
|
}
|
||||||
|
export interface GridArrowData {
|
||||||
|
direction: Direction,
|
||||||
|
position: number,
|
||||||
|
}
|
||||||
|
|
||||||
|
export enum GridArrowDispatchActionType {
|
||||||
|
CLEAR,
|
||||||
|
CYCLE,
|
||||||
|
SHIFT,
|
||||||
|
}
|
||||||
|
|
||||||
|
export type GridArrowDispatchAction = {action: GridArrowDispatchActionType, position?: number};
|
||||||
|
export type GridArrowDispatch = React.Dispatch<GridArrowDispatchAction>;
|
||||||
|
|
||||||
export function matchCoordinate(playerLetters: PlayableLetterData[], coords: CoordinateData): number {
|
export function matchCoordinate(playerLetters: PlayableLetterData[], coords: CoordinateData): number {
|
||||||
|
|
||||||
for (let i=0; i<playerLetters.length; i++){
|
for (let i=0; i<playerLetters.length; i++){
|
||||||
|
@ -136,4 +155,6 @@ export function mergeTrays(existing: PlayableLetterData[], newer: (Letter | unde
|
||||||
return ld as PlayableLetterData;
|
return ld as PlayableLetterData;
|
||||||
});
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const GRID_LENGTH = 15;
|
Loading…
Reference in a new issue