binmat
Version:
binmat simulator
131 lines (130 loc) • 3.4 kB
JavaScript
import { doMove } from "./doMove.js"
import { makeState } from "./makeState.js"
import { parseMove } from "./parseMove.js"
import { StatusCodeMessages, StatusCode, Role, MoveKind } from "./shared.js"
import { generateArgsForDefender, generateArgsForAttacker } from "./generateArgs.js"
import "./doMoveCombat.js"
import "./doCombat.js"
import "@samual/lib/shuffle"
import "./doMoveDiscard.js"
import "./doMoveDraw.js"
import "./doMovePass.js"
import "./doMovePlay.js"
import "./doMovePlayFaceUp.js"
import "@samual/lib/assert"
function simulateGame(
defenderBrain,
attackerBrain,
{
timeLimit: timeLimit = 5e3,
defenderUserName: defenderUserName = "defender",
attackerUserName: attackerUserName = "attacker",
noThrow: noThrow = !1,
onMove: onMove,
state: state = makeState(),
defenderBinlog: defenderBinlog = [],
attackerBinlog: attackerBinlog = []
} = {}
) {
let endTime, winner, madeMove
for (;;) {
if (
((madeMove = !1),
(endTime = Date.now() + timeLimit),
defenderBrain(
{
caller: defenderUserName,
this_script: `${defenderUserName}.binmat_brain`,
cols: 0,
rows: 0,
calling_script: null
},
generateArgsForDefender(state, defenderUserName, attackerUserName, [
...defenderBinlog,
...attackerBinlog
]),
xform
),
!madeMove)
) {
if (!noThrow) throw new Error("defender brain did not attempt to make a move")
doDefaultMove()
}
if ((onMove?.(state, defenderBinlog), winner)) return winner
if (
((madeMove = !1),
(endTime = Date.now() + timeLimit),
attackerBrain(
{
caller: attackerUserName,
this_script: `${attackerUserName}.binmat_brain`,
cols: 0,
rows: 0,
calling_script: null
},
generateArgsForAttacker(state, defenderUserName, attackerUserName, [
...attackerBinlog,
...defenderBinlog
]),
xform
),
!madeMove)
) {
if (!noThrow) throw new Error("attacker brain did not attempt to make a move")
doDefaultMove()
}
if ((onMove?.(state, attackerBinlog), winner)) return winner
}
function xform({ op: op }) {
if (madeMove) {
if (noThrow) return { ok: !1 }
throw new Error("only 1 move per turn")
}
if (((madeMove = !0), Date.now() > endTime)) {
if (noThrow) return doDefaultMove()
throw new Error("made move too late")
}
let move
try {
move = parseMove(op)
} catch (error) {
if (noThrow) return doDefaultMove()
throw error
}
const result = doMove(state, move)
switch (result.status) {
case StatusCode.Ok:
break
case StatusCode.AttackerWin:
winner = Role.Attacker
break
case StatusCode.DefenderWin:
winner = Role.Defender
break
default:
if (noThrow) return doDefaultMove()
throw new Error(StatusCodeMessages[result.status])
}
return (
(state.turn % 2) + 1 == Role.Defender ? (attackerBinlog = result.binlog) : (defenderBinlog = result.binlog),
{ ok: !0 }
)
}
function doDefaultMove() {
const result = doMove(state, { kind: MoveKind.Pass })
switch (result.status) {
case StatusCode.Ok:
break
case StatusCode.DefenderWin:
winner = Role.Defender
break
default:
throw new Error(`unexpected status code ${result.status}`)
}
return (
(state.turn % 2) + 1 == Role.Defender ? (attackerBinlog = result.binlog) : (defenderBinlog = result.binlog),
{ ok: !1 }
)
}
}
export { simulateGame }