From b6146eed6b9ab79f68207b25f0262dbde07b844f Mon Sep 17 00:00:00 2001 From: djmil Date: Fri, 17 Nov 2023 20:37:33 +0100 Subject: [PATCH] NewGame: game board configuration - GameBoard interactivity --- .../api/GameProposalController.java | 2 +- webapp/src/components/Checkers.jsx | 145 +++++++++--------- webapp/src/container/Games.jsx | 6 +- webapp/src/container/games/GameBoard.css | 2 +- webapp/src/container/games/GameBoard.jsx | 43 ++++-- webapp/src/reducer/games.js | 3 +- 6 files changed, 115 insertions(+), 86 deletions(-) diff --git a/backend/src/main/java/djmil/cordacheckers/api/GameProposalController.java b/backend/src/main/java/djmil/cordacheckers/api/GameProposalController.java index 490f1d9..f209746 100644 --- a/backend/src/main/java/djmil/cordacheckers/api/GameProposalController.java +++ b/backend/src/main/java/djmil/cordacheckers/api/GameProposalController.java @@ -50,7 +50,7 @@ public class GameProposalController { gpSender, gpReceiver, gpReceiverColor, - // gpRequest.board() // GiteaIssue #3: use provided board configuration + gpRequest.board(), gpRequest.message()); URI locationOfNewGameProposal = ucb diff --git a/webapp/src/components/Checkers.jsx b/webapp/src/components/Checkers.jsx index be54ea1..52ed697 100644 --- a/webapp/src/components/Checkers.jsx +++ b/webapp/src/components/Checkers.jsx @@ -65,102 +65,103 @@ export function Player({ color, name }) { /* * Board */ -export function Board({ game }) { +export function Board({ game, onClick }) { + const board = (game && game.board && typeof game.board === 'object') ? game.board : defaultBoard; - const board = (game && game.board && typeof game.board === 'object') ? game.board : defaultBoard(); + const BlackTile = () => { + return
+ } + + const WhiteTile = ({ id }) => { + const stone = board[id]; + const isInteractive = (typeof onClick === 'function') ? ' interactive' : ''; + + return ( +
isInteractive && onClick(id)}> + +
+ ); + } return
- - - - + + + +
- - - - + + + +
- - - - + + + +
- - - - + + + +
- - - - + + + +
- - - - + + + +
- - - - + + + +
- - - - + + + +
} -function defaultBoard() { - return { - 1: { color: "BLACK", type: "MAN" }, - 2: { color: "BLACK", type: "MAN" }, - 3: { color: "BLACK", type: "MAN" }, - 4: { color: "BLACK", type: "MAN" }, - 5: { color: "BLACK", type: "MAN" }, - 6: { color: "BLACK", type: "MAN" }, - 7: { color: "BLACK", type: "MAN" }, - 8: { color: "BLACK", type: "MAN" }, - 9: { color: "BLACK", type: "MAN" }, - 10: { color: "BLACK", type: "MAN" }, - 11: { color: "BLACK", type: "MAN" }, - 12: { color: "BLACK", type: "MAN" }, - 21: { color: "WHITE", type: "MAN" }, - 22: { color: "WHITE", type: "MAN" }, - 23: { color: "WHITE", type: "MAN" }, - 24: { color: "WHITE", type: "MAN" }, - 25: { color: "WHITE", type: "MAN" }, - 26: { color: "WHITE", type: "MAN" }, - 27: { color: "WHITE", type: "MAN" }, - 28: { color: "WHITE", type: "MAN" }, - 29: { color: "WHITE", type: "MAN" }, - 30: { color: "WHITE", type: "MAN" }, - 31: { color: "WHITE", type: "MAN" }, - 32: { color: "WHITE", type: "MAN" }, - } +const blackMan = { color: Color.black, type: 'MAN' }; +const blackKing = { color: Color.black, type: 'KING' }; +const whiteMan = { color: Color.white, type: 'MAN' }; +const whiteKing = { color: Color.white, type: 'KING' }; + +export const defaultBoard = { + 1: blackMan, 2: blackMan, 3: blackMan, 4: blackMan, 5: blackMan, 6: blackMan, 7: blackMan, 8: blackMan, 9: blackMan, 10: blackMan, 11: blackMan, 12: blackMan, + 21: whiteMan, 22: whiteMan, 23: whiteMan, 24: whiteMan, 25: whiteMan, 26: whiteMan, 27: whiteMan, 28: whiteMan, 29: whiteMan, 30: whiteMan, 31: whiteMan, 32: whiteMan, } -function WhiteTile({ id, stone }) { - return ( -
console.log('click', id)} - > - -
- ); -} +export function nextStone(currentStone) { + const color = currentStone?.color; + const type = currentStone?.type; -function BlackTile() { - return
+ if (!color || !type) + return blackMan; + + if (color === Color.black && type === 'MAN') + return blackKing; + + if (color === Color.black && type === 'KING') + return whiteMan; + + if (color === Color.white && type === 'MAN') + return whiteKing; + + if (color === Color.white && type === 'KING') + return null; } \ No newline at end of file diff --git a/webapp/src/container/Games.jsx b/webapp/src/container/Games.jsx index 38406f4..fd8d594 100644 --- a/webapp/src/container/Games.jsx +++ b/webapp/src/container/Games.jsx @@ -26,7 +26,11 @@ export default function Games({ context: { gamesReducer, gamesApi }, players })
{/* */} - + dispatchGames({ type: 'nextNewGame', board })} + onActiveGameMove={(uuid, from, to) => console.log(uuid, 'move', from, '->', to)} + />
diff --git a/webapp/src/container/games/GameBoard.css b/webapp/src/container/games/GameBoard.css index bd5e884..2c90743 100644 --- a/webapp/src/container/games/GameBoard.css +++ b/webapp/src/container/games/GameBoard.css @@ -14,7 +14,7 @@ margin-top: -1px; } -.GameBoard .Tile.white:hover { +.GameBoard .Tile.white.interactive:hover { background-color:azure; } diff --git a/webapp/src/container/games/GameBoard.jsx b/webapp/src/container/games/GameBoard.jsx index dad8c10..22043f9 100644 --- a/webapp/src/container/games/GameBoard.jsx +++ b/webapp/src/container/games/GameBoard.jsx @@ -1,35 +1,58 @@ -import React, { useContext } from 'react'; +import React, { useContext, useState } from 'react'; import { useLocation, matchPath } from 'react-router-dom'; import { GamesContext } from '../../context/games'; -import { Color, Player, Board } from '../../components/Checkers'; +import { Color, Player, Board, nextStone } from '../../components/Checkers'; import './GameBoard.css'; -export default function GameBoard({ username }) { +export default function GameBoard({ username, onNewGameBoardStone, onActiveGameMove }) { const games = useContext(GamesContext); const { pathname } = useLocation(); + const [startId, setStartId] = useState(null); - const game = (() => { + const onClick_NewGame = (cellId) => { + let nextBoard = { ...games.newGame.board }; + nextBoard[cellId] = nextStone(nextBoard[cellId]); + + onNewGameBoardStone(nextBoard); + } + + const onClick_ActiveGame = (cellId) => { + if (startId === cellId) + return setStartId(null); + + if (startId === null) + return setStartId(cellId); + + if (game?.uuid) + onActiveGameMove(game.uuid, startId, cellId); + + setStartId(null); + }; + + const [game, onClick] = (() => { if (matchPath('/games/new', pathname)) - return gameFrom(games.newGame); + return [gameFrom(games.newGame), onClick_NewGame]; if (matchPath('/games/proposal', pathname)) - return games.findGame({ uuid: games.proposal.selectedUUID }); + return [games.findGame({ uuid: games.proposal.selectedUUID }), null]; else if (matchPath('/games/active', pathname)) - return games.findGame({ uuid: games.active.selectedUUID }); + return [games.findGame({ uuid: games.active.selectedUUID }), onClick_ActiveGame]; else if (matchPath('/games/archive', pathname)) - return games.findGame({ uuid: games.archive.selectedUUID }); + return [games.findGame({ uuid: games.archive.selectedUUID }), null]; - return {}; // defaults + return [{}, null]; // defaults })(); // <<-- Execute const opponentColor = Color.opposite(game?.myColor); const [opponentName, myName] = game?.opponentName ? [game.opponentName, username] : ['', '']; + const optionalOnClick = (onClick && game?.board) ? (id) => onClick(id) : null; + return (
- +
) diff --git a/webapp/src/reducer/games.js b/webapp/src/reducer/games.js index 379d4e8..71f20f7 100644 --- a/webapp/src/reducer/games.js +++ b/webapp/src/reducer/games.js @@ -1,5 +1,6 @@ import { useReducer } from 'react'; import { nextState } from '../util/StateHelper'; +import { defaultBoard } from '../components/Checkers'; export const gamesInitialState = { gamesList: null, @@ -7,7 +8,7 @@ export const gamesInitialState = { newGame: { opponentName: '', opponentColor: '', - board: null, + board: defaultBoard, message: '', },