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.
70 lines (64 loc) • 2.73 kB
text/typescript
import { all, any, curry, lens, lensProp, pipe, view } from 'ramda'
import { match } from 'ts-pattern'
import { addBonusAction, revertActivePlayerToCurrent, setFrameToAllowFreeUsage, withFrame } from '../board/frame'
import { moveClergyToOwnBuilding } from '../board/landscape'
import { activeLens, isLayBrother, isPrior } from '../board/player'
import { GameCommandEnum, GameStatePlaying, NextUseClergy, StateReducer } from '../types'
// there are two modes of this, really...
// first, if activePlayer == currentPlayer, then make it so the next "use" is with a prior
// -> fail if they have no prior available
// -> otherwise set the nextUse = NextUseClergy.OnlyPrior
const withPriorForCurrentPlayer: StateReducer = (state) => {
if (state === undefined) return undefined
if (state.players[state.frame.activePlayerIndex].clergy.some(isPrior) === false) return undefined
return withFrame((frame) => ({
...frame,
nextUse: NextUseClergy.OnlyPrior,
mainActionUsed: true,
}))(state)
}
// second, if activePlayer != currentPlayer, as in a work contract, then
// -> move the player's prior onto the building in usableBuildings (work contracted building)
// -> set the nextUse = NextUseClergy.Free
// -> set the activePlayer back to currentPlayer
const withPriorForWorkContract: StateReducer = (state) => {
if (state === undefined) return undefined
if (state.frame.usableBuildings.length !== 1) return undefined
return pipe(
//
withPriorForCurrentPlayer,
moveClergyToOwnBuilding(state.frame.usableBuildings[0]),
setFrameToAllowFreeUsage([state.frame.usableBuildings[0]]),
revertActivePlayerToCurrent
)(state)
}
export const withPrior: StateReducer = (state) => {
if (state === undefined) return undefined
if (state.frame.activePlayerIndex === state.frame.currentPlayerIndex) {
return pipe(
//
withPriorForCurrentPlayer,
addBonusAction(GameCommandEnum.USE)
)(state)
}
return withPriorForWorkContract(state)
}
export const complete =
(state: GameStatePlaying) =>
(partial: string[]): string[] =>
match<string[], string[]>(partial)
.with([], () => {
const player = view(activeLens(state), state)
const control = view(lensProp('frame'), state)
if (control.activePlayerIndex === control.currentPlayerIndex) {
// this is the normal case, outside of work_contract
if (control.nextUse === NextUseClergy.OnlyPrior) return []
if (control.mainActionUsed) return []
}
if (all(isLayBrother, player.clergy)) return []
return [GameCommandEnum.WITH_PRIOR]
})
.with([GameCommandEnum.WITH_PRIOR], () => {
return ['']
})
.otherwise(() => [])