Better chess clock and implementation

pull/1/merge
Thibault Duplessis 2012-03-15 21:58:00 +01:00
parent dd63efc80e
commit c7fd3d8760
6 changed files with 72 additions and 29 deletions

2
bc 100644
View File

@ -0,0 +1,2 @@
Game.lastMove (and no more in pieces notation)
clock time in milliseconds (and no more floating seconds)

View File

@ -2,12 +2,13 @@ package lila.chess
import scala.math.max
// All durations are expressed in milliseconds
sealed trait Clock {
val color: Color
val whiteTime: Long
val blackTime: Long
val increment: Int
val limit: Int
val increment: Int
val color: Color
val whiteTime: Int
val blackTime: Int
val timer: Long
def time(c: Color) = if (c == White) whiteTime else blackTime
@ -20,50 +21,64 @@ sealed trait Clock {
def elapsedTime(c: Color) = time(c)
def limitInMinutes = limit / 60
def limitInSeconds = limit / 1000
def now = System.currentTimeMillis
def limitInMinutes = limitInSeconds / 60
def estimateTotalTime = limit + 30 * increment
def step: RunningClock
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,
limit: Int,
increment: Int,
limit: Int) extends Clock {
color: Color = White,
whiteTime: Int = 0,
blackTime: Int = 0,
timer: Long = 0l) extends Clock {
override def elapsedTime(c: Color) = time(c) + {
if (c == color) now - timer else 0
if (c == color) (now - timer).toInt else 0
}
def step =
addTime(color, max(0, now - timer - Clock.httpDelay - increment)).copy(
addTime(
color,
max(0, (now - timer).toInt - Clock.httpDelay - increment)
).copy(
color = !color,
timer = now
)
def addTime(c: Color, t: Long) = c match {
def addTime(c: Color, t: Int) = c match {
case White copy(whiteTime = whiteTime + t)
case Black copy(blackTime = blackTime + t)
}
def giveTime(c: Color, t: Long) = addTime(c, -t)
def giveTime(c: Color, t: Int) = addTime(c, -t)
private def now = System.currentTimeMillis
}
case class PausedClock(
color: Color = White,
whiteTime: Long = 0l,
blackTime: Long = 0l,
limit: Int,
increment: Int,
limit: Int) extends Clock {
color: Color = White,
whiteTime: Int = 0,
blackTime: Int = 0) extends Clock {
val timer = 0l
val timer = 0l
def step = RunningClock(
color = color,
whiteTime = whiteTime,
blackTime = blackTime,
increment = increment,
limit = limit).giveTime(White, increment).step
}
object Clock {

View File

@ -21,6 +21,7 @@ case class Game(
board = move.finalizeAfter,
player = !player,
turns = turns + 1,
clock = clock map (_.step),
deads = (for {
cpos move.capture
cpiece board(cpos)
@ -30,12 +31,6 @@ case class Game(
(newGame.copy(pgnMoves = (pgnMoves + " " + pgnMove).trim), move)
}
def playMove(
orig: Pos,
dest: Pos,
promotion: PromotableRole = Queen): Valid[Game] =
apply(orig, dest, promotion) map (_._1)
lazy val situation = Situation(board, player)
def pgnMovesList = pgnMoves.split(' ').toList
@ -54,5 +49,5 @@ case class Game(
*/
def fullMoveNumber: Int = 1 + turns / 2
def updateBoard(f: Board Board) = copy(board = f(board))
def updateBoard(f: Board => Board) = copy(board = f(board))
}

View File

@ -25,8 +25,16 @@ trait ChessTest
def playMoveList(moves: Iterable[(Pos, Pos)]): Valid[Game] =
moves.foldLeft(success(game): Valid[Game]) { (vg, move)
vg flatMap { g g.playMove(move._1, move._2) }
vg flatMap { g g(move._1, move._2) map (_._1) }
}
def playMove(
orig: Pos,
dest: Pos,
promotion: PromotableRole = Queen): Valid[Game] =
game.apply(orig, dest, promotion) map (_._1)
def withClock(c: Clock) = game.copy(clock = Some(c))
}
def bePoss(poss: Pos*): Matcher[Option[Iterable[Pos]]] = beSome.like {

View File

@ -0,0 +1,23 @@
package lila.chess
import Pos._
class ClockTest extends ChessTest {
"play with a clock" in {
val clock = PausedClock(5 * 60 * 1000, 0)
val game = Game() withClock clock
"new game" in {
game.clock must beSome.like {
case c c.color must_== White
}
}
"one move played" in {
game.playMoves(E2 -> E4) must beSuccess.like {
case g g.clock must beSome.like {
case c c.color must_== Black
}
}
}
}
}

View File

@ -7,7 +7,7 @@ case class RawDbClock(
color: String,
increment: Int,
limit: Int,
times: Map[String, Long],
times: Map[String, Int],
timer: Long = 0l) {
def decode: Option[Clock] = for {