more work on correspondence chess

pull/138/head
Thibault Duplessis 2014-11-30 11:22:23 +01:00
parent 7fe4e8e84b
commit 928f73ee52
31 changed files with 543 additions and 378 deletions

View File

@ -10,7 +10,7 @@ trait SetupHelper { self: I18nHelper =>
def translatedTimeModeChoices(implicit ctx: Context) = List(
(TimeMode.Clock.id.toString, trans.clock.str(), none),
(TimeMode.Correspondance.id.toString, trans.correspondance.str(), none),
(TimeMode.Correspondence.id.toString, trans.correspondence.str(), none),
(TimeMode.Unlimited.id.toString, trans.unlimited.str(), none)
).map { x =>
x.copy(_2 = s"${trans.timeControl.str()}: ${x._2}")

View File

@ -17,7 +17,11 @@
<span class="setup">
@bookmark.toggle(game)
@game.clock.map(_.show).getOrElse {
@game.daysPerTurn.map { days =>
<span data-hint="@trans.correspondence()" class="hint--top">@trans.xDays(days)</span>
}.getOrElse {
<span data-hint="@trans.unlimited()" class="hint--top"></span>
}
} •
@if(game.variant.exotic) {
@variantLink(game.variant, (if (game.variant == chess.Variant.KingOfTheHill) game.variant.shortName else game.variant.name).toUpperCase, cssClass = "hint--top")

View File

@ -14,7 +14,7 @@
@trans.incrementInSeconds(): <span>@form("increment").value</span>
@setup.input(form("increment"))
</div>
<div class="correspondance">
<div class="correspondence">
<div class="days_choice slider">
@trans.daysPerTurn(): <span>@form("days").value</span>
@setup.input(form("days"))

View File

@ -31,7 +31,7 @@
@showPerf(u.perfs.bullet, PerfType.Bullet)
@showPerf(u.perfs.blitz, PerfType.Blitz)
@showPerf(u.perfs.classical, PerfType.Classical)
@showPerf(u.perfs.correspondance, PerfType.Correspondance)
@showPerf(u.perfs.correspondence, PerfType.Correspondence)
<br />
@if(u.perfs.chess960.nonEmpty) {
@showPerf(u.perfs.chess960, PerfType.Chess960)

View File

@ -81,8 +81,9 @@ minutesPerSide=Minutes per side
variant=Variant
timeControl=Time control
clock=Clock
correspondance=Correspondance
correspondence=Correspondence
daysPerTurn=Days per turn
xDays=%s days
time=Time
username=User name
password=Password

View File

@ -0,0 +1,10 @@
package lila.game
// times are expressed in seconds
case class CorrespondenceClock(
increment: Int,
whiteTime: Float,
blackTime: Float) {
def emerg = 60 * 10
}

View File

@ -157,6 +157,15 @@ object Event {
clock remainingTime Color.Black)
}
case class CorrespondenceClock(white: Float, black: Float) extends Event {
def typ = "cclock"
def data = Json.obj("white" -> white, "black" -> black)
}
object CorrespondenceClock {
def apply(clock: lila.game.CorrespondenceClock): CorrespondenceClock =
CorrespondenceClock(clock.whiteTime, clock.blackTime)
}
case class CheckCount(white: Int, black: Int) extends Event {
def typ = "checkCount"
def data = Json.obj(

View File

@ -20,7 +20,7 @@ case class Game(
startedAtTurn: Int,
clock: Option[Clock],
castleLastMoveTime: CastleLastMoveTime,
correspondanceDayPerTurn: Option[Int],
daysPerTurn: Option[Int],
positionHashes: PositionHash = Array(),
checkCount: CheckCount = CheckCount(0, 0),
binaryMoveTimes: ByteArray = ByteArray.empty, // tenths of seconds
@ -87,6 +87,10 @@ case class Game(
private def lastMoveTime: Option[Long] = castleLastMoveTime.lastMoveTime map {
_.toLong + (createdAt.getMillis / 100)
}
private def lastMoveTimeDate: Option[DateTime] = castleLastMoveTime.lastMoveTime map { lmt =>
createdAt plusMillis (lmt * 100)
}
def lastMoveTimeInSeconds: Option[Int] = lastMoveTime.map(x => (x / 10).toInt)
// in tenths of seconds
@ -161,7 +165,11 @@ case class Game(
status = situation.status | status,
clock = game.clock)
val finalEvents = events ::: updated.clock.??(c => List(Event.Clock(c))) ::: {
val clockEvent = updated.clock map Event.Clock.apply orElse {
updated.correspondenceClock map Event.CorrespondenceClock.apply
}
val finalEvents = events ::: clockEvent.toList ::: {
(updated.playable && (
abortable != updated.abortable || (Color.all exists { color =>
playerCanOfferDraw(color) != updated.playerCanOfferDraw(color)
@ -201,6 +209,18 @@ case class Game(
}
)
def correspondenceClock: Option[CorrespondenceClock] = daysPerTurn ifTrue playable map { days =>
val increment = days * 24 * 60 * 60
val secondsLeft = lastMoveTimeDate.fold(increment) { lmd =>
val flagAt = lmd plusDays days
(flagAt.getSeconds - nowSeconds).toInt max 0
}
CorrespondenceClock(
increment = increment,
whiteTime = turnColor.fold(secondsLeft, increment),
blackTime = turnColor.fold(increment, secondsLeft))
}
def speed = chess.Speed(clock)
def perfType = PerfType(PerfPicker.key(this))
@ -307,7 +327,7 @@ case class Game(
if (!c.isRunning && !c.isInit) || (c outoftime player.color)
} yield player
def isCorrespondance = correspondanceDayPerTurn.isDefined
def isCorrespondence = daysPerTurn.isDefined
def hasClock = clock.isDefined
@ -400,7 +420,7 @@ object Game {
source: Source,
pgnImport: Option[PgnImport],
castles: Castles = Castles.init,
correspondanceDayPerTurn: Option[Int] = None): Game = Game(
daysPerTurn: Option[Int] = None): Game = Game(
id = IdGenerator.game,
whitePlayer = whitePlayer,
blackPlayer = blackPlayer,
@ -412,7 +432,7 @@ object Game {
startedAtTurn = game.startedAtTurn,
clock = game.clock,
castleLastMoveTime = CastleLastMoveTime.init.copy(castles = castles),
correspondanceDayPerTurn = correspondanceDayPerTurn,
daysPerTurn = daysPerTurn,
mode = mode,
variant = variant,
metadata = Metadata(
@ -447,7 +467,7 @@ object Game {
val positionHashes = "ph"
val checkCount = "cc"
val castleLastMoveTime = "cl"
val correspondanceDayPerTurn = "cd"
val daysPerTurn = "cd"
val moveTimes = "mt"
val rated = "ra"
val analysed = "an"
@ -502,7 +522,7 @@ object Game {
CheckCount(~counts.headOption, ~counts.lastOption)
},
castleLastMoveTime = r.get[CastleLastMoveTime](castleLastMoveTime)(castleLastMoveTimeBSONHandler),
correspondanceDayPerTurn = r intO correspondanceDayPerTurn,
daysPerTurn = r intO daysPerTurn,
binaryMoveTimes = (r bytesO moveTimes) | ByteArray.empty,
mode = Mode(r boolD rated),
variant = Variant(r intD variant) | Variant.Standard,
@ -534,7 +554,7 @@ object Game {
positionHashes -> w.bytesO(o.positionHashes),
checkCount -> o.checkCount.nonEmpty.option(o.checkCount),
castleLastMoveTime -> castleLastMoveTimeBSONHandler.write(o.castleLastMoveTime),
correspondanceDayPerTurn -> o.correspondanceDayPerTurn,
daysPerTurn -> o.daysPerTurn,
moveTimes -> (BinaryFormat.moveTime write o.moveTimes),
rated -> w.boolO(o.mode.rated),
variant -> o.variant.exotic.option(o.variant.id).map(w.int),

File diff suppressed because one or more lines are too long

View File

@ -28,11 +28,11 @@ object PerfType {
title = Speed.Classical.title,
iconChar = '+')
case object Correspondance extends PerfType(
key = "correspondance",
name = "Correspondance",
title = "Correspondance",
iconChar = 'e')
case object Correspondence extends PerfType(
key = "correspondence",
name = "Correspondence",
title = "Correspondence",
iconChar = ';')
case object Standard extends PerfType(
key = "standard",

View File

@ -6,7 +6,7 @@ import scala.math
import play.api.libs.json._
import lila.common.PimpedJson._
import lila.game.{ Pov, Game, PerfPicker, Source, GameRepo }
import lila.game.{ Pov, Game, PerfPicker, Source, GameRepo, CorrespondenceClock }
import lila.pref.Pref
import lila.user.{ User, UserRepo }
@ -62,9 +62,10 @@ final class JsonView(
"rematch" -> game.next,
"source" -> game.source.map(sourceJson),
"status" -> Json.obj(
"id" -> pov.game.status.id,
"name" -> pov.game.status.name)),
"id" -> game.status.id,
"name" -> game.status.name)),
"clock" -> game.clock.map(clockJson),
"correspondence" -> game.correspondenceClock.map(correspondenceJson),
"player" -> Json.obj(
"id" -> playerId,
"color" -> player.color.name,
@ -165,9 +166,10 @@ final class JsonView(
)
},
"status" -> Json.obj(
"id" -> pov.game.status.id,
"name" -> pov.game.status.name)),
"id" -> game.status.id,
"name" -> game.status.name)),
"clock" -> game.clock.map(clockJson),
"correspondence" -> game.correspondenceClock.map(correspondenceJson),
"player" -> Json.obj(
"color" -> color.name,
"version" -> socket.version,
@ -254,6 +256,12 @@ final class JsonView(
"emerg" -> clock.emergTime,
"moretime" -> moretimeSeconds)
private def correspondenceJson(c: CorrespondenceClock) = Json.obj(
"increment" -> c.increment,
"white" -> c.whiteTime,
"black" -> c.blackTime,
"emerg" -> c.emerg)
private def sourceJson(source: Source) = source.name
private def possibleMoves(pov: Pov) = (pov.game playableBy pov.player) option {

View File

@ -64,7 +64,7 @@ private[round] final class Rematcher(
} inject List(Event.ReloadOwner)
private def returnGame(pov: Pov): Fu[Game] = for {
initialFen <- GameRepo initialFen pov.game.id
initialFen <- GameRepo initialFen pov.game.id
situation = initialFen flatMap Forsyth.<<<
pieces = pov.game.variant.standard.fold(
pov.game.variant.pieces,
@ -86,6 +86,7 @@ private[round] final class Rematcher(
mode = pov.game.mode,
variant = pov.game.variant,
source = pov.game.source | Source.Lobby,
daysPerTurn = pov.game.daysPerTurn,
castles = situation.fold(Castles.init)(_.situation.board.history.castles),
pgnImport = None)

View File

@ -30,7 +30,7 @@ case class AiConfig(
mode = Mode.Casual,
variant = variant,
source = (variant == Variant.FromPosition).fold(Source.Position, Source.Ai),
correspondanceDayPerTurn = makeDaysPerTurn,
daysPerTurn = makeDaysPerTurn,
pgnImport = None)
} start

View File

@ -18,7 +18,7 @@ private[setup] trait Config {
// Clock increment in seconds
val increment: Int
// Correspondance days per turn
// Correspondence days per turn
val days: Int
// Game variant code
@ -41,7 +41,7 @@ private[setup] trait Config {
Clock(time * 60, clockHasTime.fold(increment, 1))
}
def makeDaysPerTurn: Option[Int] = (timeMode == TimeMode.Correspondance) option days
def makeDaysPerTurn: Option[Int] = (timeMode == TimeMode.Correspondence) option days
}
trait GameGenerator { self: Config =>

View File

@ -27,7 +27,7 @@ case class FriendConfig(
mode = (variant == Variant.FromPosition).fold(Mode.Casual, mode),
variant = variant,
source = (variant == Variant.FromPosition).fold(Source.Position, Source.Friend),
correspondanceDayPerTurn = makeDaysPerTurn,
daysPerTurn = makeDaysPerTurn,
pgnImport = None)
}

View File

@ -6,9 +6,9 @@ object TimeMode {
case object Unlimited extends TimeMode(0)
case object Clock extends TimeMode(1)
case object Correspondance extends TimeMode(2)
case object Correspondence extends TimeMode(2)
val all = List(Unlimited, Clock, Correspondance)
val all = List(Unlimited, Clock, Correspondence)
val ids = all map (_.id)

View File

@ -14,7 +14,7 @@ case class Perfs(
bullet: Perf,
blitz: Perf,
classical: Perf,
correspondance: Perf,
correspondence: Perf,
puzzle: Perf) {
def perfs = List(
@ -25,7 +25,7 @@ case class Perfs(
"bullet" -> bullet,
"blitz" -> blitz,
"classical" -> classical,
"correspondance" -> correspondance,
"correspondence" -> correspondence,
"puzzle" -> puzzle)
def bestPerf: Option[(PerfType, Perf)] = {
@ -57,7 +57,7 @@ case class Perfs(
"bullet" -> bullet,
"blitz" -> blitz,
"classical" -> classical,
"correspondance" -> correspondance,
"correspondence" -> correspondence,
"puzzle" -> puzzle)
def ratingMap: Map[String, Int] = perfsMap mapValues (_.intRating)
@ -71,7 +71,7 @@ case class Perfs(
case PerfType.Bullet => bullet
case PerfType.Blitz => blitz
case PerfType.Classical => classical
case PerfType.Correspondance => correspondance
case PerfType.Correspondence => correspondence
case PerfType.Chess960 => chess960
case PerfType.KingOfTheHill => kingOfTheHill
case PerfType.ThreeCheck => threeCheck
@ -86,7 +86,7 @@ case class Perfs(
def updateStandard = copy(
standard = {
val subs = List(bullet, blitz, classical, correspondance)
val subs = List(bullet, blitz, classical, correspondence)
subs.maxBy(_.latest.fold(0l)(_.getMillis)).latest.fold(standard) { date =>
val nb = subs.map(_.nb).sum
val glicko = Glicko(
@ -139,7 +139,7 @@ case object Perfs {
bullet = perf("bullet"),
blitz = perf("blitz"),
classical = perf("classical"),
correspondance = perf("correspondance"),
correspondence = perf("correspondence"),
puzzle = perf("puzzle"))
}
@ -153,7 +153,7 @@ case object Perfs {
"bullet" -> notNew(o.bullet),
"blitz" -> notNew(o.blitz),
"classical" -> notNew(o.classical),
"correspondance" -> notNew(o.correspondance),
"correspondence" -> notNew(o.correspondence),
"puzzle" -> notNew(o.puzzle))
}

Binary file not shown.

View File

@ -89,4 +89,5 @@
<glyph unicode="&#47;" d="M389 330c34 0 63-12 87-35 24-23 36-52 36-85 0-34-12-62-36-85-24-23-53-35-87-35 0 0-97 0-97 0 0 0 0 97 0 97 0 0 54 0 54 0 0 0-90 118-90 118 0 0-89-118-89-118 0 0 53 0 53 0 0 0 0-97 0-97 0 0-127 0-127 0-25 0-47 9-65 27-19 17-28 39-28 63 0 25 9 47 27 65 18 17 40 26 66 26 5 0 8 0 10-1 0 4-1 11-1 20 0 37 14 68 40 94 27 26 59 39 97 39 30 0 58-9 82-27 23-17 39-40 48-68 9 1 16 2 20 2"/>
<glyph unicode="&#42;" d="M107 6c-2-7-7-8-14-4-6 3-8 9-8 17 2 35 10 73 26 116-34 53-43 107-27 162 4-11 9-24 17-40 7-16 15-29 22-41 8-12 13-17 17-15 2 1 2 15 0 42-3 27-5 55-6 85-1 30 3 57 13 81 7 15 21 31 41 48 19 17 37 29 53 36-8-16-14-32-17-49-3-16-4-29-2-40 2-10 5-15 11-16 4 0 18 21 43 62 24 40 42 61 54 62 16 1 35-4 58-15 24-11 38-22 42-33 4-8 4-22 0-41-4-18-11-33-20-42-15-15-40-26-75-32-35-6-54-10-58-12-6-4-4-9 6-18 18-16 48-19 90-10-19-27-42-47-70-58-27-12-49-18-67-20-18-1-27-3-28-5-1-8 7-17 25-27 18-11 36-13 52-8-10-19-21-33-32-43-12-9-21-15-28-17-7-3-20-5-39-6-19-1-33-3-43-4 0 0-36-115-36-115"/>
<glyph unicode="&#58;" d="M239 256c0 19-7 35-20 48-13 14-29 20-48 20-19 0-35-6-49-20-13-13-20-29-20-48 0-19 7-35 20-48 14-14 30-20 49-20 19 0 35 6 48 20 13 13 20 29 20 48z m205-137c0 10-4 18-10 24-7 7-15 11-24 11-10 0-18-4-24-11-7-6-11-14-11-24 0-9 4-17 10-24 7-6 15-10 25-10 9 0 17 4 24 10 6 7 10 15 10 24z m0 274c0 9-4 17-10 24-7 6-15 10-24 10-10 0-18-4-24-10-7-7-11-15-11-24 0-10 4-18 10-25 7-6 15-10 25-10 9 0 17 4 24 10 6 7 10 15 10 25z m-103-113l0-49c0-2 0-4-2-5-1-2-2-3-4-3l-41-6c-2-7-5-13-9-21 6-8 14-18 24-30 2-2 2-4 2-6 0-2 0-4-2-5-4-5-11-13-22-24-10-10-17-16-21-16-2 0-3 1-5 2l-31 24c-6-3-13-6-20-8-2-19-4-33-7-41-1-5-3-7-8-7l-49 0c-2 0-4 1-5 2-2 2-3 3-3 5l-6 41c-6 2-13 4-20 8l-32-24c-1-1-3-2-5-2-2 0-4 1-6 3-25 23-38 37-38 42 0 2 1 4 2 5 2 3 5 8 11 14 5 7 9 13 12 17-4 8-7 15-9 22l-41 6c-1 0-3 1-4 3-1 1-2 3-2 5l0 49c0 2 1 4 2 5 1 2 3 3 4 3l41 6c2 7 5 13 9 21-6 8-14 18-24 30-1 2-2 4-2 6 0 2 1 4 2 5 4 5 11 13 22 24 11 10 18 16 21 16 2 0 4-1 6-2l30-24c6 3 13 6 21 8 2 19 4 33 6 41 1 5 4 7 8 7l49 0c2 0 4-1 6-2 1-2 2-3 2-5l7-41c6-2 12-4 20-8l31 24c1 1 3 2 5 2 2 0 4-1 6-3 26-23 38-37 38-42 0-2 0-4-1-5-3-3-6-8-12-15-5-6-9-12-12-16 4-8 7-16 9-22l41-6c2 0 3-1 4-3 2-1 2-3 2-5z m171-142l0-37c0-3-13-6-40-8-2-5-5-10-8-14 9-20 14-33 14-37 0-1 0-1-1-2-22-13-33-19-33-19-2 0-6 4-13 13-6 8-11 14-13 18-4-1-7-1-8-1-2 0-5 0-8 1-3-4-8-10-14-18-7-9-11-13-13-13 0 0-11 6-33 19 0 1-1 1-1 2 0 4 5 17 14 37-3 4-6 9-8 14-27 2-40 5-40 8l0 37c0 3 13 6 40 8 2 6 5 10 8 14-9 20-14 33-14 37 0 1 1 1 1 2 1 0 4 2 10 5 5 3 10 6 15 9 5 3 8 5 8 5 2 0 6-5 13-13 6-8 11-14 14-18 3 1 6 1 8 1 1 0 4 0 8-1 9 13 17 23 24 30l2 1c0 0 11-7 33-19 1-1 1-1 1-2 0-4-5-17-14-37 3-4 6-8 8-14 27-2 40-5 40-8z m0 273l0-37c0-3-13-6-40-8-2-5-5-10-8-14 9-20 14-33 14-37 0-1 0-1-1-2-22-13-33-19-33-19-2 0-6 4-13 13-6 8-11 14-13 18-4-1-7-1-8-1-2 0-5 0-8 1-3-4-8-10-14-18-7-9-11-13-13-13 0 0-11 6-33 19 0 1-1 1-1 2 0 4 5 17 14 37-3 4-6 9-8 14-27 2-40 5-40 8l0 37c0 3 13 6 40 8 2 6 5 10 8 14-9 20-14 33-14 37 0 1 1 1 1 2 1 0 4 2 10 5 5 4 10 7 15 9 5 3 8 5 8 5 2 0 6-4 13-13 6-8 11-14 14-18 3 1 6 1 8 1 1 0 4 0 8-1 9 13 17 23 24 30l2 1c0 0 11-7 33-19 1-1 1-1 1-2 0-4-5-17-14-37 3-4 6-8 8-14 27-2 40-5 40-8z"/>
<glyph unicode="&#59;" d="M230 207l-17-164 102 125 97-44 100 345z m282 262l-512-210 121-24 92-192-66 192z"/>
</font></defs></svg>

Before

Width:  |  Height:  |  Size: 41 KiB

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

View File

@ -43,337 +43,6 @@ h2{font-size:18px;padding:0 0 21px 5px;margin:45px 0 0 0;text-transform:uppercas
<div class="container">
<h1>lichess</h1>
<p class="small">This font was created with<a href="http://fontastic.me/">Fontastic</a></p>
<h2>Character mapping</h2>
<ul class="glyphs character-mapping">
<li>
<div data-icon="a" class="icon"></div>
<input type="text" readonly="readonly" value="a">
</li>
<li>
<div data-icon="b" class="icon"></div>
<input type="text" readonly="readonly" value="b">
</li>
<li>
<div data-icon="c" class="icon"></div>
<input type="text" readonly="readonly" value="c">
</li>
<li>
<div data-icon="d" class="icon"></div>
<input type="text" readonly="readonly" value="d">
</li>
<li>
<div data-icon="e" class="icon"></div>
<input type="text" readonly="readonly" value="e">
</li>
<li>
<div data-icon="f" class="icon"></div>
<input type="text" readonly="readonly" value="f">
</li>
<li>
<div data-icon="g" class="icon"></div>
<input type="text" readonly="readonly" value="g">
</li>
<li>
<div data-icon="h" class="icon"></div>
<input type="text" readonly="readonly" value="h">
</li>
<li>
<div data-icon="j" class="icon"></div>
<input type="text" readonly="readonly" value="j">
</li>
<li>
<div data-icon="k" class="icon"></div>
<input type="text" readonly="readonly" value="k">
</li>
<li>
<div data-icon="l" class="icon"></div>
<input type="text" readonly="readonly" value="l">
</li>
<li>
<div data-icon="m" class="icon"></div>
<input type="text" readonly="readonly" value="m">
</li>
<li>
<div data-icon="p" class="icon"></div>
<input type="text" readonly="readonly" value="p">
</li>
<li>
<div data-icon="r" class="icon"></div>
<input type="text" readonly="readonly" value="r">
</li>
<li>
<div data-icon="s" class="icon"></div>
<input type="text" readonly="readonly" value="s">
</li>
<li>
<div data-icon="t" class="icon"></div>
<input type="text" readonly="readonly" value="t">
</li>
<li>
<div data-icon="u" class="icon"></div>
<input type="text" readonly="readonly" value="u">
</li>
<li>
<div data-icon="v" class="icon"></div>
<input type="text" readonly="readonly" value="v">
</li>
<li>
<div data-icon="w" class="icon"></div>
<input type="text" readonly="readonly" value="w">
</li>
<li>
<div data-icon="x" class="icon"></div>
<input type="text" readonly="readonly" value="x">
</li>
<li>
<div data-icon="z" class="icon"></div>
<input type="text" readonly="readonly" value="z">
</li>
<li>
<div data-icon="A" class="icon"></div>
<input type="text" readonly="readonly" value="A">
</li>
<li>
<div data-icon="C" class="icon"></div>
<input type="text" readonly="readonly" value="C">
</li>
<li>
<div data-icon="D" class="icon"></div>
<input type="text" readonly="readonly" value="D">
</li>
<li>
<div data-icon="E" class="icon"></div>
<input type="text" readonly="readonly" value="E">
</li>
<li>
<div data-icon="F" class="icon"></div>
<input type="text" readonly="readonly" value="F">
</li>
<li>
<div data-icon="G" class="icon"></div>
<input type="text" readonly="readonly" value="G">
</li>
<li>
<div data-icon="H" class="icon"></div>
<input type="text" readonly="readonly" value="H">
</li>
<li>
<div data-icon="I" class="icon"></div>
<input type="text" readonly="readonly" value="I">
</li>
<li>
<div data-icon="J" class="icon"></div>
<input type="text" readonly="readonly" value="J">
</li>
<li>
<div data-icon="K" class="icon"></div>
<input type="text" readonly="readonly" value="K">
</li>
<li>
<div data-icon="B" class="icon"></div>
<input type="text" readonly="readonly" value="B">
</li>
<li>
<div data-icon="M" class="icon"></div>
<input type="text" readonly="readonly" value="M">
</li>
<li>
<div data-icon="N" class="icon"></div>
<input type="text" readonly="readonly" value="N">
</li>
<li>
<div data-icon="L" class="icon"></div>
<input type="text" readonly="readonly" value="L">
</li>
<li>
<div data-icon="O" class="icon"></div>
<input type="text" readonly="readonly" value="O">
</li>
<li>
<div data-icon="O" class="icon"></div>
<input type="text" readonly="readonly" value="O">
</li>
<li>
<div data-icon="O" class="icon"></div>
<input type="text" readonly="readonly" value="O">
</li>
<li>
<div data-icon="Q" class="icon"></div>
<input type="text" readonly="readonly" value="Q">
</li>
<li>
<div data-icon="Q" class="icon"></div>
<input type="text" readonly="readonly" value="Q">
</li>
<li>
<div data-icon="Q" class="icon"></div>
<input type="text" readonly="readonly" value="Q">
</li>
<li>
<div data-icon="R" class="icon"></div>
<input type="text" readonly="readonly" value="R">
</li>
<li>
<div data-icon="S" class="icon"></div>
<input type="text" readonly="readonly" value="S">
</li>
<li>
<div data-icon="T" class="icon"></div>
<input type="text" readonly="readonly" value="T">
</li>
<li>
<div data-icon="U" class="icon"></div>
<input type="text" readonly="readonly" value="U">
</li>
<li>
<div data-icon="V" class="icon"></div>
<input type="text" readonly="readonly" value="V">
</li>
<li>
<div data-icon="W" class="icon"></div>
<input type="text" readonly="readonly" value="W">
</li>
<li>
<div data-icon="X" class="icon"></div>
<input type="text" readonly="readonly" value="X">
</li>
<li>
<div data-icon="Y" class="icon"></div>
<input type="text" readonly="readonly" value="Y">
</li>
<li>
<div data-icon="Z" class="icon"></div>
<input type="text" readonly="readonly" value="Z">
</li>
<li>
<div data-icon="!" class="icon"></div>
<input type="text" readonly="readonly" value="!">
</li>
<li>
<div data-icon="P" class="icon"></div>
<input type="text" readonly="readonly" value="P">
</li>
<li>
<div data-icon="i" class="icon"></div>
<input type="text" readonly="readonly" value="i">
</li>
<li>
<div data-icon="2" class="icon"></div>
<input type="text" readonly="readonly" value="2">
</li>
<li>
<div data-icon="3" class="icon"></div>
<input type="text" readonly="readonly" value="3">
</li>
<li>
<div data-icon="0" class="icon"></div>
<input type="text" readonly="readonly" value="0">
</li>
<li>
<div data-icon="1" class="icon"></div>
<input type="text" readonly="readonly" value="1">
</li>
<li>
<div data-icon="4" class="icon"></div>
<input type="text" readonly="readonly" value="4">
</li>
<li>
<div data-icon="5" class="icon"></div>
<input type="text" readonly="readonly" value="5">
</li>
<li>
<div data-icon="6" class="icon"></div>
<input type="text" readonly="readonly" value="6">
</li>
<li>
<div data-icon="9" class="icon"></div>
<input type="text" readonly="readonly" value="9">
</li>
<li>
<div data-icon="&#34;" class="icon"></div>
<input type="text" readonly="readonly" value="&quot;">
</li>
<li>
<div data-icon="7" class="icon"></div>
<input type="text" readonly="readonly" value="7">
</li>
<li>
<div data-icon="#" class="icon"></div>
<input type="text" readonly="readonly" value="#">
</li>
<li>
<div data-icon="$" class="icon"></div>
<input type="text" readonly="readonly" value="$">
</li>
<li>
<div data-icon="%" class="icon"></div>
<input type="text" readonly="readonly" value="%">
</li>
<li>
<div data-icon="&" class="icon"></div>
<input type="text" readonly="readonly" value="&amp;">
</li>
<li>
<div data-icon="o" class="icon"></div>
<input type="text" readonly="readonly" value="o">
</li>
<li>
<div data-icon="q" class="icon"></div>
<input type="text" readonly="readonly" value="q">
</li>
<li>
<div data-icon="y" class="icon"></div>
<input type="text" readonly="readonly" value="y">
</li>
<li>
<div data-icon="n" class="icon"></div>
<input type="text" readonly="readonly" value="n">
</li>
<li>
<div data-icon="8" class="icon"></div>
<input type="text" readonly="readonly" value="8">
</li>
<li>
<div data-icon="'" class="icon"></div>
<input type="text" readonly="readonly" value="&#39;">
</li>
<li>
<div data-icon="(" class="icon"></div>
<input type="text" readonly="readonly" value="(">
</li>
<li>
<div data-icon=")" class="icon"></div>
<input type="text" readonly="readonly" value=")">
</li>
<li>
<div data-icon="+" class="icon"></div>
<input type="text" readonly="readonly" value="+">
</li>
<li>
<div data-icon="," class="icon"></div>
<input type="text" readonly="readonly" value=",">
</li>
<li>
<div data-icon="-" class="icon"></div>
<input type="text" readonly="readonly" value="-">
</li>
<li>
<div data-icon="." class="icon"></div>
<input type="text" readonly="readonly" value=".">
</li>
<li>
<div data-icon="/" class="icon"></div>
<input type="text" readonly="readonly" value="/">
</li>
<li>
<div data-icon="*" class="icon"></div>
<input type="text" readonly="readonly" value="*">
</li>
<li>
<div data-icon=":" class="icon"></div>
<input type="text" readonly="readonly" value=":">
</li>
</ul>
<h2>CSS mapping</h2>
<ul class="glyphs css-mapping">
<li>
@ -704,6 +373,345 @@ h2{font-size:18px;padding:0 0 21px 5px;margin:45px 0 0 0;text-transform:uppercas
<div class="icon icon-gears-setting"></div>
<input type="text" readonly="readonly" value="gears-setting">
</li>
<li>
<div class="icon icon-email-plane"></div>
<input type="text" readonly="readonly" value="email-plane">
</li>
</ul>
<h2>Character mapping</h2>
<ul class="glyphs character-mapping">
<li>
<div data-icon="a" class="icon"></div>
<input type="text" readonly="readonly" value="a">
</li>
<li>
<div data-icon="b" class="icon"></div>
<input type="text" readonly="readonly" value="b">
</li>
<li>
<div data-icon="c" class="icon"></div>
<input type="text" readonly="readonly" value="c">
</li>
<li>
<div data-icon="d" class="icon"></div>
<input type="text" readonly="readonly" value="d">
</li>
<li>
<div data-icon="e" class="icon"></div>
<input type="text" readonly="readonly" value="e">
</li>
<li>
<div data-icon="f" class="icon"></div>
<input type="text" readonly="readonly" value="f">
</li>
<li>
<div data-icon="g" class="icon"></div>
<input type="text" readonly="readonly" value="g">
</li>
<li>
<div data-icon="h" class="icon"></div>
<input type="text" readonly="readonly" value="h">
</li>
<li>
<div data-icon="j" class="icon"></div>
<input type="text" readonly="readonly" value="j">
</li>
<li>
<div data-icon="k" class="icon"></div>
<input type="text" readonly="readonly" value="k">
</li>
<li>
<div data-icon="l" class="icon"></div>
<input type="text" readonly="readonly" value="l">
</li>
<li>
<div data-icon="m" class="icon"></div>
<input type="text" readonly="readonly" value="m">
</li>
<li>
<div data-icon="p" class="icon"></div>
<input type="text" readonly="readonly" value="p">
</li>
<li>
<div data-icon="r" class="icon"></div>
<input type="text" readonly="readonly" value="r">
</li>
<li>
<div data-icon="s" class="icon"></div>
<input type="text" readonly="readonly" value="s">
</li>
<li>
<div data-icon="t" class="icon"></div>
<input type="text" readonly="readonly" value="t">
</li>
<li>
<div data-icon="u" class="icon"></div>
<input type="text" readonly="readonly" value="u">
</li>
<li>
<div data-icon="v" class="icon"></div>
<input type="text" readonly="readonly" value="v">
</li>
<li>
<div data-icon="w" class="icon"></div>
<input type="text" readonly="readonly" value="w">
</li>
<li>
<div data-icon="x" class="icon"></div>
<input type="text" readonly="readonly" value="x">
</li>
<li>
<div data-icon="z" class="icon"></div>
<input type="text" readonly="readonly" value="z">
</li>
<li>
<div data-icon="A" class="icon"></div>
<input type="text" readonly="readonly" value="A">
</li>
<li>
<div data-icon="C" class="icon"></div>
<input type="text" readonly="readonly" value="C">
</li>
<li>
<div data-icon="D" class="icon"></div>
<input type="text" readonly="readonly" value="D">
</li>
<li>
<div data-icon="E" class="icon"></div>
<input type="text" readonly="readonly" value="E">
</li>
<li>
<div data-icon="F" class="icon"></div>
<input type="text" readonly="readonly" value="F">
</li>
<li>
<div data-icon="G" class="icon"></div>
<input type="text" readonly="readonly" value="G">
</li>
<li>
<div data-icon="H" class="icon"></div>
<input type="text" readonly="readonly" value="H">
</li>
<li>
<div data-icon="I" class="icon"></div>
<input type="text" readonly="readonly" value="I">
</li>
<li>
<div data-icon="J" class="icon"></div>
<input type="text" readonly="readonly" value="J">
</li>
<li>
<div data-icon="K" class="icon"></div>
<input type="text" readonly="readonly" value="K">
</li>
<li>
<div data-icon="B" class="icon"></div>
<input type="text" readonly="readonly" value="B">
</li>
<li>
<div data-icon="M" class="icon"></div>
<input type="text" readonly="readonly" value="M">
</li>
<li>
<div data-icon="N" class="icon"></div>
<input type="text" readonly="readonly" value="N">
</li>
<li>
<div data-icon="L" class="icon"></div>
<input type="text" readonly="readonly" value="L">
</li>
<li>
<div data-icon="O" class="icon"></div>
<input type="text" readonly="readonly" value="O">
</li>
<li>
<div data-icon="O" class="icon"></div>
<input type="text" readonly="readonly" value="O">
</li>
<li>
<div data-icon="O" class="icon"></div>
<input type="text" readonly="readonly" value="O">
</li>
<li>
<div data-icon="Q" class="icon"></div>
<input type="text" readonly="readonly" value="Q">
</li>
<li>
<div data-icon="Q" class="icon"></div>
<input type="text" readonly="readonly" value="Q">
</li>
<li>
<div data-icon="Q" class="icon"></div>
<input type="text" readonly="readonly" value="Q">
</li>
<li>
<div data-icon="R" class="icon"></div>
<input type="text" readonly="readonly" value="R">
</li>
<li>
<div data-icon="S" class="icon"></div>
<input type="text" readonly="readonly" value="S">
</li>
<li>
<div data-icon="T" class="icon"></div>
<input type="text" readonly="readonly" value="T">
</li>
<li>
<div data-icon="U" class="icon"></div>
<input type="text" readonly="readonly" value="U">
</li>
<li>
<div data-icon="V" class="icon"></div>
<input type="text" readonly="readonly" value="V">
</li>
<li>
<div data-icon="W" class="icon"></div>
<input type="text" readonly="readonly" value="W">
</li>
<li>
<div data-icon="X" class="icon"></div>
<input type="text" readonly="readonly" value="X">
</li>
<li>
<div data-icon="Y" class="icon"></div>
<input type="text" readonly="readonly" value="Y">
</li>
<li>
<div data-icon="Z" class="icon"></div>
<input type="text" readonly="readonly" value="Z">
</li>
<li>
<div data-icon="!" class="icon"></div>
<input type="text" readonly="readonly" value="!">
</li>
<li>
<div data-icon="P" class="icon"></div>
<input type="text" readonly="readonly" value="P">
</li>
<li>
<div data-icon="i" class="icon"></div>
<input type="text" readonly="readonly" value="i">
</li>
<li>
<div data-icon="2" class="icon"></div>
<input type="text" readonly="readonly" value="2">
</li>
<li>
<div data-icon="3" class="icon"></div>
<input type="text" readonly="readonly" value="3">
</li>
<li>
<div data-icon="0" class="icon"></div>
<input type="text" readonly="readonly" value="0">
</li>
<li>
<div data-icon="1" class="icon"></div>
<input type="text" readonly="readonly" value="1">
</li>
<li>
<div data-icon="4" class="icon"></div>
<input type="text" readonly="readonly" value="4">
</li>
<li>
<div data-icon="5" class="icon"></div>
<input type="text" readonly="readonly" value="5">
</li>
<li>
<div data-icon="6" class="icon"></div>
<input type="text" readonly="readonly" value="6">
</li>
<li>
<div data-icon="9" class="icon"></div>
<input type="text" readonly="readonly" value="9">
</li>
<li>
<div data-icon="&#34;" class="icon"></div>
<input type="text" readonly="readonly" value="&quot;">
</li>
<li>
<div data-icon="7" class="icon"></div>
<input type="text" readonly="readonly" value="7">
</li>
<li>
<div data-icon="#" class="icon"></div>
<input type="text" readonly="readonly" value="#">
</li>
<li>
<div data-icon="$" class="icon"></div>
<input type="text" readonly="readonly" value="$">
</li>
<li>
<div data-icon="%" class="icon"></div>
<input type="text" readonly="readonly" value="%">
</li>
<li>
<div data-icon="&" class="icon"></div>
<input type="text" readonly="readonly" value="&amp;">
</li>
<li>
<div data-icon="o" class="icon"></div>
<input type="text" readonly="readonly" value="o">
</li>
<li>
<div data-icon="q" class="icon"></div>
<input type="text" readonly="readonly" value="q">
</li>
<li>
<div data-icon="y" class="icon"></div>
<input type="text" readonly="readonly" value="y">
</li>
<li>
<div data-icon="n" class="icon"></div>
<input type="text" readonly="readonly" value="n">
</li>
<li>
<div data-icon="8" class="icon"></div>
<input type="text" readonly="readonly" value="8">
</li>
<li>
<div data-icon="'" class="icon"></div>
<input type="text" readonly="readonly" value="&#39;">
</li>
<li>
<div data-icon="(" class="icon"></div>
<input type="text" readonly="readonly" value="(">
</li>
<li>
<div data-icon=")" class="icon"></div>
<input type="text" readonly="readonly" value=")">
</li>
<li>
<div data-icon="+" class="icon"></div>
<input type="text" readonly="readonly" value="+">
</li>
<li>
<div data-icon="," class="icon"></div>
<input type="text" readonly="readonly" value=",">
</li>
<li>
<div data-icon="-" class="icon"></div>
<input type="text" readonly="readonly" value="-">
</li>
<li>
<div data-icon="." class="icon"></div>
<input type="text" readonly="readonly" value=".">
</li>
<li>
<div data-icon="/" class="icon"></div>
<input type="text" readonly="readonly" value="/">
</li>
<li>
<div data-icon="*" class="icon"></div>
<input type="text" readonly="readonly" value="*">
</li>
<li>
<div data-icon=":" class="icon"></div>
<input type="text" readonly="readonly" value=":">
</li>
<li>
<div data-icon=";" class="icon"></div>
<input type="text" readonly="readonly" value=";">
</li>
</ul>
</div><script type="text/javascript">
(function() {

View File

@ -284,3 +284,6 @@
.icon-gears-setting:before {
content: ":";
}
.icon-email-plane:before {
content: ";";
}

View File

@ -70,8 +70,8 @@ time {
}
@font-face {
font-family: "lichess";
src: url("../font21/fonts/lichess.eot");
src: url("../font21/fonts/lichess.eot?#iefix") format("embedded-opentype"), url("../font21/fonts/lichess.woff") format("woff"), url("../font21/fonts/lichess.ttf") format("truetype"), url("../font21/fonts/lichess.svg#lichess") format("svg");
src: url("../font22/fonts/lichess.eot");
src: url("../font22/fonts/lichess.eot?#iefix") format("embedded-opentype"), url("../font22/fonts/lichess.woff") format("woff"), url("../font22/fonts/lichess.ttf") format("truetype"), url("../font22/fonts/lichess.svg#lichess") format("svg");
font-weight: normal;
font-style: normal;
}

View File

@ -527,6 +527,7 @@ div.game_config .variants {
}
div.game_config select {
font-weight: bold;
padding: 5px 8px;
}
div.game_config .fen_position {
padding: 8px 0;

View File

@ -0,0 +1,29 @@
module.exports = function(data, onFlag) {
var lastUpdate;
this.data = data;
this.data.barTime = this.data.increment;
function setLastUpdate() {
lastUpdate = {
white: data.white,
black: data.black,
at: new Date()
};
}
setLastUpdate();
this.update = function(white, black) {
this.data.white = white;
this.data.black = black;
setLastUpdate();
}.bind(this);
this.tick = function(color) {
m.startComputation();
this.data[color] = Math.max(0, lastUpdate[color] - (new Date() - lastUpdate.at) / 1000);
if (this.data[color] === 0) onFlag();
m.endComputation();
}.bind(this);
}

View File

@ -0,0 +1,44 @@
var classSet = require('chessground').util.classSet;
function prefixInteger(num, length) {
return (num / Math.pow(10, length)).toFixed(length).substr(2);
}
function bold(x) {
return '<b>' + x + '</b>';
}
function formatClockTime(ctrl, time) {
var date = new Date(time);
var minutes = prefixInteger(date.getUTCMinutes(), 2);
var seconds = prefixInteger(date.getSeconds(), 2);
var str = '';
if (time >= 86400 * 1000) {
var days = date.getUTCDate() - 1;
str += bold(days) + 'D ';
if (time % 86400 === 0) return str;
}
str += bold(prefixInteger(date.getUTCHours(), 2)) + ':' + bold(minutes);
if (time < 3600 * 1000) str += ':' + bold(seconds);
return str;
}
module.exports = function(ctrl, color, position, runningColor) {
var time = ctrl.data[color];
return m('div', {
class: 'correspondence clock clock_' + color + ' clock_' + position + ' ' + classSet({
'outoftime': !time,
'running': runningColor === color,
'emerg': time < ctrl.data.emerg
})
}, [
ctrl.data.showBar ? m('div.bar',
m('span', {
style: {
width: Math.max(0, Math.min(100, (time / ctrl.data.barTime) * 100)) + '%'
}
})
) : null,
m('div.time', m.trust(formatClockTime(ctrl, time * 1000)))
]);
}

View File

@ -16,6 +16,7 @@ var init = require('./init');
var blind = require('./blind');
var replayCtrl = require('./replay/ctrl');
var clockCtrl = require('./clock/ctrl');
var correspondenceClockCtrl = require('./correspondenceClock/ctrl');
module.exports = function(cfg, router, i18n, socketSend) {
@ -24,7 +25,11 @@ module.exports = function(cfg, router, i18n, socketSend) {
this.vm = {
flip: false,
reloading: false,
redirecting: false
redirecting: false,
correspondenceTimeLeft: {
white: '',
black: ''
}
};
this.socket = new socket(socketSend, this);
@ -80,8 +85,7 @@ module.exports = function(cfg, router, i18n, socketSend) {
this.clock = this.data.clock ? new clockCtrl(
this.data.clock,
this.data.player.spectator ? function() {} : throttle(partial(this.socket.send, 'outoftime'), 500),
(this.data.player.spectator || !this.data.pref.clockSound) ? null : this.data.player.color
this.data.player.spectator ? function() {} : throttle(partial(this.socket.send, 'outoftime'), 500), (this.data.player.spectator || !this.data.pref.clockSound) ? null : this.data.player.color
) : false;
this.isClockRunning = function() {
@ -93,7 +97,17 @@ module.exports = function(cfg, router, i18n, socketSend) {
if (this.isClockRunning()) this.clock.tick(this.data.game.player);
}.bind(this);
this.correspondenceClock = this.data.correspondence ? new correspondenceClockCtrl(
this.data.correspondence,
partial(this.socket.send, 'outoftime')
) : false;
this.correspondenceClockTick = function() {
if (game.playable(this.data)) this.correspondenceClock.tick(this.data.game.player);
}.bind(this);
if (this.clock) setInterval(this.clockTick, 100);
else if (this.data.correspondence) setInterval(this.correspondenceClockTick, 1000);
this.replay = new replayCtrl(this);

View File

@ -74,6 +74,9 @@ module.exports = function(send, ctrl) {
clock: function(o) {
if (ctrl.clock) ctrl.clock.update(o.white, o.black);
},
cclock: function(o) {
if (ctrl.correspondenceClock) ctrl.correspondenceClock.update(o.white, o.black);
},
crowd: function(o) {
['white', 'black'].forEach(function(c) {
game.setOnGame(ctrl.data, c, o[c]);

View File

@ -4,6 +4,7 @@ var game = require('game').game;
var status = require('game').status;
var opposite = chessground.util.opposite;
var renderClock = require('../clock/view');
var renderCorrespondenceClock = require('../correspondenceClock/view');
var renderReplay = require('../replay/view');
var renderStatus = require('./status');
var renderUser = require('game').view.user;
@ -122,9 +123,13 @@ module.exports = function(ctrl) {
return m('div.table_wrap', [
(ctrl.clock && !ctrl.data.blind) ? renderClock(
ctrl.clock,
opposite(ctrl.data.player.color),
ctrl.data.opponent.color,
"top", clockRunningColor
) : whosTurn(ctrl, ctrl.data.opponent.color),
) : (
ctrl.data.correspondence ? renderCorrespondenceClock(
ctrl.correspondenceClock, ctrl.data.opponent.color, "top", ctrl.data.game.player
) : whosTurn(ctrl, ctrl.data.opponent.color)
),
m('div', {
class: 'table' + (status.finished(ctrl.data) ? ' finished' : '')
}, [
@ -137,6 +142,9 @@ module.exports = function(ctrl) {
]), (ctrl.clock && !ctrl.data.blind) ? [
renderClock(ctrl.clock, ctrl.data.player.color, "bottom", clockRunningColor),
button.moretime(ctrl)
] : whosTurn(ctrl, ctrl.data.player.color)
])
] : (
ctrl.data.correspondence ? renderCorrespondenceClock(
ctrl.correspondenceClock, ctrl.data.player.color, "bottom", ctrl.data.game.player
) : whosTurn(ctrl, ctrl.data.player.color))
]);
}