Better chess clock implementation
parent
aa00870a89
commit
f97d3f478a
|
@ -1,11 +1,72 @@
|
|||
package lila.chess
|
||||
|
||||
case class Clock(
|
||||
color: Color,
|
||||
increment: Int,
|
||||
limit: Int,
|
||||
whiteTime: Float,
|
||||
blackTime: Float) {
|
||||
import scala.math.max
|
||||
|
||||
val times: Map[Color, Float] = Map(White -> whiteTime, Black -> blackTime)
|
||||
sealed trait Clock {
|
||||
val color: Color
|
||||
val whiteTime: Long
|
||||
val blackTime: Long
|
||||
val increment: Int
|
||||
val limit: Int
|
||||
val timer: Long
|
||||
|
||||
def time(c: Color) = if (c == White) whiteTime else blackTime
|
||||
|
||||
def isOutOfTime(c: Color) = remainingTime(c) == 0
|
||||
|
||||
def remainingTime(c: Color) = max(limit, elapsedTime(c))
|
||||
|
||||
def remainingTimes = Color.all map { c ⇒ (c, remainingTime(c)) }
|
||||
|
||||
def elapsedTime(c: Color) = time(c)
|
||||
|
||||
def limitInMinutes = limit / 60
|
||||
|
||||
def now = System.currentTimeMillis
|
||||
|
||||
def estimateTotalTime = limit + 30 * increment
|
||||
|
||||
override def toString =
|
||||
"%d minutes/side + %d seconds/move".format(limitInMinutes, increment)
|
||||
}
|
||||
|
||||
case class RunningClock(
|
||||
color: Color = White,
|
||||
whiteTime: Long = 0l,
|
||||
blackTime: Long = 0l,
|
||||
timer: Long = 0l,
|
||||
increment: Int,
|
||||
limit: Int) extends Clock {
|
||||
|
||||
override def elapsedTime(c: Color) = time(c) + {
|
||||
if (c == color) now - timer else 0
|
||||
}
|
||||
|
||||
def step =
|
||||
addTime(color, max(0, now - timer - Clock.httpDelay - increment)).copy(
|
||||
color = !color,
|
||||
timer = now
|
||||
)
|
||||
|
||||
def addTime(c: Color, t: Long) = c match {
|
||||
case White ⇒ copy(whiteTime = whiteTime + t)
|
||||
case Black ⇒ copy(blackTime = blackTime + t)
|
||||
}
|
||||
|
||||
def giveTime(c: Color, t: Long) = addTime(c, -t)
|
||||
}
|
||||
|
||||
case class PausedClock(
|
||||
color: Color = White,
|
||||
whiteTime: Long = 0l,
|
||||
blackTime: Long = 0l,
|
||||
increment: Int,
|
||||
limit: Int) extends Clock {
|
||||
|
||||
val timer = 0l
|
||||
}
|
||||
|
||||
object Clock {
|
||||
|
||||
val httpDelay = 500
|
||||
}
|
||||
|
|
|
@ -7,19 +7,28 @@ case class RawDbClock(
|
|||
color: String,
|
||||
increment: Int,
|
||||
limit: Int,
|
||||
times: Map[String, Float]) {
|
||||
times: Map[String, Long],
|
||||
timer: Long = 0l) {
|
||||
|
||||
def decode: Option[Clock] = for {
|
||||
trueColor ← Color(color)
|
||||
whiteTime ← times get "white"
|
||||
blackTime ← times get "black"
|
||||
} yield Clock(
|
||||
color = trueColor,
|
||||
increment = increment,
|
||||
limit = limit,
|
||||
whiteTime = whiteTime,
|
||||
blackTime = blackTime
|
||||
)
|
||||
} yield {
|
||||
if (timer == 0l) PausedClock(
|
||||
color = trueColor,
|
||||
increment = increment,
|
||||
limit = limit,
|
||||
whiteTime = whiteTime,
|
||||
blackTime = blackTime)
|
||||
else RunningClock(
|
||||
color = trueColor,
|
||||
increment = increment,
|
||||
limit = limit,
|
||||
whiteTime = whiteTime,
|
||||
blackTime = blackTime,
|
||||
timer = timer)
|
||||
}
|
||||
}
|
||||
|
||||
object RawDbClock {
|
||||
|
@ -33,7 +42,8 @@ object RawDbClock {
|
|||
times = Map(
|
||||
"white" -> whiteTime,
|
||||
"black" -> blackTime
|
||||
)
|
||||
),
|
||||
timer = timer
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -62,17 +62,4 @@ object RawDbGame {
|
|||
variant = variant.id
|
||||
)
|
||||
}
|
||||
|
||||
def encode(clock: Clock): RawDbClock = {
|
||||
import clock._
|
||||
RawDbClock(
|
||||
color = color.name,
|
||||
increment = increment,
|
||||
limit = limit,
|
||||
times = Map(
|
||||
"white" -> whiteTime,
|
||||
"black" -> blackTime
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,7 +7,6 @@ import com.novus.salat._
|
|||
package object system
|
||||
extends OrnicarValidation
|
||||
with OrnicarCommon
|
||||
//with OrnicarNonEmptyLists
|
||||
with scalaz.NonEmptyLists
|
||||
with scalaz.Strings
|
||||
with scalaz.Booleans {
|
||||
|
|
|
@ -63,12 +63,12 @@ trait Fixtures {
|
|||
pgn = "e4 e5 Qh5 Qf6 Nf3 g6 Qxe5+ Qxe5 Nxe5 Nf6 Nc3 Nc6 Nxc6 bxc6 e5 Nd5 Nxd5 cxd5 d4 Rb8 c3 d6 Be2 dxe5 dxe5 Rg8 Bf3 d4 cxd4 Bb4+ Ke2 g5 a3 g4 Bc6+ Bd7 Bxd7+ Kxd7 axb4 Rxb4 Kd3 Rb3+ Kc4 Rb6 Rxa7 Rc6+ Kb5 Rb8+ Ka5 Rc4 Rd1 Kc6 d5+ Kc5 Rxc7#",
|
||||
status = Mate,
|
||||
turns = 55,
|
||||
clock = Clock(
|
||||
clock = PausedClock(
|
||||
color = Black,
|
||||
increment = 5,
|
||||
limit = 1200,
|
||||
whiteTime = 196.25f,
|
||||
blackTime = 304.1f
|
||||
whiteTime = 196250l,
|
||||
blackTime = 304100l
|
||||
).some,
|
||||
lastMove = Some("a7 c7")
|
||||
)
|
||||
|
@ -105,12 +105,12 @@ trait Fixtures {
|
|||
pgn = "b3 d5 Bb2 e6 a3 a6 g3 h6 Bg2 f5 h3 Nf6 Bf1 Be7 e3 O-O Bg2 Bd7 h4 c5 h5 Nc6 f3 d4 g4 dxe3 dxe3 fxg4 fxg4 e5 g5 hxg5 h6 g6 h7+ Kh8 Bxc6 Bxc6 Bxe5 Qxd1+ Kxd1 Rf7 Bxf6+ Bxf6 Rh2 Bxa1 c3 Rd8+ Kc2 Rf3 Rd2 Rxe3 Rxd8+ Kxh7 Rd2",
|
||||
status = Outoftime,
|
||||
turns = 55,
|
||||
clock = Some(Clock(
|
||||
clock = Some(PausedClock(
|
||||
color = Black,
|
||||
increment = 0,
|
||||
limit = 60,
|
||||
whiteTime = 27.61f,
|
||||
blackTime = 60.24f
|
||||
whiteTime = 27610l,
|
||||
blackTime = 60240l
|
||||
)),
|
||||
lastMove = Some("d8 d2")
|
||||
)
|
||||
|
|
|
@ -72,12 +72,12 @@ K kPP
|
|||
game.board.history.lastMove must_== (A7, C7).some
|
||||
}
|
||||
"clock" in {
|
||||
game.clock must_== Some(Clock(
|
||||
game.clock must_== Some(PausedClock(
|
||||
color = Black,
|
||||
increment = 5,
|
||||
limit = 1200,
|
||||
whiteTime = 196.25f,
|
||||
blackTime = 304.1f
|
||||
whiteTime = 196250l,
|
||||
blackTime = 304100l
|
||||
))
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue