diff --git a/src/Classes/PlayerScoreCard.ts b/src/Classes/PlayerScoreCard.ts index 363fd90..d2b31f3 100755 --- a/src/Classes/PlayerScoreCard.ts +++ b/src/Classes/PlayerScoreCard.ts @@ -1,8 +1,7 @@ import {ScoreCellValue} from "./ScoreCell"; import ScoreBlock, {createBlockFromDef, BlockState, ScoreBlockJSONRepresentation} from "./ScoreBlock"; -import {BlockDef, GameSchema} from "../static/rulesets"; +import {BlockDef, Ruleset, CellFlag} from "../../../shared/rulesets"; import { Memento, Originator } from "./Caretaker"; -import {CellFlag} from "../static/enums"; export type CellLocation = { blockId: string, cellId: string }; @@ -10,9 +9,23 @@ class PlayerScoreCard implements Originator { private readonly playerId: string; private readonly blocks: ScoreBlock[]; - constructor(playerId: string, gameSchema: GameSchema) { - this.playerId = playerId; - this.blocks = PlayerScoreCard.generateBlocks(gameSchema.blocks); + constructor(jsonRep: PlayerScoreCardJSONRepresentation, gameSchema: Ruleset); + constructor(playerId: string, gameSchema: Ruleset) + constructor(...args: any[]) { + this.blocks = PlayerScoreCard.generateBlocks(args[1].blocks); + if (typeof args[0] === "string") { + this.playerId = args[0]; + } + else { + this.playerId = (args[0] as PlayerScoreCardJSONRepresentation).playerId; + this.restoreFromJSON(args[0]); + } + } + + private restoreFromJSON(jsonRep: PlayerScoreCardJSONRepresentation): void { + for (const block of this.blocks) { + block.restoreFromJSON(jsonRep.blocks[block.getId()]); + } } private static generateBlocks(blockDefs: Record): ScoreBlock[] { @@ -97,9 +110,9 @@ class PlayerScoreCard implements Originator { getJSONRepresentation(): PlayerScoreCardJSONRepresentation { const JSONRepresentation: PlayerScoreCardJSONRepresentation = { playerId: this.playerId, - blocks: [] + blocks: {} }; - this.blocks.forEach(block => JSONRepresentation.blocks.push(block.getJSONRepresentation())); + this.blocks.forEach(block => JSONRepresentation.blocks[block.getId()] = block.getJSONRepresentation()); return JSONRepresentation; } } @@ -110,7 +123,7 @@ interface PlayerScoreCardState { export interface PlayerScoreCardJSONRepresentation { playerId: string; - blocks: ScoreBlockJSONRepresentation[]; + blocks: Record; } class PlayerScoreCardMemento implements Memento { diff --git a/src/Classes/ScoreBlock.ts b/src/Classes/ScoreBlock.ts index 54bca80..2b608ef 100755 --- a/src/Classes/ScoreBlock.ts +++ b/src/Classes/ScoreBlock.ts @@ -4,8 +4,7 @@ import ScoreCell, { CellState, ScoreCellJSONRepresentation } from "./ScoreCell"; -import {CellDef, BlockDef, BonusBlockDef, NoBonusBlockDef } from "../static/rulesets"; -import {CellFlag} from "../static/enums"; +import {CellDef, BlockDef, BonusBlockDef, NoBonusBlockDef, CellFlag } from "../../../shared/rulesets"; export const createBlockFromDef = (blockId: string, blockDef: BlockDef) : ScoreBlock => { if (blockDef.hasBonus) { @@ -22,8 +21,7 @@ export interface BlockState { } export interface ScoreBlockJSONRepresentation { - id: string; - cells: ScoreCellJSONRepresentation[]; + cells: Record; } abstract class ScoreBlock { @@ -108,12 +106,17 @@ abstract class ScoreBlock { getJSONRepresentation(): ScoreBlockJSONRepresentation { const JSONRepresentation: ScoreBlockJSONRepresentation = { - id: this.id, - cells: [] + cells: {} }; - this.cells.forEach(cell => JSONRepresentation.cells.push(cell.getJSONRepresentation())); + this.cells.forEach(cell => JSONRepresentation.cells[cell.getId()] = cell.getJSONRepresentation()); return JSONRepresentation; } + + restoreFromJSON(jsonRep: ScoreBlockJSONRepresentation): void { + for (const cell of this.cells) { + cell.restoreFromJSON(jsonRep.cells[cell.getId()]); + } + } } class ScoreBlockWithBonus extends ScoreBlock { diff --git a/src/Classes/ScoreCell.ts b/src/Classes/ScoreCell.ts index c2ec3cd..92e766c 100755 --- a/src/Classes/ScoreCell.ts +++ b/src/Classes/ScoreCell.ts @@ -1,7 +1,14 @@ -import {CellFlag, FieldType} from "../static/enums"; -import {BoolCellDef, CellDef, MultiplierCellDef, NumberCellDef, YahtzeeCellDef} from "../static/rulesets" +import { + BoolCellDef, + CellDef, + CellFlag, + FieldType, + MultiplierCellDef, + NumberCellDef, + SuperkadiCellDef +} from "../../../shared/rulesets"; -export const createCellFromDef = (cellId: string, cellDef: CellDef) : ScoreCell => { +export const createCellFromDef = (cellId: string, cellDef: CellDef): ScoreCell => { switch (cellDef.fieldType) { case FieldType.number: return new NumberScoreCell(cellId, cellDef); @@ -9,8 +16,8 @@ export const createCellFromDef = (cellId: string, cellDef: CellDef) : ScoreCell return new BoolScoreCell(cellId, cellDef); case FieldType.multiplier: return new MultiplierScoreCell(cellId, cellDef); - case FieldType.yahtzee: - return new YahtzeeScoreCell(cellId, cellDef); + case FieldType.superkadi: + return new SuperkadiScoreCell(cellId, cellDef); } }; @@ -24,7 +31,6 @@ export interface CellState { } export interface ScoreCellJSONRepresentation { - id: string; value: number | boolean | CellFlag.strike; } @@ -79,7 +85,11 @@ abstract class ScoreCell { } getJSONRepresentation(): ScoreCellJSONRepresentation { - return { id: this.id, value: this.isStruck() ? CellFlag.strike : this.value }; + return { value: this.isStruck() ? CellFlag.strike : this.value }; + } + + restoreFromJSON(jsonRep: ScoreCellJSONRepresentation): void { + this.update(jsonRep.value); } } @@ -202,17 +212,17 @@ class BoolScoreCell extends IterableScoreCell { } } -class YahtzeeScoreCell extends IterableScoreCell { - protected static readonly fieldType = FieldType.yahtzee; +class SuperkadiScoreCell extends IterableScoreCell { + protected static readonly fieldType = FieldType.superkadi; private readonly score: number; protected value: number; - constructor(cellId: string, cellDef: YahtzeeCellDef) { + constructor(cellId: string, cellDef: SuperkadiCellDef) { super(cellId, cellDef); this.score = cellDef.score; this.value = 0; - for (let i = 0; i <= cellDef.maxYahtzees; i++) { + for (let i = 0; i <= cellDef.maxSuperkadis; i++) { this.iteratedSequence.push(i); } } diff --git a/src/Components/KadiBlockBonusRow.tsx b/src/Components/KadiBlockBonusRow.tsx index bcc18c9..cdb7f45 100755 --- a/src/Components/KadiBlockBonusRow.tsx +++ b/src/Components/KadiBlockBonusRow.tsx @@ -1,7 +1,7 @@ import React, {ReactNode} from "react"; import KadiCell from "./KadiCell"; -import {FieldType} from "../static/enums"; import {CellScores} from "./KadiBoard"; +import {FieldType} from "../../../shared/rulesets"; interface KadiBlockBonusRowProps { blockId: string; diff --git a/src/Components/KadiBlockRenderer.tsx b/src/Components/KadiBlockRenderer.tsx index 0a3b479..6a9fe59 100755 --- a/src/Components/KadiBlockRenderer.tsx +++ b/src/Components/KadiBlockRenderer.tsx @@ -1,8 +1,5 @@ -import {BlockDef} from "../static/rulesets"; -import {CellLocation} from "../Classes/PlayerScoreCard"; import React, {ReactElement} from "react"; import {formatUnicorn} from "../static/strings"; -import {FieldType} from "../static/enums"; import {BlockScores, CellEventResponse} from "./KadiBoard"; import GenericKadiRowContainer from "./GenericKadiRowContainer"; import KadiEditableRowCells from "./KadiEditableRowCells"; @@ -10,6 +7,7 @@ import KadiBlockTotalRow from "./KadiBlockTotalRow"; import KadiBlockSubtotalRow from "./KadiBlockSubtotalRow"; import KadiBlockBonusRow from "./KadiBlockBonusRow"; import LocaleContext from "../LocaleContext"; +import {BlockDef, FieldType} from "../../../shared/rulesets"; interface BlockRendererProps { blockId: string; diff --git a/src/Components/KadiBlockSubtotalRow.tsx b/src/Components/KadiBlockSubtotalRow.tsx index db14308..5fa79b9 100755 --- a/src/Components/KadiBlockSubtotalRow.tsx +++ b/src/Components/KadiBlockSubtotalRow.tsx @@ -1,7 +1,7 @@ import React, {ReactNode} from "react"; import KadiCell from "./KadiCell"; -import {FieldType} from "../static/enums"; import {CellScores} from "./KadiBoard"; +import {FieldType} from "../../../shared/rulesets"; interface KadiBlockSubtotalRowProps { blockId: string; diff --git a/src/Components/KadiBlockTotalRow.tsx b/src/Components/KadiBlockTotalRow.tsx index 330c4b7..eb5f398 100755 --- a/src/Components/KadiBlockTotalRow.tsx +++ b/src/Components/KadiBlockTotalRow.tsx @@ -1,7 +1,7 @@ import React, {ReactNode} from "react"; import KadiCell from "./KadiCell"; -import {FieldType} from "../static/enums"; import {CellScores} from "./KadiBoard"; +import {FieldType} from "../../../shared/rulesets"; interface KadiBlockTotalRowProps { blockId: string; diff --git a/src/Components/KadiBoard.tsx b/src/Components/KadiBoard.tsx index 74fbc59..b666eef 100755 --- a/src/Components/KadiBoard.tsx +++ b/src/Components/KadiBoard.tsx @@ -1,8 +1,7 @@ import React, {ReactElement, ReactNode, useContext} from "react"; import PlayerScoreCard, {CellLocation, PlayerScoreCardJSONRepresentation} from "../Classes/PlayerScoreCard"; -import {GameSchema, getGameSchemaById} from "../static/rulesets"; +import {getGameSchemaById} from "../static/rulesets"; import LocaleContext from "../LocaleContext"; -import {CellFlag} from "../static/enums"; import {ScoreCellValue} from "../Classes/ScoreCell"; import {CaretakerSet} from "../Classes/Caretaker"; import {GameSettings} from "./GameSetup"; @@ -15,6 +14,7 @@ import KadiBlockRenderer from "./KadiBlockRenderer"; import {KadiCellDisplayValue} from "./KadiCell"; import {Player} from "./Game"; import {SERVER_BASE_NAME} from "../index"; +import {CellFlag, Ruleset} from "../../../shared/rulesets"; export interface CellScores { @@ -53,7 +53,7 @@ interface ScoreSheet { } class KadiBoard extends React.Component { - private readonly gameSchema: GameSchema; + private readonly gameSchema: Ruleset; private readonly caretaker: CaretakerSet; state: KadiBoardState; diff --git a/src/Components/KadiCell.tsx b/src/Components/KadiCell.tsx index 306aeac..ce9c739 100755 --- a/src/Components/KadiCell.tsx +++ b/src/Components/KadiCell.tsx @@ -1,9 +1,9 @@ import React, {ChangeEvent, FocusEvent, ReactNode, KeyboardEvent} from "react"; -import {CellFlag, FieldType} from "../static/enums"; import {ScoreCellValue} from "../Classes/ScoreCell"; import {CellEventResponse} from "./KadiBoard"; import {CellLocation} from "../Classes/PlayerScoreCard"; import {useLongPress} from "./useLongPress"; +import {CellFlag, FieldType} from "../../../shared/rulesets"; export type KadiCellDisplayValue = ScoreCellValue | CellFlag.strike; @@ -93,8 +93,8 @@ class KadiCell extends React.Component { return ; case FieldType.number: return ; - case FieldType.yahtzee: - return ; + case FieldType.superkadi: + return ; } } } @@ -185,16 +185,16 @@ const NumberKadiCell: React.FunctionComponent = ({ strike ) }; -const YahtzeeKadiCell: React.FunctionComponent = ({value, timeoutMs, strikeCell, updateCell}) => { +const SuperkadiKadiCell: React.FunctionComponent = ({value, timeoutMs, strikeCell, updateCell}) => { const handleClick = (): void => updateCell(true); const strikeCellOnLongPress = useLongPress(strikeCell, timeoutMs); return ( -
+
{value}
diff --git a/src/Components/KadiEditableRowCells.tsx b/src/Components/KadiEditableRowCells.tsx index b09eec2..d185dc7 100755 --- a/src/Components/KadiEditableRowCells.tsx +++ b/src/Components/KadiEditableRowCells.tsx @@ -1,8 +1,8 @@ import {CellLocation} from "../Classes/PlayerScoreCard"; -import {FieldType} from "../static/enums"; import React, {ReactElement} from "react"; import KadiCell from "./KadiCell"; import {CellEventResponse, CellScores} from "./KadiBoard"; +import {FieldType} from "../../../shared/rulesets"; interface KadiEditableRowCellsProps { location: CellLocation; diff --git a/src/Components/KadiGrandTotalRow.tsx b/src/Components/KadiGrandTotalRow.tsx index 2612ae0..fec6ddf 100755 --- a/src/Components/KadiGrandTotalRow.tsx +++ b/src/Components/KadiGrandTotalRow.tsx @@ -1,9 +1,9 @@ import React, {ReactNode} from "react"; import LocaleContext from "../LocaleContext"; import KadiCell from "./KadiCell"; -import {FieldType} from "../static/enums"; import {Icon} from "semantic-ui-react"; import {CellScores} from "./KadiBoard"; +import {FieldType} from "../../../shared/rulesets"; interface KadiGrandTotalRowProps { showResults: boolean; diff --git a/src/static/css/game.css b/src/static/css/game.css index 4f029da..03ec2c1 100755 --- a/src/static/css/game.css +++ b/src/static/css/game.css @@ -125,7 +125,7 @@ div.subtotalField, div.totalField, div.bonusField, div.globalTotalField, -div.yahtzeeField, +div.superkadiField, div.multipleField, div.numberField { width: var(--default-field-width); diff --git a/src/static/enums.ts b/src/static/enums.ts index 4339058..7e8aadf 100755 --- a/src/static/enums.ts +++ b/src/static/enums.ts @@ -1,14 +1,3 @@ -export enum FieldType { - number = "numberField", - bool = "boolField", - bonus = "bonusField", - subtotal = "subtotalField", - globalTotal = "globalTotalField", - total = "totalField", - yahtzee = "yahtzeeField", - multiplier = "multiplierField", -} - export enum CellFlag { strike = "cellFlagStrike", unstrike = "cellFlagUnstrike", diff --git a/src/static/rulesets.ts b/src/static/rulesets.ts index 4a94c89..cfb012c 100755 --- a/src/static/rulesets.ts +++ b/src/static/rulesets.ts @@ -1,4 +1,13 @@ -import { FieldType } from "./enums"; +export enum FieldType { + number = "numberField", + bool = "boolField", + bonus = "bonusField", + subtotal = "subtotalField", + globalTotal = "globalTotalField", + total = "totalField", + superkadi = "superkadiField", + multiplier = "multiplierField", +} export const defaultCellValues = { [FieldType.number]: 0, @@ -6,12 +15,11 @@ export const defaultCellValues = { [FieldType.subtotal]: 0, [FieldType.total]: 0, [FieldType.bonus]: 0, - [FieldType.yahtzee]: 0, + [FieldType.superkadi]: 0, [FieldType.multiplier]: 0, }; -// ----- gameSchema interface definitions -export interface GameSchema { +export interface Ruleset { id: string; label: string; blocks: Record; @@ -35,10 +43,10 @@ interface DefaultBlockDef { } export type CellDef = - | BoolCellDef - | MultiplierCellDef - | NumberCellDef - | YahtzeeCellDef; + | BoolCellDef + | MultiplierCellDef + | NumberCellDef + | SuperkadiCellDef; export interface BoolCellDef extends DefaultCellDef { fieldType: FieldType.bool; @@ -51,10 +59,10 @@ export interface MultiplierCellDef extends DefaultCellDef { maxMultiples: number; } -export interface YahtzeeCellDef extends DefaultCellDef { - fieldType: FieldType.yahtzee; +export interface SuperkadiCellDef extends DefaultCellDef { + fieldType: FieldType.superkadi; score: number; - maxYahtzees: number; + maxSuperkadis: number; } export interface NumberCellDef extends DefaultCellDef { @@ -65,11 +73,12 @@ interface DefaultCellDef { label: string; } + // ----- Predefined sets const defaultDiceCount = 5; const DEFAULT_RULESET = "DEFAULT_RULESET"; -const gameSchemas: GameSchema[] = [ +const gameSchemas: Ruleset[] = [ { id: DEFAULT_RULESET, label: "Standard Kadi Rules (en)", @@ -127,39 +136,39 @@ const gameSchemas: GameSchema[] = [ label: "Lower", hasBonus: false, cells: { - three_kind: { + threeKind: { fieldType: FieldType.number, label: "Three of a Kind", }, - four_kind: { + fourKind: { fieldType: FieldType.number, label: "Four of a Kind", }, - full_house: { + fullHouse: { fieldType: FieldType.bool, label: "Full House", score: 25, }, - sml_straight: { + smlStraight: { fieldType: FieldType.bool, label: "Small Straight", score: 30, }, - lg_straight: { + lgSraight: { fieldType: FieldType.bool, label: "Large Straight", score: 40, }, - yahtzee: { - fieldType: FieldType.yahtzee, - label: "Kadi", + kadi: { + fieldType: FieldType.superkadi, + label: "Super Kadis", score: 50, - maxYahtzees: 5, + maxSuperkadis: 5, }, chance: { @@ -227,34 +236,34 @@ const gameSchemas: GameSchema[] = [ label: "Unten", hasBonus: false, cells: { - three_kind: { + threeKind: { fieldType: FieldType.number, label: "Dreierpasch", }, - four_kind: { + fourKind: { fieldType: FieldType.number, label: "Viererpasch", }, - full_house: { + fullSouse: { fieldType: FieldType.bool, label: "Full House", score: 25, }, - sml_straight: { + smlStraight: { fieldType: FieldType.bool, label: "Kleine Straße", score: 30, }, - lg_straight: { + lgStraight: { fieldType: FieldType.bool, label: "Große Straße", score: 40, }, - yahtzee: { - fieldType: FieldType.yahtzee, - label: "Kadi", + kadi: { + fieldType: FieldType.superkadi, + label: "Ultrakadi", score: 50, - maxYahtzees: 5, + maxSuperkadis: 5, }, change: { fieldType: FieldType.number, @@ -266,7 +275,7 @@ const gameSchemas: GameSchema[] = [ }, ]; -export function getGameSchemaById(schemaId: string): GameSchema { +export function getGameSchemaById(schemaId: string): Ruleset { for (const schema of gameSchemas) { if (schema.id === schemaId) { return schema;