import React, {ReactElement, ReactNode, useContext} from "react"; import PlayerScoreCard, {CellLocation, PlayerScoreCardJSONRepresentation} from "../Classes/PlayerScoreCard"; import {BlockDef, GameSchema, getGameSchemaById} from "../static/rulesets"; import {formatUnicorn} from "../static/strings"; import LocaleContext from "../LocaleContext"; import {CellFlag} from "../static/enums"; import {ScoreCellValue} from "../Classes/ScoreCell"; import {CaretakerSet} from "../Classes/Caretaker"; import {GameSettings} from "./GameSetup"; import Settings from "../static/settings.json"; import axios from "axios"; import {Button, Container, Header, Icon, Image} from "semantic-ui-react"; import logo from "../static/images/kadi.png"; import KadiGrandTotalRow from "./KadiGrandTotalRow"; import KadiBlockRenderer from "./KadiBlockRenderer"; import {KadiCellDisplayValue} from "./KadiCell"; export interface CellScores { [key: string]: KadiCellDisplayValue; } export interface BlockScores { [key: string]: CellScores; bonuses: CellScores; subtotals: CellScores; totals: CellScores; } export interface CellEventResponse { value: ScoreCellValue | CellFlag; playerId: string; location: CellLocation; } export interface KadiBoardProps { settings: GameSettings; returnToSetup: () => void; } interface KadiBoardState { scoreSheet: ScoreSheet; playerIds: string[]; showResults: boolean; savingGame: boolean; } interface ScoreSheet { [key: string]: PlayerScoreCard; } class KadiBoard extends React.Component { private readonly gameSchema: GameSchema; private readonly caretaker: CaretakerSet; state: KadiBoardState; constructor(props: KadiBoardProps) { super(props); this.gameSchema = getGameSchemaById(this.props.settings.ruleset); this.state = { scoreSheet: this.generateNewScoreSheet(this.props.settings.playerIds), playerIds: this.props.settings.playerIds, showResults: true, savingGame: false, }; this.caretaker = new CaretakerSet( Settings.maxHistoryLength, ...this.state.playerIds.map( pid => this.state.scoreSheet[pid] ) ); } private generateNewScoreSheet(playerIds: string[]): ScoreSheet { const scoreSheet: ScoreSheet = {}; for (const playerId of playerIds) { scoreSheet[playerId] = new PlayerScoreCard(playerId, this.gameSchema); } return scoreSheet; } private onCellEdit = (response: CellEventResponse): void => { const newScoreSheet = this.state.scoreSheet; KadiBoard.updateScoreSheetFromCellResponse(newScoreSheet, response); this.setState({ scoreSheet: newScoreSheet }); this.caretaker.save(); }; private static updateScoreSheetFromCellResponse(scoreSheet: ScoreSheet, response: CellEventResponse): void { const playerScoreCard = scoreSheet[response.playerId]; playerScoreCard.updateCellByLocationWithValue(response.location, response.value); } toggleShowResults = () => { this.setState({ showResults: !this.state.showResults }); }; private getCellDisplayValueByPlayerIdAndLocation(playerId: string, location: CellLocation): KadiCellDisplayValue { const playerSheet = this.state.scoreSheet[playerId]; let cellValue: KadiCellDisplayValue = playerSheet.getCellScoreByLocation(location); cellValue = playerSheet.cellAtLocationIsStruck(location) ? CellFlag.strike : cellValue; return cellValue; }; private getBlockSubtotalByPlayerId(blockId: string, playerId: string): number { return this.state.scoreSheet[playerId].getBlockSubTotalById(blockId); } private getBlockTotalByPlayerId(blockId: string, playerId: string): number { return this.state.scoreSheet[playerId].getBlockTotalById(blockId); } private getTotalForPlayer(playerId: string): number { return this.state.scoreSheet[playerId].getTotal(); } private playerHasBonusForBlock(playerId: string, blockId: string): boolean { return this.state.scoreSheet[playerId].blockWithIdHasBonus(blockId); } private undo(): void { this.caretaker.undo(); this.forceUpdate(); } private redo(): void { this.caretaker.redo(); this.forceUpdate(); } private getJSONRepresentationForBoard(): string { const JSONScoreCards: PlayerScoreCardJSONRepresentation[] = []; for (const playerId in this.state.scoreSheet) { JSONScoreCards.push(this.state.scoreSheet[playerId].getJSONRepresentation()); } return JSON.stringify({ gameType: this.gameSchema.id, results: JSONScoreCards }); } private canSave(): boolean { for (const playerId in this.state.scoreSheet) { if (!this.state.scoreSheet[playerId].filledOut()) { return false; } } return true; } private saveGame: () => void = async () => { this.setState({savingGame: true}); axios.post(Settings.rootUrl + "/api/savegame", this.getJSONRepresentationForBoard(), {headers: {"Content-Type": "application/json"}} ) .then(response => this.onGameSave(response.data)) .catch(error => this.onSaveError(error)) .finally(() => this.setState({ savingGame: false })); }; private onGameSave = (serverResponse: string) => { console.log("Response:", serverResponse); }; private onSaveError = (error: any) => { console.log("Error saving:", error); }; render(): ReactNode { const Locale = this.context.strings; const rows: ReactElement[] = []; for (const block of this.gameSchema.blocks) { const scores: BlockScores = {subtotals: {}, bonuses: {}, totals: {}}; for (const cell of block.cells) { scores[cell.id] = {}; } this.state.playerIds.forEach(pid => { scores.totals[pid] = this.getBlockTotalByPlayerId(block.id, pid); scores.bonuses[pid] = this.playerHasBonusForBlock(pid, block.id); scores.subtotals[pid] = this.getBlockSubtotalByPlayerId(block.id, pid); for (const cell of block.cells) { scores[cell.id][pid] = this.getCellDisplayValueByPlayerIdAndLocation( pid, { blockId: block.id, cellId: cell.id }); } }); rows.push( ); } const grandTotals: CellScores = {}; this.state.playerIds.forEach(pid => grandTotals[pid] = this.getTotalForPlayer(pid) ); rows.push( ); return (
{rows}
K  A  D  I
); } } KadiBoard.contextType = LocaleContext; interface ColumnHeadersRowProps { playerIds: string[]; } const ColumnHeadersRow: React.FunctionComponent = ({ playerIds }) => { const Locale = useContext(LocaleContext).strings; const columnHeaders: ReactNode[] = [( {Locale.headers.rowLabels} )]; for (const playerId of playerIds) { columnHeaders.push( {playerId} ); } return ( {columnHeaders} ); }; export default KadiBoard;