test and implement binary clock storage

pull/83/head
Thibault Duplessis 2013-12-03 23:12:18 +01:00
parent dff14fb7b8
commit 9887cd7c1c
4 changed files with 131 additions and 4 deletions

9
doc/binary-clock 100644
View File

@ -0,0 +1,9 @@
limit 0-255 8 bits
increment 0-255 8 bits
w (centisec) 0-16M 24 bits
b (centisec) 0-16M 24 bits
timer (centis) 0-1E12 40 bits
= 13 bytes

View File

@ -8,6 +8,37 @@ import lila.db.ByteArray
object BinaryFormat {
object clock {
def write(clock: Clock): ByteArray = ByteArray {
def time(seconds: Float) = writeSignedInt24((seconds * 100).toInt)
def timer(seconds: Double) = writeLong40((seconds * 100).toLong)
Array(writeInt8(clock.limit), writeInt8(clock.increment)) ++
time(clock.whiteTime) ++
time(clock.blackTime) ++
timer(clock.timerOption getOrElse 0d) map (_.toByte)
}
def read(ba: ByteArray): Color => Clock = color ba.value map toInt match {
case Array(b1, b2, b3, b4, b5, b6, b7, b8, b9, b10, b11, b12, b13)
readLong40(b9, b10, b11, b12, b13) match {
case 0 PausedClock(
color = color,
limit = b1,
increment = b2,
whiteTime = readSignedInt24(b3, b4, b5).toFloat / 100,
blackTime = readSignedInt24(b6, b7, b8).toFloat / 100)
case timer RunningClock(
color = color,
limit = b1,
increment = b2,
whiteTime = readSignedInt24(b3, b4, b5).toFloat / 100,
blackTime = readSignedInt24(b6, b7, b8).toFloat / 100,
timer = timer.toDouble / 100)
}
}
}
object castleLastMoveTime {
def write(clmt: CastleLastMoveTime): ByteArray = {
@ -43,8 +74,7 @@ object BinaryFormat {
to posAt((b2 & 63) >> 3, b2 & 7)
if from != to
} yield from -> to,
lastMoveTime = Some((b3 << 16) + (b4 << 8) + b5) filter (0 !=)
)
lastMoveTime = readInt24(b3, b4, b5).some filter (0 !=))
}
}
}
@ -101,4 +131,32 @@ object BinaryFormat {
}
@inline private def toInt(b: Byte): Int = b & 0xff
def writeInt8(int: Int) = math.min(255, int)
private val int24Max = math.pow(2, 24).toInt
def writeInt24(int: Int) = {
val i = math.min(int24Max, int)
Array(i >> 16, (i >> 8) & 255, i & 255)
}
def readInt24(b1: Int, b2: Int, b3: Int) = (b1 << 16) + (b2 << 8) + b3
private val int23Max = math.pow(2, 23).toInt
def writeSignedInt24(int: Int) = {
val i = math.abs(math.min(int23Max, int))
val j = if (int < 0) i + int23Max else i
Array(j >> 16, (j >> 8) & 255, j & 255)
}
def readSignedInt24(b1: Int, b2: Int, b3: Int) = {
val i = (b1 << 16) + (b2 << 8) + b3
if (i > int23Max) int23Max - i else i
}
private val long40Max = math.pow(2, 40).toLong
def writeLong40(long: Long) = {
val i = math.min(long40Max, long)
Array(i >> 32, (i >> 24) & 255, (i >> 16) & 255, (i >> 8) & 255, i & 255) map (_.toInt)
}
def readLong40(b1: Int, b2: Int, b3: Int, b4: Int, b5: Int) =
(b1.toLong << 32) + (b2 << 24) + (b3 << 16) + (b4 << 8) + b5
}

View File

@ -434,8 +434,8 @@ object Game {
id -> o.id,
token -> o.token,
players -> List(
(_: Color) => o.whitePlayer,
(_: Color) => o.blackPlayer),
(_: Color) o.whitePlayer,
(_: Color) o.blackPlayer),
binaryPieces -> o.binaryPieces,
status -> o.status.id,
turns -> o.turns,

View File

@ -0,0 +1,60 @@
package lila.game
import scala.concurrent.duration._
import chess.Clock
import org.specs2.mutable._
import org.specs2.specification._
import lila.db.ByteArray
class BinaryClockTest extends Specification {
val _0_ = "00000000"
def write(c: Clock): List[String] =
(BinaryFormat.clock write c).toString.split(',').toList
def read(bytes: List[String]): Clock =
(BinaryFormat.clock read ByteArray.parseBytes(bytes))(chess.White)
def isomorphism(c: Clock): Clock =
(BinaryFormat.clock read (BinaryFormat.clock write c))(chess.White)
"binary Clock" should {
val clock = Clock(2, 2)
val bits22 = List("00000010", "00000010")
"write" in {
write(clock) must_== {
bits22 ::: List.fill(11)(_0_)
}
write(clock.giveTime(chess.White, 0.03f)) must_== {
bits22 ::: List("10000000", "00000000", "00000011") ::: List.fill(8)(_0_)
}
write(clock.giveTime(chess.White, -0.03f)) must_== {
bits22 ::: List("00000000", "00000000", "00000011") ::: List.fill(8)(_0_)
}
}
"read" in {
read(bits22 ::: List.fill(11)(_0_)) must_== {
clock
}
read(bits22 ::: List("10000000", "00000000", "00000011") ::: List.fill(8)(_0_)) must_== {
clock.giveTime(chess.White, 0.03f)
}
read(bits22 ::: List("00000000", "00000000", "00000011") ::: List.fill(8)(_0_)) must_== {
clock.giveTime(chess.White, -0.03f)
}
}
"isomorphism" in {
isomorphism(clock) must_== clock
val c2 = clock.giveTime(chess.White, 15)
isomorphism(c2) must_== c2
val c3 = clock.giveTime(chess.Black, 5)
isomorphism(c3) must_== c3
val c4 = clock.run
isomorphism(c4).timerOption.get must beCloseTo(c4.timerOption.get, 1)
}
}
}