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.

90 lines 5.12 kB
import { match } from 'ts-pattern'; import { always, head, map, pipe, sum } from 'ramda'; import { pickFrameFlow } from './board/frame'; import { GameCommandEnum, SettlementRound, GameStatusEnum, } from './types'; import { completeBuild, completeCommit, completeConvert, completeCutPeat, completeFellTrees, completeSettle, completeUse, completeWorkContract, completeWithLaybrother, completeWithPrior, completeBuyPlot, completeBuyDistrict, } from './commands'; import { costPoints } from './board/resource'; import { allBuildingPoints, allDwellingPoints } from './board/landscape'; import { introduceBuildings, roundBuildings } from './board/buildings'; import { introduceGrapeToken, introduceStoneToken } from './board/rondel'; const computeFlow = (state) => { var _a, _b, _c, _d, _e, _f, _g, _h, _j; const frameFlow = pickFrameFlow(state.config); const flow = []; let limit = 200; let frameIndex; let playerIndex = state.frame.activePlayerIndex; let { frame } = state; let { round } = frame; let lastSeenSettlementRound = SettlementRound.S; do { round = (_a = frame.round) !== null && _a !== void 0 ? _a : round; playerIndex = (_b = frame.currentPlayerIndex) !== null && _b !== void 0 ? _b : playerIndex; const settle = !!((_c = frame.bonusActions) === null || _c === void 0 ? void 0 : _c.includes(GameCommandEnum.SETTLE)) || !!frame.neutralBuildingPhase; lastSeenSettlementRound = (_d = frame.settlementRound) !== null && _d !== void 0 ? _d : lastSeenSettlementRound; flow.push({ round, player: (_f = (_e = state === null || state === void 0 ? void 0 : state.players) === null || _e === void 0 ? void 0 : _e[playerIndex]) === null || _f === void 0 ? void 0 : _f.color, settle, bonus: !!frame.bonusRoundPlacement, introduced: [ ...(((_g = frame.upkeep) === null || _g === void 0 ? void 0 : _g.includes(introduceBuildings)) ? roundBuildings(state.config, lastSeenSettlementRound) : []), ...(((_h = frame.upkeep) === null || _h === void 0 ? void 0 : _h.includes(introduceGrapeToken)) ? ['grape'] : []), ...(((_j = frame.upkeep) === null || _j === void 0 ? void 0 : _j.includes(introduceStoneToken)) ? ['stone'] : []), ], }); frameIndex = frame.next; frame = frameFlow[frame.next]; } while (frame && frameIndex < frame.next && limit--); return flow; }; export const control = (state, partial, player) => { const completion = match(head(partial)) .with(undefined, () => state.status === GameStatusEnum.FINISHED ? [] : [ ...completeUse(state)([]), ...completeBuild(state)([]), ...completeCutPeat(state)([]), ...completeFellTrees(state)([]), ...completeWorkContract(state)([]), ...completeBuyPlot(state)([]), ...completeBuyDistrict(state)([]), ...completeConvert(state)([]), ...completeSettle(state)([]), ...completeWithLaybrother(state)([]), ...completeWithPrior(state)([]), ...completeCommit(state)([]), ]) // this can be prettier with https://github.com/gvergnaud/ts-pattern/pull/139 // git blame this line and see how it used to be, but i really want something like // .with([GameCommandEnum.Use, P.rest], complete.USE(state)) .with(GameCommandEnum.USE, () => completeUse(state)(partial)) .with(GameCommandEnum.BUILD, () => completeBuild(state)(partial)) .with(GameCommandEnum.CUT_PEAT, () => completeCutPeat(state)(partial)) .with(GameCommandEnum.FELL_TREES, () => completeFellTrees(state)(partial)) .with(GameCommandEnum.WORK_CONTRACT, () => completeWorkContract(state)(partial)) .with(GameCommandEnum.BUY_PLOT, () => completeBuyPlot(state)(partial)) .with(GameCommandEnum.BUY_DISTRICT, () => completeBuyDistrict(state)(partial)) .with(GameCommandEnum.CONVERT, () => completeConvert(state)(partial)) .with(GameCommandEnum.SETTLE, () => completeSettle(state)(partial)) .with(GameCommandEnum.WITH_LAYBROTHER, () => completeWithLaybrother(state)(partial)) .with(GameCommandEnum.WITH_PRIOR, () => completeWithPrior(state)(partial)) .with(GameCommandEnum.COMMIT, () => completeCommit(state)(partial)) .otherwise(always([])); const score = map(pipe((player) => ({ goods: costPoints(player) + 30 * player.wonders, economic: allBuildingPoints(player.landscape), settlements: allDwellingPoints(player.landscape), total: -Infinity, }), (score) => (Object.assign(Object.assign({}, score), { total: sum([...score.settlements, score.goods, score.economic]) }))), state.players.slice(0, state.config.players) // this will remove neutral player ); return { active: player === state.frame.activePlayerIndex, flow: computeFlow(state), partial, completion, score, }; }; //# sourceMappingURL=control.js.map