chess960 and rated tournaments

This commit is contained in:
Thibault Duplessis 2013-01-05 17:00:47 +01:00
parent c8b2a450c1
commit a52ac0d8ec
12 changed files with 110 additions and 45 deletions

View file

@ -15,11 +15,11 @@ trait SetupHelper { self: I18nHelper ⇒
def translatedVariantChoices(implicit ctx: Context) = List(
Variant.Standard.id.toString -> trans.standard.str(),
Variant.Chess960.id.toString -> StringHelper.ucFirst(Variant.Chess960.name)
Variant.Chess960.id.toString -> Variant.Chess960.name.capitalize
)
def translatedSpeedChoices(implicit ctx: Context) = Speed.all map { s
s.id.toString -> (s.toString + " - " + StringHelper.ucFirst(s.name))
s.id.toString -> (s.toString + " - " + s.name.capitalize)
}
def eloDiffChoices(elo: Int)(implicit ctx: Context) = FilterConfig.eloDiffs map { diff

View file

@ -11,8 +11,6 @@ object StringHelper extends StringHelper
trait StringHelper {
def ucFirst(str: String) = ~(str lift 0).map(_.toUpper) + (str drop 1)
def slugify(input: String) = {
val nowhitespace = input.trim.replace(" ", "-")
val normalized = Normalizer.normalize(nowhitespace, Normalizer.Form.NFD)

View file

@ -1,6 +1,9 @@
package lila
package tournament
import chess.{ Mode, Variant }
import lila.setup.Mappings
import play.api.data._
import play.api.data.Forms._
import play.api.data.validation.Constraints._
@ -35,7 +38,9 @@ final class DataForm(isDev: Boolean) {
"clockTime" -> numberIn(clockTimeChoices),
"clockIncrement" -> numberIn(clockIncrementChoices),
"minutes" -> numberIn(minuteChoices),
"minPlayers" -> numberIn(minPlayerChoices)
"minPlayers" -> numberIn(minPlayerChoices),
"variant" -> Mappings.variant,
"mode" -> Mappings.mode(true)
)(TournamentSetup.apply)(TournamentSetup.unapply)
.verifying("Invalid clock", _.validClock)
.verifying("Increase tournament duration, or decrease game clock", _.validTiming)
@ -43,14 +48,18 @@ final class DataForm(isDev: Boolean) {
clockTime = clockTimeDefault,
clockIncrement = clockIncrementDefault,
minutes = minuteDefault,
minPlayers = minPlayerDefault)
minPlayers = minPlayerDefault,
variant = Variant.Standard.id,
mode = Mode.Casual.id.some)
}
private[tournament] case class TournamentSetup(
clockTime: Int,
clockIncrement: Int,
minutes: Int,
minPlayers: Int) {
minPlayers: Int,
variant: Int,
mode: Option[Int]) {
def validClock = (clockTime + clockIncrement) > 0

View file

@ -22,18 +22,17 @@ final class GameJoiner(
def apply(tour: Started)(pairing: Pairing): IO[DbGame] = for {
user1 getUser(pairing.user1) map (_ err "No such user " + pairing)
user2 getUser(pairing.user2) map (_ err "No such user " + pairing)
variant = chess.Variant.Standard
game = DbGame(
game = chess.Game(
board = chess.Board init variant,
board = chess.Board init tour.variant,
clock = tour.clock.chessClock.some
),
ai = None,
whitePlayer = DbPlayer.white withUser user1,
blackPlayer = DbPlayer.black withUser user2,
creatorColor = chess.Color.White,
mode = chess.Mode.Casual,
variant = variant
mode = tour.mode,
variant = tour.variant
).withTournamentId(tour.id)
.withId(pairing.gameId)
.start

View file

@ -8,6 +8,7 @@ import com.mongodb.casbah.query.Imports.DBObject
import ornicar.scalalib.Random
import scalaz.NonEmptyList
import chess.{ Variant, Mode }
import user.User
import game.PovRef
@ -16,6 +17,8 @@ case class Data(
clock: TournamentClock,
minutes: Int,
minPlayers: Int,
variant: Variant,
mode: Mode,
createdAt: DateTime,
createdBy: String)
@ -40,6 +43,10 @@ sealed trait Tournament {
def minutes = data.minutes
lazy val duration = new Duration(minutes * 60 * 1000)
def variant = data.variant
def mode = data.mode
def rated = mode.rated
def userIds = players map (_.id)
def activeUserIds = players filter (_.active) map (_.id)
def nbActiveUsers = players count (_.active)
@ -79,6 +86,8 @@ sealed trait StartedOrFinished extends Tournament {
clock = data.clock,
minutes = data.minutes,
minPlayers = data.minPlayers,
variant = data.variant.id,
mode = data.mode.id,
createdAt = data.createdAt,
createdBy = data.createdBy,
startedAt = startedAt.some,
@ -112,6 +121,8 @@ case class Created(
status = Status.Created.id,
name = data.name,
clock = data.clock,
variant = data.variant.id,
mode = data.mode.id,
minutes = data.minutes,
minPlayers = data.minPlayers,
createdAt = data.createdAt,
@ -214,11 +225,13 @@ case class RawTournament(
status: Int,
startedAt: Option[DateTime] = None,
players: List[Player] = Nil,
pairings: List[RawPairing] = Nil) {
pairings: List[RawPairing] = Nil,
variant: Int = Variant.Standard.id,
mode: Int = Mode.Casual.id) {
def created: Option[Created] = (status == Status.Created.id) option Created(
id = id,
data = Data(name, clock, minutes, minPlayers, createdAt, createdBy),
data = Data(name, clock, minutes, minPlayers, Variant orDefault variant, Mode orDefault mode, createdAt, createdBy),
players = players)
def started: Option[Started] = for {
@ -226,7 +239,7 @@ case class RawTournament(
if status == Status.Started.id
} yield Started(
id = id,
data = Data(name, clock, minutes, minPlayers, createdAt, createdBy),
data = Data(name, clock, minutes, minPlayers, Variant orDefault variant, Mode orDefault mode, createdAt, createdBy),
startedAt = stAt,
players = players,
pairings = decodePairings)
@ -236,7 +249,7 @@ case class RawTournament(
if status == Status.Finished.id
} yield Finished(
id = id,
data = Data(name, clock, minutes, minPlayers, createdAt, createdBy),
data = Data(name, clock, minutes, minPlayers, Variant orDefault variant, Mode orDefault mode, createdAt, createdBy),
startedAt = stAt,
players = players,
pairings = decodePairings)
@ -258,13 +271,17 @@ object Tournament {
createdBy: User,
clock: TournamentClock,
minutes: Int,
minPlayers: Int): Created = Created(
minPlayers: Int,
variant: Variant,
mode: Mode): Created = Created(
id = Random nextString 8,
data = Data(
name = RandomName(),
clock = clock,
createdBy = createdBy.id,
createdAt = DateTime.now,
variant = variant,
mode = mode,
minutes = minutes,
minPlayers = minPlayers),
players = List(Player(createdBy))

View file

@ -7,6 +7,7 @@ import scalaz.effects._
import scalaz.{ NonEmptyList, Success, Failure }
import play.api.libs.json._
import chess.{ Mode, Variant }
import controllers.routes
import game.DbGame
import user.User
@ -37,7 +38,9 @@ private[tournament] final class TournamentApi(
createdBy = me,
clock = TournamentClock(setup.clockTime * 60, setup.clockIncrement),
minutes = setup.minutes,
minPlayers = setup.minPlayers)
minPlayers = setup.minPlayers,
mode = Mode orDefault ~setup.mode,
variant = Variant orDefault setup.variant)
_ repo saveIO created
_ (withdrawIds map socket.reload).sequence
_ reloadSiteSocket
@ -47,15 +50,11 @@ private[tournament] final class TournamentApi(
def startIfReady(created: Created): Option[IO[Unit]] = created.startIfReady map doStart
def earlyStart(created: Created): Option[IO[Unit]] =
def earlyStart(created: Created): Option[IO[Unit]] =
created.readyToEarlyStart option doStart(created.start)
private def doStart(started: Started): IO[Unit] = for {
_ repo saveIO started
_ socket start started.id
_ reloadSiteSocket
_ lobbyReload
} yield ()
private def doStart(started: Started): IO[Unit] =
(repo saveIO started) >> (socket start started.id) >> reloadSiteSocket >> lobbyReload
def wipeEmpty(created: Created): IO[Unit] = (for {
_ repo removeIO created

View file

@ -10,6 +10,14 @@
@tours.map { tour =>
<tr>
<td>@tournament.linkTo(tour)</td>
<td class="small">
@if(tour.variant.exotic) {
960
}
@if(tour.rated) {
rated
}
</td>
<td>@tour.clock.show</td>
<td>@{tour.minutes}m</td>
<td>@tour.playerRatio</td>

View file

@ -8,7 +8,7 @@ You will be notified when the tournament starts, so it is safe to
<a target="_blank" href="@routes.Lobby.home()">play in another tab</a> while waiting.
## Is it rated?
No, tournament games won't impact your ELO.
Some tournaments are rated and will affect your ELO.
## How to win?
The players with the more points at the end of the tournament duration wins.

View file

@ -12,6 +12,22 @@ title = "New tournament") {
<p class="error">@error.message</p>
}
<table>
<tr>
<th>
<label for="@form("variant").id">@trans.variant()</label>
</th>
<td>
@base.select(form("variant"), translatedVariantChoices)
</td>
</tr>
<tr>
<th>
<label for="@form("mode").id">@trans.mode()</label>
</th>
<td>
@base.select(form("mode"), translatedModeChoices)
</td>
</tr>
<tr>
<th>
<label>Game clock</label>

View file

@ -6,8 +6,8 @@
<thead>
<tr>
<th class="large">Open tournaments</th>
<th>Clock</th>
<th>Duration</th>
<th>@trans.mode()</th>
<th>@trans.timeControl()</th>
<th colspan="2">Players</th>
</tr>
</thead>
@ -15,8 +15,15 @@
@createds.map { tour =>
<tr>
<td>@linkTo(tour)</td>
<td>@tour.clock.show</td>
<td>@{tour.minutes}m</td>
<td class="small">
@if(tour.variant.exotic) {
960
}
@if(tour.rated) {
@trans.rated()
}
</td>
<td>@tour.clock.show | @{tour.minutes}m</td>
<td>@tour.playerRatio</td>
<td>
@ctx.me.map { me =>
@ -43,8 +50,8 @@
<thead>
<tr>
<th class="large">Now Playing</th>
<th>Clock</th>
<th>Duration</th>
<th>@trans.mode()</th>
<th>@trans.timeControl()</th>
<th>Players</th>
<th>Leader</th>
</tr>
@ -53,8 +60,15 @@
@starteds.map { tour =>
<tr>
<td>@linkTo(tour)</td>
<td>@tour.clock.show</td>
<td>@{tour.minutes}m</td>
<td class="small">
@if(tour.variant.exotic) {
960
}
@if(tour.rated) {
@trans.rated()
}
</td>
<td>@tour.clock.show | @{tour.minutes}m</td>
<td>@tour.playerRatio</td>
<td>@tour.winner.map { player =>
@userInfosLink(player.username, player.elo.some, withOnline = false)
@ -67,8 +81,8 @@
<thead>
<tr>
<th class="large">Finished</th>
<th>Clock</th>
<th>Duration</th>
<th>@trans.mode()</th>
<th>@trans.timeControl()</th>
<th>Players</th>
<th>Winner</th>
</tr>
@ -77,8 +91,15 @@
@finisheds.map { tour =>
<tr>
<td>@linkTo(tour)</td>
<td>@tour.clock.show</td>
<td>@{tour.minutes}m</td>
<td class="small">
@if(tour.variant.exotic) {
960
}
@if(tour.rated) {
@trans.rated()
}
</td>
<td>@tour.clock.show | @{tour.minutes}m</td>
<td>@tour.playerRatio</td>
<td>@tour.winner.map { player =>
@userInfosLink(player.username, player.elo.some, withOnline = false)

View file

@ -6,15 +6,10 @@
<br />
Created by @userIdLink(tour.createdBy.some, withOnline = false)
<br /><br />
@tour.playerRatio players,
@if(false) {
rated
} else {
casual
}
<span class="s16 clock">@tour.clock.show</span>,
@variantName(tour.variant).capitalize,
@{ tour.rated.fold(trans.rated(), trans.casual()) }
<br /><br />
<span class="s16 clock">@tour.clock.show</span>
<br />
Duration: @tour.minutes minutes
@if(tour.isRunning && (tour isActive ctx.me)) {
<br /><br />

View file

@ -42,6 +42,9 @@
#tournament table.slist tbody span.winner {
background-position: right -304px;
}
#tournament table.slist .small {
font-size: 0.8em;
}
#tournament form.inline {
display: inline;