hathora-et-labora-game
Version:
Game logic reducer for Uwe Rosenberg's Ora et Labora
86 lines • 3.47 kB
JavaScript
import { curry, dropLast, head, last, map, pipe, reduce, splitAt, splitEvery, startsWith, take, view, without, } from 'ramda';
import { P, match } from 'ts-pattern';
import { activeLens, getCost, withActivePlayer } from '../board/player';
import { BuildingEnum } from '../types';
import { forestLocations, forestLocationsForCol } from '../board/landscape';
const removeForestAt = (player, [col, row]) => {
if (player === undefined)
return undefined;
const tile = player.landscape[row + player.landscapeOffset][col + 2];
if (tile === undefined)
return undefined;
const [land, building] = tile;
if (building !== BuildingEnum.Forest)
return undefined;
const landscape = [
...player.landscape.slice(0, row + player.landscapeOffset),
[
...player.landscape[row + player.landscapeOffset].slice(0, col + 2),
// the tile in question
[land],
...player.landscape[row + player.landscapeOffset].slice(col + 2 + 1),
],
...player.landscape.slice(row + player.landscapeOffset + 1),
];
return {
...player,
landscape,
};
};
export const printingOffice = (...coords) => {
if (coords.length % 2 === 1)
return () => undefined;
const pairs = take(4)(splitEvery(2)(map((n) => Number.parseInt(n, 10), coords)));
return withActivePlayer(pipe(
//
(state) => reduce(removeForestAt, state, pairs), getCost({ book: pairs.length })));
};
const forestPairs = (player) => (coords) => {
const forestsAlreadyCutDown = pipe(
//
splitEvery(2), map(([a, b]) => `${a} ${b}`))(coords);
const forestsRemaining = pipe(
//
forestLocations, without(forestsAlreadyCutDown))(player);
return [...forestsRemaining, ''];
};
const forestPairsWithColumn = (player) => (coords) => {
const coordPairs = splitEvery(2, coords);
const completePairs = dropLast(1, coordPairs);
const forestsCutDown = map(([a, b]) => `${a} ${b}`, completePairs);
const allForestsRemaining = forestLocations(player);
const forestsAfterCutDown = without(forestsCutDown, allForestsRemaining);
const coordsAvail = reduce((accum, coordPair) => {
const col = last(coords) ?? '';
if (startsWith(`${col} `, coordPair)) {
const [, row] = splitAt(col.length + 1, coordPair);
accum.push(row);
}
return accum;
}, [], forestsAfterCutDown);
return coordsAvail;
};
// TODO: this can be better
export const complete = curry((partial, state) => {
const player = view(activeLens(state), state);
return match(partial)
.with([], forestPairs(player))
.with([P._], (coords) => forestLocationsForCol(head(coords) ?? '', player))
.with([P._, P._], forestPairs(player))
.with([P._, P._, P._], forestPairsWithColumn(player))
.with([P._, P._, P._, P._], forestPairs(player))
.with([P._, P._, P._, P._, P._], forestPairsWithColumn(player))
.with([P._, P._, P._, P._, P._, P._], forestPairs(player))
.otherwise((param) => {
const locations = param;
if (locations?.length === 7) {
// well this is annoying, i can't check an array with more than 6 things?
return forestPairsWithColumn(player)(locations);
}
if (locations?.length === 8) {
return [''];
}
return [];
});
});
//# sourceMappingURL=printingOffice.js.map