NewGame: game board configuration

- GameBoard interactivity
This commit is contained in:
djmil 2023-11-17 20:37:33 +01:00
parent 016423aeb6
commit b6146eed6b
6 changed files with 115 additions and 86 deletions

View File

@ -50,7 +50,7 @@ public class GameProposalController {
gpSender, gpSender,
gpReceiver, gpReceiver,
gpReceiverColor, gpReceiverColor,
// gpRequest.board() // GiteaIssue #3: use provided board configuration gpRequest.board(),
gpRequest.message()); gpRequest.message());
URI locationOfNewGameProposal = ucb URI locationOfNewGameProposal = ucb

View File

@ -65,102 +65,103 @@ export function Player({ color, name }) {
/* /*
* Board * 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 <div className='Tile black' />
return <div className='Board'>
<div className='row'>
<BlackTile /> <WhiteTile id={1} stone={board[1]} />
<BlackTile /> <WhiteTile id={2} stone={board[2]} />
<BlackTile /> <WhiteTile id={3} stone={board[3]} />
<BlackTile /> <WhiteTile id={4} stone={board[4]} />
</div>
<div className='row'>
<WhiteTile id={5} stone={board[5]} /> <BlackTile />
<WhiteTile id={6} stone={board[6]} /> <BlackTile />
<WhiteTile id={7} stone={board[7]} /> <BlackTile />
<WhiteTile id={8} stone={board[8]} /> <BlackTile />
</div>
<div className='row'>
<BlackTile /> <WhiteTile id={9} stone={board[9]} />
<BlackTile /> <WhiteTile id={10} stone={board[10]} />
<BlackTile /> <WhiteTile id={11} stone={board[11]} />
<BlackTile /> <WhiteTile id={12} stone={board[12]} />
</div>
<div className='row'>
<WhiteTile id={13} stone={board[13]} /> <BlackTile />
<WhiteTile id={14} stone={board[14]} /> <BlackTile />
<WhiteTile id={15} stone={board[15]} /> <BlackTile />
<WhiteTile id={16} stone={board[16]} /> <BlackTile />
</div>
<div className='row'>
<BlackTile /> <WhiteTile id={17} stone={board[17]} />
<BlackTile /> <WhiteTile id={18} stone={board[18]} />
<BlackTile /> <WhiteTile id={19} stone={board[19]} />
<BlackTile /> <WhiteTile id={20} stone={board[20]} />
</div>
<div className='row'>
<WhiteTile id={21} stone={board[21]} /> <BlackTile />
<WhiteTile id={22} stone={board[22]} /> <BlackTile />
<WhiteTile id={23} stone={board[23]} /> <BlackTile />
<WhiteTile id={24} stone={board[24]} /> <BlackTile />
</div>
<div className='row'>
<BlackTile /> <WhiteTile id={25} stone={board[25]} />
<BlackTile /> <WhiteTile id={26} stone={board[26]} />
<BlackTile /> <WhiteTile id={27} stone={board[27]} />
<BlackTile /> <WhiteTile id={28} stone={board[28]} />
</div>
<div className='row'>
<WhiteTile id={29} stone={board[29]} /> <BlackTile />
<WhiteTile id={30} stone={board[30]} /> <BlackTile />
<WhiteTile id={31} stone={board[31]} /> <BlackTile />
<WhiteTile id={32} stone={board[32]} /> <BlackTile />
</div>
</div>
} }
function defaultBoard() { const WhiteTile = ({ id }) => {
return { const stone = board[id];
1: { color: "BLACK", type: "MAN" }, const isInteractive = (typeof onClick === 'function') ? ' interactive' : '';
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" },
}
}
function WhiteTile({ id, stone }) {
return ( return (
<div className='Tile white' <div className={'Tile white' + isInteractive} onClick={() => isInteractive && onClick(id)}>
onClick={() => console.log('click', id)}
>
<Stone color={stone?.color} type={stone?.type} /> <Stone color={stone?.color} type={stone?.type} />
</div> </div>
); );
} }
function BlackTile() { return <div className='Board'>
return <div className='Tile black' /> <div className='row'>
<BlackTile /> <WhiteTile id={1} />
<BlackTile /> <WhiteTile id={2} />
<BlackTile /> <WhiteTile id={3} />
<BlackTile /> <WhiteTile id={4} />
</div>
<div className='row'>
<WhiteTile id={5} /> <BlackTile />
<WhiteTile id={6} /> <BlackTile />
<WhiteTile id={7} /> <BlackTile />
<WhiteTile id={8} /> <BlackTile />
</div>
<div className='row'>
<BlackTile /> <WhiteTile id={9} />
<BlackTile /> <WhiteTile id={10} />
<BlackTile /> <WhiteTile id={11} />
<BlackTile /> <WhiteTile id={12} />
</div>
<div className='row'>
<WhiteTile id={13} /> <BlackTile />
<WhiteTile id={14} /> <BlackTile />
<WhiteTile id={15} /> <BlackTile />
<WhiteTile id={16} /> <BlackTile />
</div>
<div className='row'>
<BlackTile /> <WhiteTile id={17} />
<BlackTile /> <WhiteTile id={18} />
<BlackTile /> <WhiteTile id={19} />
<BlackTile /> <WhiteTile id={20} />
</div>
<div className='row'>
<WhiteTile id={21} /> <BlackTile />
<WhiteTile id={22} /> <BlackTile />
<WhiteTile id={23} /> <BlackTile />
<WhiteTile id={24} /> <BlackTile />
</div>
<div className='row'>
<BlackTile /> <WhiteTile id={25} />
<BlackTile /> <WhiteTile id={26} />
<BlackTile /> <WhiteTile id={27} />
<BlackTile /> <WhiteTile id={28} />
</div>
<div className='row'>
<WhiteTile id={29} /> <BlackTile />
<WhiteTile id={30} /> <BlackTile />
<WhiteTile id={31} /> <BlackTile />
<WhiteTile id={32} /> <BlackTile />
</div>
</div>
}
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,
}
export function nextStone(currentStone) {
const color = currentStone?.color;
const type = currentStone?.type;
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;
} }

View File

@ -26,7 +26,11 @@ export default function Games({ context: { gamesReducer, gamesApi }, players })
<div className='right-side'> <div className='right-side'>
<ActionPanel gamesApi={gamesApi} /> <ActionPanel gamesApi={gamesApi} />
{/* <GameMessage /> */} {/* <GameMessage /> */}
<GameBoard username={players.currentUser} /> <GameBoard
username={players.currentUser}
onNewGameBoardStone={(board) => dispatchGames({ type: 'nextNewGame', board })}
onActiveGameMove={(uuid, from, to) => console.log(uuid, 'move', from, '->', to)}
/>
<Message2Opponent dispatchGames={dispatchGames} /> <Message2Opponent dispatchGames={dispatchGames} />
</div> </div>

