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.

110 lines (101 loc) 3.57 kB
import { always, lift, map, pipe, range, reverse, view, without } from 'ramda' import { P, match } from 'ts-pattern' import { activeLens, subtractCoins, withActivePlayer } from '../board/player' import { GameCommandConvertParams, GameCommandEnum, GameStatePlaying, ResourceEnum, Tableau } from '../types' import { stringRepeater } from '../board/resource' const convertGrain = (amount = 0) => (player: Tableau | undefined) => player && { ...player, grain: (player.grain ?? 0) - amount, straw: (player.straw ?? 0) + amount, } const convertWine = (amount = 0) => (player: Tableau | undefined) => player && { ...player, wine: (player.wine ?? 0) - amount, penny: (player.penny ?? 0) + amount, } const convertNickel = (amount = 0) => (player: Tableau | undefined) => player && { ...player, nickel: (player.nickel ?? 0) - amount, penny: (player.penny ?? 0) + amount * 5, } const convertWhiskey = (amount = 0) => (player: Tableau | undefined) => player && { ...player, whiskey: (player.whiskey ?? 0) - amount, penny: (player.penny ?? 0) + amount * 2, } const convertPenny = (amount = 0) => (player: Tableau | undefined) => { const subtracted = subtractCoins(amount)(player) if (subtracted === undefined) return undefined const p = { ...subtracted } // janice, then do the thing p.nickel += amount / 5 p.penny += amount % 5 return p } export const convert = ({ grain, wine, nickel, whiskey, penny }: GameCommandConvertParams) => { if ((penny ?? 0) % 5 !== 0) return () => undefined return withActivePlayer( pipe( // convertGrain(grain), convertWine(wine), convertNickel(nickel), convertWhiskey(whiskey), convertPenny(penny) ) ) } export const complete = (state: GameStatePlaying) => (partial: string[]): string[] => match<string[], string[]>(partial) .with([], () => { if ( state.frame.currentPlayerIndex === state.frame.activePlayerIndex && withActivePlayer((player) => { if (!player) return player const { penny, grain, wine, nickel, whiskey } = player if (penny >= 5 || grain || wine || nickel || whiskey) return player return undefined })(state) ) { return [GameCommandEnum.CONVERT] } return [] }) .with([GameCommandEnum.CONVERT], () => { const { penny = 0, grain = 0, wine = 0, nickel = 0, whiskey = 0 } = view(activeLens(state), state) const convertMoney = [ ...map((s) => stringRepeater(ResourceEnum.Penny, 5 * s), reverse(range(1, 1 + Math.floor(penny / 5)))), ...map((s) => stringRepeater(ResourceEnum.Nickel, s), reverse(range(1, 1 + nickel))), '', ] const convertGrain = map((s) => stringRepeater(ResourceEnum.Grain, s), reverse(range(0, 1 + grain))) const convertWhiskey = map((s) => stringRepeater(ResourceEnum.Whiskey, s), reverse(range(0, 1 + whiskey))) const convertWine = map((s) => stringRepeater(ResourceEnum.Wine, s), reverse(range(0, 1 + wine))) return without<string>( [''], lift<(a: string, b: string, c: string, d: string) => string>((a, b, c, d) => a + b + c + d)( convertMoney, convertGrain, convertWhiskey, convertWine ) ) }) .with([GameCommandEnum.CONVERT, P._], always([''])) .otherwise(always([]))