hathora-et-labora-game
Version:
Game logic reducer for Uwe Rosenberg's Ora et Labora
130 lines • 4.22 kB
JavaScript
import { createShuffle } from 'fast-shuffle';
import { createPcg32, randomInt } from 'pcg';
import { pipe, range } from 'ramda';
import { nextFrame } from '../board/frame';
import { districtPrices, makeLandscape, plotPrices } from '../board/landscape';
import { clergyForColor } from '../board/player';
import { 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, neutralColorIndex) => [
// 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, { seed, colors }) => {
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 = {
...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);
};
//# sourceMappingURL=start.js.map