58 lines
2.3 KiB
Scala
58 lines
2.3 KiB
Scala
package gambit
|
|
|
|
object TimeControl:
|
|
val defaultMovesToGo = 30
|
|
val overheadMs = 25L
|
|
val maxDepth = 64
|
|
|
|
final case class Limits(
|
|
wtime: Long = -1L,
|
|
btime: Long = -1L,
|
|
winc: Long = 0L,
|
|
binc: Long = 0L,
|
|
movestogo: Int = 0,
|
|
movetime: Long = -1L,
|
|
depth: Int = -1,
|
|
infinite: Boolean = false
|
|
):
|
|
def hasClock: Boolean = wtime >= 0L || btime >= 0L
|
|
|
|
final case class Plan(depth: Int, timeMs: Long)
|
|
|
|
def plan(limits: Limits, whiteToMove: Boolean): Plan =
|
|
val depth = if limits.depth > 0 then math.min(limits.depth, maxDepth) else maxDepth
|
|
val time = budgetMs(limits, whiteToMove)
|
|
Plan(depth, time)
|
|
|
|
def budgetMs(limits: Limits, whiteToMove: Boolean): Long =
|
|
if limits.infinite then 0L
|
|
else if limits.movetime > 0L then math.max(1L, limits.movetime - overheadMs)
|
|
else if limits.hasClock then
|
|
val myTime = if whiteToMove then limits.wtime else limits.btime
|
|
val myInc = if whiteToMove then limits.winc else limits.binc
|
|
if myTime <= 0L then math.max(1L, myInc - overheadMs)
|
|
else
|
|
val moves = if limits.movestogo > 0 then limits.movestogo else defaultMovesToGo
|
|
val base = myTime / moves + myInc * 3L / 4L
|
|
val hardCap = math.max(1L, (myTime * 4L) / 5L)
|
|
val budget = math.min(base, hardCap)
|
|
math.max(1L, budget - overheadMs)
|
|
else 0L
|
|
|
|
def parse(tokens: List[String]): Limits =
|
|
var limits = Limits()
|
|
var rest = tokens
|
|
while rest.nonEmpty do
|
|
rest match
|
|
case "wtime" :: v :: tail => limits = limits.copy(wtime = v.toLong); rest = tail
|
|
case "btime" :: v :: tail => limits = limits.copy(btime = v.toLong); rest = tail
|
|
case "winc" :: v :: tail => limits = limits.copy(winc = v.toLong); rest = tail
|
|
case "binc" :: v :: tail => limits = limits.copy(binc = v.toLong); rest = tail
|
|
case "movestogo" :: v :: tail => limits = limits.copy(movestogo = v.toInt); rest = tail
|
|
case "movetime" :: v :: tail => limits = limits.copy(movetime = v.toLong); rest = tail
|
|
case "depth" :: v :: tail => limits = limits.copy(depth = v.toInt); rest = tail
|
|
case "infinite" :: tail => limits = limits.copy(infinite = true); rest = tail
|
|
case _ :: tail => rest = tail
|
|
case Nil => rest = Nil
|
|
limits
|