tsgammon-core
Version:
A Backgammon library for Typescript, formerly developed as a part of tsgammon-ui
334 lines (311 loc) • 8.46 kB
text/typescript
import { CubeOwner, CubeState } from '../CubeState'
import { eog, EOGStatus } from '../EOGStatus'
import { SGResult } from '../records/SGResult'
import { score, Score, scoreAsRed, scoreAsWhite } from '../Score'
import { applyStakeConf, StakeConf } from '../StakeConf'
/**
* バックギャモンの局面を示す状態を、キューブのみに限定した定義
*/
export type CBState =
| CBOpening
| CBInPlay
| CBAction
| CBResponse
| CBToRoll
| CBEoG
export type CBOpening = _CBState & {
tag: 'CBOpening'
doStartCheckerPlayRed: () => CBInPlayRed
doStartCheckerPlayWhite: () => CBInPlayWhite
}
export type CBAction = CBActionRed | CBActionWhite
export type CBResponse = CBResponseRed | CBResponseWhite
export type CBToRoll = CBToRollRed | CBToRollWhite
export type CBInPlay = CBInPlayRed | CBInPlayWhite
export type CBEoG = CBEoGRedWon | CBEoGWhiteWon | CBEoGNogame
type _CBState = {
cubeState: CubeState
}
type _CBAction = _CBState & {
tag: 'CBAction'
}
export type CBActionRed = _CBAction & {
isRed: true
doDouble: () => CBResponseWhite
doStartCheckerPlay: () => CBInPlayRed
doSkipCubeAction: () => CBToRollRed
}
export type CBActionWhite = _CBAction & {
isRed: false
doDouble: () => CBResponseRed
doStartCheckerPlay: () => CBInPlayWhite
doSkipCubeAction: () => CBToRollWhite
}
type _CBResponse = _CBState & {
tag: 'CBResponse'
isRed: boolean
}
export type CBResponseRed = _CBResponse & {
doTake: () => CBToRollWhite
doPass: () => CBEoGWhiteWon
isDoubleFromRed: false
isRed: true
}
export type CBResponseWhite = _CBResponse & {
doTake: () => CBToRollRed
doPass: () => CBEoGRedWon
isDoubleFromRed: true
isRed: false
}
type LastCubeAction = 'Take' | 'Skip'
type _CBToRoll = _CBState & {
tag: 'CBToRoll'
lastAction: LastCubeAction
}
export type CBToRollRed = _CBToRoll & {
isRed: true
doStartCheckerPlay: () => CBInPlayRed
}
export type CBToRollWhite = _CBToRoll & {
isRed: false
doStartCheckerPlay: () => CBInPlayWhite
}
type _CBInPlay = _CBState & {
tag: 'CBInPlay'
mayDouble: boolean
}
export type CBInPlayRed = _CBInPlay & {
isRed: true
doStartCubeAction: (
skipCubeAction: boolean
) => CBActionWhite | CBToRollWhite
}
export type CBInPlayWhite = _CBInPlay & {
isRed: false
doStartCubeAction: (skipCubeAction: boolean) => CBActionRed | CBToRollRed
}
type _CBEoG = _CBState & {
tag: 'CBEoG'
eogStatus: EOGStatus
isWonByPass: boolean
calcStake: (conf?: StakeConf) => {
stake: Score
eogStatus: EOGStatus
jacobyApplied: boolean
}
}
export type CBEoGRedWon = _CBEoG & {
result: SGResult.REDWON
}
export type CBEoGWhiteWon = _CBEoG & {
result: SGResult.WHITEWON
}
export type CBEoGNogame = _CBEoG & {
isWonByPass: false
result: SGResult.NOGAME
}
export function cbOpening(cubeState: CubeState): CBOpening {
return {
tag: 'CBOpening',
cubeState,
doStartCheckerPlayRed: () => cbInPlayRed(cubeState),
doStartCheckerPlayWhite: () => cbInPlayWhite(cubeState),
}
}
export function cbActionRed(cubeState: CubeState): CBActionRed {
return {
tag: 'CBAction',
isRed: true,
cubeState,
doDouble: () => {
return cbResponseWhite(cubeState)
},
doStartCheckerPlay: () => {
return cbInPlayRed(cubeState)
},
doSkipCubeAction: () => {
return cbToRollRed(cubeState, 'Skip')
},
}
}
export function cbActionWhite(cubeState: CubeState): CBActionWhite {
return {
tag: 'CBAction',
isRed: false,
cubeState,
doDouble: () => {
return cbResponseRed(cubeState)
},
doStartCheckerPlay: () => {
return cbInPlayWhite(cubeState)
},
doSkipCubeAction: () => {
return cbToRollWhite(cubeState, 'Skip')
},
}
}
export function cbInPlayRed(cubeState: CubeState): CBInPlayRed {
const mayDouble = cubeState.mayDoubleFor(CubeOwner.WHITE)
return {
tag: 'CBInPlay',
isRed: true,
cubeState,
mayDouble,
doStartCubeAction(
skipCubeAction: boolean
): CBActionWhite | CBToRollWhite {
return mayDouble && !skipCubeAction
? cbActionWhite(cubeState)
: cbToRollWhite(cubeState, 'Skip')
},
}
}
export function cbInPlayWhite(cubeState: CubeState): CBInPlayWhite {
const mayDouble = cubeState.mayDoubleFor(CubeOwner.RED)
return {
tag: 'CBInPlay',
isRed: false,
cubeState,
mayDouble,
doStartCubeAction(skipCubeAction: boolean): CBActionRed | CBToRollRed {
return mayDouble && !skipCubeAction
? cbActionRed(cubeState)
: cbToRollRed(cubeState, 'Skip')
},
}
}
export function cbResponseRed(cubeState: CubeState): CBResponseRed {
const cbResponse: CBResponseRed = {
tag: 'CBResponse',
isDoubleFromRed: false,
isRed: true,
cubeState,
doTake: () => {
return doAccept(CubeOwner.RED, cbToRollWhite, cubeState)
},
doPass: () => {
return cbEoGWhiteWon(cubeState, eog(), true)
},
}
return cbResponse
}
export function cbResponseWhite(cubeState: CubeState): CBResponseWhite {
const cbResponse: CBResponseWhite = {
tag: 'CBResponse',
isDoubleFromRed: true,
isRed: false,
cubeState,
doTake: () => {
return doAccept(CubeOwner.WHITE, cbToRollRed, cubeState)
},
doPass: () => {
return cbEoGRedWon(cubeState, eog(), true)
},
}
return cbResponse
}
function doAccept<T extends CBToRoll>(
side: CubeOwner,
cbToRoll: (cubeState: CubeState, cubeAction: LastCubeAction) => T,
cubeState: CubeState
): T {
return cbToRoll(cubeState.double(side), 'Take')
}
export function cbToRollRed(
cubeState: CubeState,
lastAction: LastCubeAction
): CBToRollRed {
return {
tag: 'CBToRoll',
isRed: true,
cubeState,
doStartCheckerPlay: () => {
return cbInPlayRed(cubeState)
},
lastAction,
}
}
export function cbToRollWhite(
cubeState: CubeState,
lastAction: LastCubeAction
): CBToRollWhite {
return {
tag: 'CBToRoll',
isRed: false,
cubeState,
doStartCheckerPlay: () => {
return cbInPlayWhite(cubeState)
},
lastAction,
}
}
export function resultToCBEoG(
cubeState: CubeState,
sgResult: SGResult,
eogStatus: EOGStatus
): CBEoG {
switch (sgResult) {
case SGResult.WHITEWON:
return cbEoGWhiteWon(cubeState, eogStatus, false)
case SGResult.REDWON:
return cbEoGRedWon(cubeState, eogStatus, false)
case SGResult.NOGAME:
return cbEoGNogame(cubeState, eogStatus)
}
}
function cbEoGRedWon(
cubeState: CubeState,
eogStatus: EOGStatus,
isWonByPass: boolean
): CBEoGRedWon {
return {
tag: 'CBEoG',
cubeState,
result: SGResult.REDWON,
eogStatus,
isWonByPass,
calcStake: (stakeConf?: StakeConf) => {
const applied = applyStakeConf(cubeState, eogStatus, stakeConf)
return {
...applied,
stake: scoreAsRed(applied.stake),
}
},
}
}
function cbEoGWhiteWon(
cubeState: CubeState,
eogStatus: EOGStatus,
isWonByPass: boolean
): CBEoGWhiteWon {
return {
tag: 'CBEoG',
cubeState,
result: SGResult.WHITEWON,
eogStatus,
isWonByPass,
calcStake: (stakeConf?: StakeConf) => {
const applied = applyStakeConf(cubeState, eogStatus, stakeConf)
return {
...applied,
stake: scoreAsWhite(applied.stake),
}
},
}
}
function cbEoGNogame(cubeState: CubeState, eogStatus: EOGStatus): CBEoGNogame {
return {
tag: 'CBEoG',
cubeState,
result: SGResult.NOGAME,
eogStatus,
isWonByPass: false,
calcStake: () => {
return {
stake: score(),
eogStatus,
jacobyApplied: false,
}
},
}
}