Skip to content

Commit

Permalink
WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
neelkapse committed Jun 15, 2023
1 parent 7ac89a5 commit 1640d57
Show file tree
Hide file tree
Showing 10 changed files with 129 additions and 60 deletions.
2 changes: 2 additions & 0 deletions js/frontend/components/game-online/GameOnline.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ const GameOnline = ({ uid, game }: { uid: string | null; game: Game }) => {
const boardCentered = useGameSelector(selectBoardCentered);
const { authToken } = usePlayer();

console.log(ghosts);

// TODO: Neel: probably not the right place to do this
useEffect(() => dispatch(authTokenAdded(authToken)));

Expand Down
19 changes: 13 additions & 6 deletions js/frontend/pages/game/[gameid].tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { useRouter } from 'next/router';
import { useEffect, useState } from 'react';
import { Provider } from 'react-redux';
import { Game, usePlayer } from 'hive-db';
import { Game, usePlayer, getGame, newGameFromBackendGame } from 'hive-db';
import { GameOnline } from '../../components/game-online/GameOnline';
import { GameOnlineSidebar } from '../../components/game-online/GameOnlineSidebar';
import { NavBar } from '../../components/nav/NavBar';
Expand Down Expand Up @@ -62,10 +62,13 @@ const Game = () => {

useEffect(() => {
// TODO: should this be a strict type check while enforcing that gameid is a string?
setGame(activeGames.find((g) => g.gid == gameid));
}, [activeGames, gameid]);

console.log(game);
if (gameid) {
getGame(gameid).then((game) => {
console.log(game);
setGame(newGameFromBackendGame(game));
});
}
}, [gameid]);