View File

@ -14,7 +14,7 @@
margin-top: -1px; margin-top: -1px;
} }
.GameBoard .Tile.white:hover { .GameBoard .Tile.white.interactive:hover {
background-color:azure; background-color:azure;
} }

View File

@ -1,35 +1,58 @@
import React, { useContext } from 'react'; import React, { useContext, useState } from 'react';
import { useLocation, matchPath } from 'react-router-dom'; import { useLocation, matchPath } from 'react-router-dom';
import { GamesContext } from '../../context/games'; import { GamesContext } from '../../context/games';
import { Color, Player, Board } from '../../components/Checkers'; import { Color, Player, Board, nextStone } from '../../components/Checkers';
import './GameBoard.css'; import './GameBoard.css';
export default function GameBoard({ username }) { export default function GameBoard({ username, onNewGameBoardStone, onActiveGameMove }) {
const games = useContext(GamesContext); const games = useContext(GamesContext);
const { pathname } = useLocation(); 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)) if (matchPath('/games/new', pathname))
return gameFrom(games.newGame); return [gameFrom(games.newGame), onClick_NewGame];
if (matchPath('/games/proposal', pathname)) 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)) 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)) 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 })(); // <<-- Execute
const opponentColor = Color.opposite(game?.myColor); const opponentColor = Color.opposite(game?.myColor);
const [opponentName, myName] = game?.opponentName ? [game.opponentName, username] : ['', '']; const [opponentName, myName] = game?.opponentName ? [game.opponentName, username] : ['', ''];
const optionalOnClick = (onClick && game?.board) ? (id) => onClick(id) : null;
return ( return (
<div className='GameBoard'> <div className='GameBoard'>
<Player color={opponentColor || Color.white} name={opponentName} /> <Player color={opponentColor || Color.white} name={opponentName} />
<Board game={game} /> <Board game={game} onClick={optionalOnClick} />
<Player color={game?.myColor || Color.black} name={myName} /> <Player color={game?.myColor || Color.black} name={myName} />
</div> </div>
) )

View File

@ -1,5 +1,6 @@
import { useReducer } from 'react'; import { useReducer } from 'react';
import { nextState } from '../util/StateHelper'; import { nextState } from '../util/StateHelper';
import { defaultBoard } from '../components/Checkers';
export const gamesInitialState = { export const gamesInitialState = {
gamesList: null, gamesList: null,
@ -7,7 +8,7 @@ export const gamesInitialState = {
newGame: { newGame: {
opponentName: '', opponentName: '',
opponentColor: '', opponentColor: '',
board: null, board: defaultBoard,
message: '', message: '',
}, },