UNPKG

hathora-et-labora-game

Version:

Plays Uwe Rosenberg's Ora et Labora for the Hathora engine. It reduces a list of moves into a board game state.

118 lines (114 loc) 4.04 kB
import { match, P } from 'ts-pattern' import { BuildingEnum, GameCommandEnum, GameConfigCountry, GameConfigLength, GameConfigPlayers, GameState, GameStatePlaying, GameStateSetup, PlayerColor, SettlementEnum, } from './types' import { parseResourceParam } from './board/resource' import { build, commit, config, convert, cutPeat, fellTrees, settle, start, use, withLaybrother, withPrior, buyPlot, buyDistrict, workContract, } from './commands' const PPlot = P.union('MOUNTAIN', 'COAST') const PDistrict = P.union('HILLS', 'PLAINS') const PPlayerCount = P.union('1', '2', '3', '4') const PCountry = P.union('ireland', 'france') const PLength = P.union('short', 'long') export const reducer = (state: GameState, [command, ...params]: string[]): GameState | undefined => { return match<[string, string[]], GameState | undefined>([command, params]) .with([GameCommandEnum.COMMIT, []], () => commit(state as GameStatePlaying)) .with([GameCommandEnum.USE, P.array(P.string)], ([_command, [building, ...params]]) => use(building as BuildingEnum, params)(state as GameStatePlaying) ) .with([GameCommandEnum.BUILD, P.array(P.string)], ([_, [building, col, row]]) => build({ building: building as BuildingEnum, col: Number.parseInt(col, 10), row: Number.parseInt(row, 10), })(state as GameStatePlaying) ) .with([GameCommandEnum.CUT_PEAT, P.array(P.string)], ([_, [col, row, useJoker]]) => cutPeat({ col: Number.parseInt(col, 10), row: Number.parseInt(row, 10), useJoker: useJoker === 'Jo', })(state as GameStatePlaying) ) .with([GameCommandEnum.FELL_TREES, P.array(P.string)], ([_, [col, row, useJoker]]) => fellTrees({ col: Number.parseInt(col, 10), row: Number.parseInt(row ?? '', 10), useJoker: useJoker === 'Jo', })(state as GameStatePlaying) ) .with([GameCommandEnum.WORK_CONTRACT, P.array(P.string)], ([_, [building, paymentGift, withPrior]]) => workContract(building as BuildingEnum, paymentGift, withPrior === 'WITH_PRIOR')(state as GameStatePlaying) ) .with([GameCommandEnum.WITH_PRIOR, []], () => withPrior(state as GameStatePlaying)) .with([GameCommandEnum.WITH_LAYBROTHER, []], () => withLaybrother(state as GameStatePlaying)) .with([GameCommandEnum.BUY_PLOT, [P._, PPlot]], ([_, [y, side]]) => buyPlot({ y: Number.parseInt(y, 10), side: side, })(state as GameStatePlaying) ) .with([GameCommandEnum.BUY_DISTRICT, [P._, PDistrict]], ([_, [y, side]]) => buyDistrict({ y: Number.parseInt(y, 10), side: side, })(state as GameStatePlaying) ) .with([GameCommandEnum.CONVERT, [P.select('resources')]], ({ resources }) => convert(parseResourceParam(resources))(state as GameStatePlaying) ) .with([GameCommandEnum.SETTLE, P.array(P.string)], ([_, [settlement, col, row, resources]]) => settle({ settlement: settlement as SettlementEnum, col: Number.parseInt(col, 10), row: Number.parseInt(row, 10), resources, })(state as GameStatePlaying) ) .with([GameCommandEnum.CONFIG, [PPlayerCount, PCountry, PLength]], ([_, [players, country, length]]) => config({ players: Number.parseInt(players, 10) as GameConfigPlayers, length: length as GameConfigLength, country: country as GameConfigCountry, })(state as GameStateSetup) ) .with([GameCommandEnum.START, P.array(P.string)], ([_, params]) => { const seed = Number.parseInt(params[0], 10) if (Number.isNaN(seed)) { return start(state as GameStateSetup, { seed: undefined, colors: params as PlayerColor[], }) } return start(state as GameStateSetup, { seed, colors: params.slice(1) as PlayerColor[], }) }) .otherwise((command) => { throw new Error(`Unable to parse [${command.join(',')}]`) }) }