diff --git a/bc b/bc new file mode 100644 index 0000000000..d65f8df860 --- /dev/null +++ b/bc @@ -0,0 +1,2 @@ +Game.lastMove (and no more in pieces notation) +clock time in milliseconds (and no more floating seconds) diff --git a/chess/src/main/scala/Clock.scala b/chess/src/main/scala/Clock.scala index c281c26c78..2f0935c09c 100644 --- a/chess/src/main/scala/Clock.scala +++ b/chess/src/main/scala/Clock.scala @@ -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 { diff --git a/chess/src/main/scala/Game.scala b/chess/src/main/scala/Game.scala index e1b0d610db..b866cccbaa 100644 --- a/chess/src/main/scala/Game.scala +++ b/chess/src/main/scala/Game.scala @@ -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)) } diff --git a/chess/src/test/scala/ChessTest.scala b/chess/src/test/scala/ChessTest.scala index fbefc616aa..6a69585946 100644 --- a/chess/src/test/scala/ChessTest.scala +++ b/chess/src/test/scala/ChessTest.scala @@ -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 { diff --git a/chess/src/test/scala/ClockTest.scala b/chess/src/test/scala/ClockTest.scala new file mode 100644 index 0000000000..c7624ab372 --- /dev/null +++ b/chess/src/test/scala/ClockTest.scala @@ -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 + } + } + } + } +} diff --git a/system/src/main/scala/model/RawDbClock.scala b/system/src/main/scala/model/RawDbClock.scala index b2bb4c5e21..09f1c8601f 100644 --- a/system/src/main/scala/model/RawDbClock.scala +++ b/system/src/main/scala/model/RawDbClock.scala @@ -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 {