return (
<>
Expand All @@ -75,7 +78,11 @@ const Game = () => {
<NavBar fullWidth className='border-b' />
<div className='relative w-full h-full overflow-hidden'>
<Provider store={store}>
{game ? <GameView uid={user.uid} game={game} /> : 'Loading...'}
{game && user ? (
<GameView uid={user.uid} game={game} />
) : (
'Loading...'
)}
</Provider>
</div>
</>
Expand Down
6 changes: 4 additions & 2 deletions js/frontend/state/game-online/selectors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ export const selectGame = (state: GameState): Game | null => state.game;
/**
* Get the set of valid next moves
*/
export const selectValidMoves = (state: GameState): Move[] | null =>
export const selectValidMoves = (state: GameState): PossibleMove[] | null =>
state.validNextMoves;

/**
Expand Down Expand Up @@ -143,7 +143,9 @@ export const selectGameBoard = createSelector(
*/
export const selectDisplayGameBoard = createSelector(
[selectDisplayMoves, selectDisplayUpTo],
(moves, upTo): GameBoard => buildBoard(moves, upTo)
(moves, upTo): GameBoard => {
return buildBoard(moves, upTo);
}
);

/**
Expand Down
10 changes: 9 additions & 1 deletion js/frontend/state/game-online/slice.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,15 @@ const slice = createSlice({
if (oldNotation !== newNotation && state.upTo !== -1) {
state.newMovesToView = true;
}
// TODO: Neel: populate this from game.validMoves and game.validSpawns
let validNextMoves = [];
for (const move of game.validMoves) {
validNextMoves.push(move);
}
for (const spawn of game.validSpawns) {
validNextMoves.push(spawn);
}
state.validNextMoves = validNextMoves;
}
state.game = game;
state.proposedMove = null;
Expand All @@ -60,7 +69,6 @@ const slice = createSlice({
if (game.state.moveCount === 0) {
// The first move is being played
state.selectedTileId = null;
console.log(state.authToken);
playGameMove(game, state.proposedMove, state.authToken)
.then(({ game, validNextMoves }) => {
state.game = game;
Expand Down
52 changes: 48 additions & 4 deletions js/hive-db/src/game/game.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { ColorKey, GameOptions } from 'hive-lib';
import type { ColorKey, GameOptions, HexCoordinate } from 'hive-lib';
import type { GameMeta } from './meta';
import type { GamePlayers } from './players';
import type { GameState } from './state';
Expand All @@ -23,16 +23,23 @@ export interface BackendGame {
ranked: boolean;
tournament_queen_rule: boolean;
turn: number;
moves: string;
spawns: HexCoordinate[];
}

export interface Game {
export interface GameOverview {
gid: string;
meta: GameMeta;
options: GameOptions;
players: GamePlayers;
state: GameState;
}

export type Game = GameOverview & {
validMoves: string[];
validSpawns: string[];
};

/**
* Create a new game object.
*
Expand All @@ -46,7 +53,7 @@ export function newGame(
players: GamePlayers,
options: GameOptions,
isPublic: boolean
): Game {
): OverviewGame {
return {
gid: '',
options,
Expand Down Expand Up @@ -158,6 +165,35 @@ function getStateFromBackendGame(backendGame: BackendGame): GameState {
return newGameState(backendGame.history);
}

function getValidMovesFromBackendGame(
backendGame: BackendGame
): PossibleMove[] {
console.log(backendGame.moves);
return backendGame.moves;
}wekj

function convertReserveToPieceSymbol(colorSymbol: string, pieceName: string, reserveSize: number): string {
const pieceNumber = reserveSize
return colorSymbol + pieceName[0].toUpperCase() + ;

function getValidSpawnsFromBackendGame(
backendGame: BackendGame
): PossibleMove[] {
const reserve = backendGame.turn % 2 == 0 ? backendGame.reserve_white : backendGame.reserve_black;
const colorSymbol = backendGame.turn % 2 == 0 ? 'w' : 'b';
const spawnablePieces = [];
for (let [key, value] of reserve) {
if (value === 0)
continue;
spawnablePieces.push(convertReserveToPieceSymbol(colorSymbol, key, value))
console.log(key + ' = ' + value);
}
for (const spawn of backendGame.spawns) {
console.log(spawn);
}
return backendGame.spawns;
}

/**
* Create a new game object from the backend's representation of a game.
*
Expand All @@ -172,13 +208,17 @@ export function newGameFromBackendGame(backendGame: BackendGame): Game {
const players = getPlayersFromBackendGame(backendGame);
const meta = getMetaFromBackendGame(backendGame);
const state = getStateFromBackendGame(backendGame);
const validMoves = getValidMovesFromBackendGame(backendGame);
const validSpawns = getValidSpawnsFromBackendGame(backendGame);

return {
gid: backendGame.id,
options,
players,
meta,
state
state,
validMoves,
validSpawns
};
}

Expand Down Expand Up @@ -216,6 +256,10 @@ export function getUserGames(user: UserData): Promise<Game[]> {
});
}

export function getGame(uid: string): Promise<Game[]> {
return getJSON<Game[]>(`/api/game/${uid}`);
}

/**
* Create a new partial game object, allowing for FieldValue objects to be used
* as field values. Objects created using this method can be used in Firestore
Expand Down
1 change: 0 additions & 1 deletion js/hive-db/src/game/state.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ export interface GameState {
export const newGameState = (notation?: string): GameState => {
if (!notation) notation = '';
const moves = getGameMoves(notation);
console.log(moves);
return {
notation: notation,
turn: moves.length % 2 === 0 ? 'w' : 'b',
Expand Down
2 changes: 0 additions & 2 deletions js/hive-lib/src/board.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,6 @@ export function buildBoard(moves: Move[], upTo?: number): GameBoard {
// Extract the data we need from the move object
const { tileId, refId, dir } = move;

console.log(draft);

if (isEmpty(draft)) {
// The first tile placed on the board is always at (0, 0)
_placeTile(draft, tileId, { q: 0, r: 0 });
Expand Down
2 changes: 1 addition & 1 deletion js/hive-lib/src/notation.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ describe('notation parsing', () => {
});

describe('_parseMoveNotation', () => {
test('undefined move', () => expect(_parseMoveNotation()).toBeUndefined());
// test('undefined move', () => expect(_parseMoveNotation()).toBeUndefined());
test('passing move', () =>
expect(_parseMoveNotation('x')).toEqual({
notation: 'x',
Expand Down
89 changes: 46 additions & 43 deletions js/hive-lib/src/notation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,12 +53,8 @@ export function buildMoveNotation(
* @return An array of *Move* objects.
*/
export function getGameMoves(notation: string): Move[] {
const turns = _parseGameNotation(notation);
return flatten(
turns.map((turn) =>
turn.white ? (turn.black ? [turn.white, turn.black] : [turn.white]) : []
)
);
const turns = _parseMoves(notation);
return turns;
}

/**
Expand Down Expand Up @@ -126,9 +122,27 @@ export function _buildTurnNotation(
* @return An array of *Turn* objects.
*/
export function _parseGameNotation(notation: string): Turn[] {
return notation
return [];
// return notation
// .split(';')
// .filter((s) => s)
// .map((turnNotation) => _parseMoveNotation(turnNotation));
}

/**
* Create an ordered array of *Move* objects by parsing a game notation string.
*
* @param notation A game notation string.
* @return An array of *Move* objects.
*/
export function _parseMoves(notation: string): Move[] {
if (!notation) {
return [];
}
return (notation + '')
.split(';')
.map((turnNotation) => _parseTurnNotation(turnNotation));
.filter((s) => s)
.map((moveNotation) => _parseMoveNotation(moveNotation));
}

/**
Expand All @@ -137,43 +151,40 @@ export function _parseGameNotation(notation: string): Turn[] {
* @param notation A turn notation string.
* @return A *Turn* object.
*/
// export function _parseTurnNotation(notation: string, index: number): Turn {
// const moves = notation.split(' ');
// return {
// notation,
// index: index + 1,
// white: _parseMoveNotation(moves[0]),
// black: _parseMoveNotation(moves[1])
// };
// }
export function _parseTurnNotation(notation: string): Turn {
const sepLocation = notation.indexOf('.');
const indexString = notation.slice(0, sepLocation);
const placementsString = notation.slice(sepLocation + 1);
const placements = placementsString.split(' ');
export function _parseTurnNotation(notation: string, index: number): Turn {
const moves = notation.split(' ');
return {
notation,
index: parseInt(indexString),
white: _parseMoveNotation(placements[0]),
black: _parseMoveNotation(placements[1])
index: index + 1,
white: _parseMoveNotation(moves[0]),
black: _parseMoveNotation(moves[1])
};
}
// export function _parseTurnNotation(notation: string): Turn {
// const sepLocation = notation.indexOf('.');
// const indexString = notation.slice(0, sepLocation);
// const placementsString = notation.slice(sepLocation + 1);
// const placements = placementsString.split(' ');
// return {
// notation,
// index: parseInt(indexString),
// white: _parseMoveNotation(placements[0]),
// black: _parseMoveNotation(placements[1])
// };
// }

/**
* Create a *Move* object by parsing a move notation string.
*
* @param notation A move notation string.
* @return A *Move* object.
*/
export function _parseMoveNotation(notation?: string): Move | undefined {
if (!notation) return undefined;

export function _parseMoveNotation(notation: string): Move {
// Split notation into moving tile and reference tile portions
notation = notation.trim();
let [tileId, refNotation] = notation.split(/\s/g);
console.log(notation);
console.log(tileId);
console.log(refNotation);

// TODO: Neel: figure out why this is getting called twice, once with commas as separators and once with spaces
let [tileId, refNotation] = notation.split(/\s|,/g);

// Check for and return a passing move
if (tileId === 'x')
Expand All @@ -186,17 +197,9 @@ export function _parseMoveNotation(notation?: string): Move | undefined {

// Parse the reference notation to get the reference tile and direction
let { refId, dir, end } =
refNotation !== undefined
? _parseReferenceNotation(refNotation) // only when there is one
: { refId: tileId, dir: 0, end: false }; // first move notation

// // TODO: is this the right way to do this?
// // handle first move notation
// if (tileId === '.') {
// refId = tileId;
// dir = 0;
// end = false;
// }
refNotation === '.'
? { refId: tileId, dir: 0, end: false } // first move notation
: _parseReferenceNotation(refNotation); // only when there is one

// Return a playing move
return {
Expand Down
6 changes: 6 additions & 0 deletions js/hive-lib/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,12 @@ export type GameOptions = {
mosquito: boolean;
};

export type PossibleMove = {
qCoordinate: number;
rCoordinate: number;
tileId: TileId;
};

/**
* An object describing a player's move, which can either be a pass or move or
* place a tile.
Expand Down

0 comments on commit 1640d57

Please sign in to comment.