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.

148 lines (138 loc) 3.82 kB
import { createShuffle } from 'fast-shuffle' import { createPcg32, randomInt } from 'fn-pcg' import { pipe, range } from 'ramda' import { nextFrame } from '../board/frame' import { districtPrices, makeLandscape, plotPrices } from '../board/landscape' import { clergyForColor } from '../board/player' import { GameCommandStartParams, GameStatePlaying, GameStateSetup, GameStatusEnum, NextUseClergy, PlayerColor, SettlementRound, } from '../types' // we could get more entropy with a second seed, but // honestly this is fine for now. const PCG_PERIOD = 42069 // this is a brute-forced seed given the above, which // results in a noop shuffle for 2, 3, 4, or even 5 elements const MAGIC_SEED = 2692 const neutralColor = (notThisColor: PlayerColor, neutralColorIndex: number) => [ // pick a color that the player isn't using PlayerColor.Red, PlayerColor.Blue, PlayerColor.Green, PlayerColor.White, ].filter((c) => c !== notThisColor)[neutralColorIndex] export const start = ( state: GameStateSetup, { seed, colors }: GameCommandStartParams ): GameStatePlaying | undefined => { if (state.rondel === undefined) return undefined if (state.config === undefined) return undefined if (colors.length < 1 || colors.length > 4) return undefined const seedUsed = seed ?? MAGIC_SEED let randGen = createPcg32({}, seedUsed, PCG_PERIOD) const [playerOrderSeed, randGen1] = randomInt(0, 2 ** 32 - 1, randGen) randGen = randGen1 const shuffledColors = createShuffle(playerOrderSeed, colors) const playerIndexes = range(0, state.config.players) const players = playerIndexes.map((i) => { return { landscapeOffset: 0, wonders: 0, peat: 0, penny: 0, clay: 0, wood: 0, grain: 0, sheep: 0, stone: 0, flour: 0, grape: 0, nickel: 0, malt: 0, coal: 0, book: 0, ceramic: 0, whiskey: 0, straw: 0, meat: 0, ornament: 0, bread: 0, wine: 0, beer: 0, reliquary: 0, color: shuffledColors[i], landscape: makeLandscape(shuffledColors[i]), clergy: clergyForColor(state.config)(shuffledColors[i]), settlements: [], } }) // feels weird to do this here, but i think it's more difficult to pass along the // neutral player's color IF we had it and generate it later from addNeutralPlayer if (state.config.players === 1) { if (seed === undefined) { players.push({ ...players[0], color: shuffledColors[1], landscape: [[]], clergy: [], }) } else { const [neutralColorIndex, randGen2] = randomInt(0, 3, randGen) randGen = randGen2 const color = neutralColor(players[0].color, neutralColorIndex) players.push({ ...players[0], color, landscape: [[]], clergy: [], }) } } const newState: GameStatePlaying = { ...state, config: state.config, randGen: randGen1, status: GameStatusEnum.PLAYING, players, rondel: { ...state.rondel, grain: 0, peat: 0, sheep: 0, clay: 0, coin: 0, wood: 0, joker: 0, }, wonders: 8, frame: { next: 1, round: 1, startingPlayer: 0, settlementRound: SettlementRound.S, currentPlayerIndex: 0, activePlayerIndex: 0, neutralBuildingPhase: false, bonusRoundPlacement: false, mainActionUsed: false, bonusActions: [], canBuyLandscape: true, unusableBuildings: [], usableBuildings: [], nextUse: NextUseClergy.Any, }, buildings: [], plotPurchasePrices: plotPrices(state.config), districtPurchasePrices: districtPrices(state.config), } return pipe( // nextFrame )(newState) }