Better chess clock implementation

pull/1/merge
Thibault Duplessis 2012-03-14 18:25:56 +01:00
parent aa00870a89
commit f97d3f478a
6 changed files with 96 additions and 39 deletions

View File

@ -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
}

View File

@ -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
)
}
}

View File

@ -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
)
)
}
}

View File

@ -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 {

View File

@ -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")
)

View File

@ -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
))
}
}