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.
123 lines (119 loc) • 4.87 kB
text/typescript
import { assoc, equals, isNotNil, lensPath, pathSatisfies, pipe, set, union, when } from 'ramda'
import { match } from 'ts-pattern'
import { PlayerColor, SettlementCost, SettlementEnum, SettlementRound, StateReducer } from '../types'
import { withEachPlayer } from './player'
export const costForSettlement = (settlement: SettlementEnum): SettlementCost =>
match<SettlementEnum, SettlementCost>(settlement)
.with(
SettlementEnum.ShantyTownR,
SettlementEnum.ShantyTownG,
SettlementEnum.ShantyTownB,
SettlementEnum.ShantyTownW,
() => ({ food: 1, energy: 1 })
)
.with(
SettlementEnum.FarmingVillageR,
SettlementEnum.FarmingVillageG,
SettlementEnum.FarmingVillageB,
SettlementEnum.FarmingVillageW,
() => ({ food: 3, energy: 3 })
)
.with(
SettlementEnum.MarketTownR,
SettlementEnum.MarketTownG,
SettlementEnum.MarketTownB,
SettlementEnum.MarketTownW,
() => ({ food: 7, energy: 0 })
)
.with(
SettlementEnum.FishingVillageR,
SettlementEnum.FishingVillageG,
SettlementEnum.FishingVillageB,
SettlementEnum.FishingVillageW,
() => ({ food: 8, energy: 3 })
)
.with(
SettlementEnum.ArtistsColonyR,
SettlementEnum.ArtistsColonyG,
SettlementEnum.ArtistsColonyB,
SettlementEnum.ArtistsColonyW,
() => ({ food: 5, energy: 1 })
)
.with(SettlementEnum.HamletR, SettlementEnum.HamletG, SettlementEnum.HamletB, SettlementEnum.HamletW, () => ({
food: 5,
energy: 6,
}))
.with(SettlementEnum.VillageR, SettlementEnum.VillageG, SettlementEnum.VillageB, SettlementEnum.VillageW, () => ({
food: 15,
energy: 9,
}))
.with(
SettlementEnum.HilltopVillageR,
SettlementEnum.HilltopVillageG,
SettlementEnum.HilltopVillageB,
SettlementEnum.HilltopVillageW,
() => ({ food: 30, energy: 3 })
)
.exhaustive()
export const roundSettlements = (color: PlayerColor, round?: SettlementRound): SettlementEnum[] =>
match<[PlayerColor, SettlementRound | undefined], SettlementEnum[]>([color, round])
.with([PlayerColor.Red, SettlementRound.S], () => [
SettlementEnum.ShantyTownR,
SettlementEnum.FarmingVillageR,
SettlementEnum.MarketTownR,
SettlementEnum.FishingVillageR,
])
.with([PlayerColor.Green, SettlementRound.S], () => [
SettlementEnum.ShantyTownG,
SettlementEnum.FarmingVillageG,
SettlementEnum.MarketTownG,
SettlementEnum.FishingVillageG,
])
.with([PlayerColor.Blue, SettlementRound.S], () => [
SettlementEnum.ShantyTownB,
SettlementEnum.FarmingVillageB,
SettlementEnum.MarketTownB,
SettlementEnum.FishingVillageB,
])
.with([PlayerColor.White, SettlementRound.S], () => [
SettlementEnum.ShantyTownW,
SettlementEnum.FarmingVillageW,
SettlementEnum.MarketTownW,
SettlementEnum.FishingVillageW,
])
.with([PlayerColor.Red, SettlementRound.A], () => [SettlementEnum.ArtistsColonyR])
.with([PlayerColor.Green, SettlementRound.A], () => [SettlementEnum.ArtistsColonyG])
.with([PlayerColor.Blue, SettlementRound.A], () => [SettlementEnum.ArtistsColonyB])
.with([PlayerColor.White, SettlementRound.A], () => [SettlementEnum.ArtistsColonyW])
.with([PlayerColor.Red, SettlementRound.B], () => [SettlementEnum.HamletR])
.with([PlayerColor.Green, SettlementRound.B], () => [SettlementEnum.HamletG])
.with([PlayerColor.Blue, SettlementRound.B], () => [SettlementEnum.HamletB])
.with([PlayerColor.White, SettlementRound.B], () => [SettlementEnum.HamletW])
.with([PlayerColor.Red, SettlementRound.C], () => [SettlementEnum.VillageR])
.with([PlayerColor.Green, SettlementRound.C], () => [SettlementEnum.VillageG])
.with([PlayerColor.Blue, SettlementRound.C], () => [SettlementEnum.VillageB])
.with([PlayerColor.White, SettlementRound.C], () => [SettlementEnum.VillageW])
.with([PlayerColor.Red, SettlementRound.D], () => [SettlementEnum.HilltopVillageR])
.with([PlayerColor.Green, SettlementRound.D], () => [SettlementEnum.HilltopVillageG])
.with([PlayerColor.Blue, SettlementRound.D], () => [SettlementEnum.HilltopVillageB])
.with([PlayerColor.White, SettlementRound.D], () => [SettlementEnum.HilltopVillageW])
.otherwise(() => [])
export const introduceSettlements: StateReducer = (state) => {
return pipe(
//
withEachPlayer(
when(isNotNil, (player) =>
assoc(
'settlements',
union(player.settlements, roundSettlements(player.color, state?.frame.settlementRound)),
player
)
)
),
(state) => {
if (state === undefined) return state
if (state.config.players !== 1) return state
return set(lensPath(['players', 1, 'settlements']), [], state)
}
)(state)
}