more tournament rewrite WIP
This commit is contained in:
parent
2c2ec63469
commit
4acfbfdd1f
|
@ -12,7 +12,7 @@ import lila.common.HTTPRequest
|
|||
import lila.game.{ Pov, PlayerRef, GameRepo, Game => GameModel }
|
||||
import lila.hub.actorApi.map.Tell
|
||||
import lila.round.actorApi.round._
|
||||
import lila.tournament.{ TournamentRepo, Tournament => Tourney }
|
||||
import lila.tournament.{ TournamentRepo, Tournament => Tourney, MiniStanding }
|
||||
import lila.user.{ User => UserModel, UserRepo }
|
||||
import makeTimeout.large
|
||||
import views._
|
||||
|
@ -59,7 +59,7 @@ object Round extends LilaController with TheftPrevention {
|
|||
if (pov.game.playableByAi) env.roundMap ! Tell(pov.game.id, AiPlay)
|
||||
pov.game.started.fold(
|
||||
PreventTheft(pov) {
|
||||
myTour(pov.game.tournamentId) zip
|
||||
myTour(pov.game.tournamentId, true) zip
|
||||
(pov.game.simulId ?? Env.simul.repo.find) zip
|
||||
Env.game.crosstableApi(pov.game) zip
|
||||
(!pov.game.isTournament ?? otherPovs(pov.gameId)) flatMap {
|
||||
|
@ -145,7 +145,7 @@ object Round extends LilaController with TheftPrevention {
|
|||
else ctx.userId.flatMap(pov.game.playerByUserId) ifTrue pov.game.playable match {
|
||||
case Some(player) => renderPlayer(pov withColor player.color)
|
||||
case None if HTTPRequest.isHuman(ctx.req) =>
|
||||
myTour(pov.game.tournamentId) zip
|
||||
myTour(pov.game.tournamentId, false) zip
|
||||
(pov.game.simulId ?? Env.simul.repo.find) zip
|
||||
Env.game.crosstableApi(pov.game) zip
|
||||
Env.api.roundApi.watcher(pov, lila.api.Mobile.Api.currentVersion, tv = none) map {
|
||||
|
@ -163,11 +163,9 @@ object Round extends LilaController with TheftPrevention {
|
|||
api = apiVersion => Env.api.roundApi.watcher(pov, apiVersion, tv = none) map { Ok(_) }
|
||||
)
|
||||
|
||||
private def myTour(tourId: Option[String])(implicit ctx: Context): Fu[Option[Tourney]] =
|
||||
private def myTour(tourId: Option[String], withStanding: Boolean)(implicit ctx: Context): Fu[Option[MiniStanding]] =
|
||||
tourId ?? { tid =>
|
||||
ctx.userId ?? { uid =>
|
||||
Env.tournament.cached tour tid map (_ filter (_ contains uid))
|
||||
}
|
||||
Env.tournament.api.miniStanding(tid, ctx.userId, withStanding)
|
||||
}
|
||||
|
||||
private def join(pov: Pov)(implicit ctx: Context): Fu[Result] =
|
||||
|
@ -211,12 +209,12 @@ object Round extends LilaController with TheftPrevention {
|
|||
}
|
||||
|
||||
private def sides(pov: Pov, isPlayer: Boolean)(implicit ctx: Context) =
|
||||
myTour(pov.game.simulId) zip
|
||||
myTour(pov.game.simulId, isPlayer) zip
|
||||
(pov.game.simulId ?? Env.simul.repo.find) zip
|
||||
GameRepo.initialFen(pov.game) zip
|
||||
Env.game.crosstableApi(pov.game) map {
|
||||
case (((myTour, simul), initialFen), crosstable) =>
|
||||
Ok(html.game.sides(pov, initialFen, myTour, crosstable, withTourStanding = isPlayer, simul))
|
||||
case (((tour, simul), initialFen), crosstable) =>
|
||||
Ok(html.game.sides(pov, initialFen, tour, crosstable, simul))
|
||||
}
|
||||
|
||||
def continue(id: String, mode: String) = Open { implicit ctx =>
|
||||
|
|
|
@ -57,9 +57,9 @@ object Tournament extends LilaController {
|
|||
}
|
||||
|
||||
def gameStanding(id: String) = Open { implicit ctx =>
|
||||
env.cached tour id map {
|
||||
case Some(t) if !t.isCreated => Ok(html.tournament.gameStanding(t, true))
|
||||
case _ => NotFound
|
||||
env.api.miniStanding(id, true) map {
|
||||
case Some(m) if !m.tour.isCreated => Ok(html.tournament.gameStanding(m))
|
||||
case _ => NotFound
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -70,11 +70,11 @@ object Tournament extends LilaController {
|
|||
html = repo enterableById id map {
|
||||
case None => tournamentNotFound
|
||||
case Some(tour) =>
|
||||
env.api.join(tour, me)
|
||||
env.api.join(tour.id, me)
|
||||
Redirect(routes.Tournament.show(tour.id))
|
||||
},
|
||||
api = _ => OptionFuOk(repo enterableById id) { tour =>
|
||||
env.api.join(tour, me)
|
||||
env.api.join(tour.id, me)
|
||||
fuccess(Json.obj("ok" -> true))
|
||||
}
|
||||
)
|
||||
|
|
|
@ -45,7 +45,7 @@ userId: @Html(ctx.userId.fold("null")(id => s""""$id""""))
|
|||
|
||||
@analyse.layout(
|
||||
title = title,
|
||||
side = views.html.game.side(pov, initialFen, none, withTourStanding = false, simul = simul, userTv = userTv).some,
|
||||
side = views.html.game.side(pov, initialFen, none, simul = simul, userTv = userTv).some,
|
||||
chat = base.chatDom(trans.spectatorRoom.str(), ctx.isAuth).some,
|
||||
underchat = underchat.some,
|
||||
moreCss = moreCss,
|
||||
|
|
|
@ -37,7 +37,7 @@ orientation: "@pov.color.name"
|
|||
|
||||
@analyse.layout(
|
||||
title = title,
|
||||
side = views.html.game.side(pov, initialFen, none, withTourStanding = false, simul = simul).some,
|
||||
side = views.html.game.side(pov, initialFen, none, simul = simul).some,
|
||||
chat = base.chatDom(trans.spectatorRoom.str(), ctx.isAuth).some,
|
||||
underchat = underchat.some,
|
||||
moreJs = moreJs,
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
@(pov: Pov, initialFen: Option[String], myTour: Option[lila.tournament.Tournament], withTourStanding: Boolean, simul: Option[lila.simul.Simul], userTv: Option[User] = None)(implicit ctx: Context)
|
||||
@(pov: Pov, initialFen: Option[String], tour: Option[lila.tournament.MiniStanding], simul: Option[lila.simul.Simul], userTv: Option[User] = None)(implicit ctx: Context)
|
||||
|
||||
@import pov._
|
||||
@import lila.tournament.arena
|
||||
|
@ -86,16 +86,14 @@
|
|||
</div>
|
||||
}
|
||||
|
||||
@myTour match {
|
||||
case Some(t) if !t.isCreated => { @tournament.gameStanding(t, withTourStanding) }
|
||||
case _ => {
|
||||
@pov.game.tournamentId.map { tourId =>
|
||||
@tour match {
|
||||
case Some(m) if !m.tour.isCreated => { @tournament.gameStanding(m) }
|
||||
case Some(m) => {
|
||||
<div class="game_tournament side_box no_padding">
|
||||
<p class="top text" data-icon="g"><a href="@routes.Tournament.show(tourId)">@tournamentIdToName(tourId)</a></p>
|
||||
<p class="top text" data-icon="g"><a href="@routes.Tournament.show(m.tour.id)">@m.tour.fullName</a></p>
|
||||
</div>
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@simul.map { sim =>
|
||||
<div class="game_simul side_box no_padding">
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
@(pov: Pov, initialFen: Option[String], myTour: Option[lila.tournament.Tournament], cross: Option[lila.game.Crosstable], withTourStanding: Boolean, simul: Option[lila.simul.Simul], userTv: Option[User] = None)(implicit ctx: Context)
|
||||
@(pov: Pov, initialFen: Option[String], tour: Option[lila.tournament.MiniStanding], cross: Option[lila.game.Crosstable], simul: Option[lila.simul.Simul], userTv: Option[User] = None)(implicit ctx: Context)
|
||||
|
||||
<div class="sides">
|
||||
@side(pov, initialFen, myTour, withTourStanding, simul, userTv)
|
||||
@side(pov, initialFen, tour, simul, userTv)
|
||||
@cross.map { c =>
|
||||
<div class="crosstable">
|
||||
@crosstable(c, pov.gameId.some)
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
@(pov: Pov, data: play.api.libs.json.JsObject, tour: Option[lila.tournament.Tournament], simul: Option[lila.simul.Simul], cross: Option[lila.game.Crosstable], playing: List[Pov])(implicit ctx: Context)
|
||||
@(pov: Pov, data: play.api.libs.json.JsObject, tour: Option[lila.tournament.MiniStanding], simul: Option[lila.simul.Simul], cross: Option[lila.game.Crosstable], playing: List[Pov])(implicit ctx: Context)
|
||||
|
||||
@import pov._
|
||||
|
||||
|
@ -20,7 +20,7 @@ userId: @Html(ctx.userId.fold("null")(id => s""""$id""""))
|
|||
|
||||
@round.layout(
|
||||
title = title,
|
||||
side = views.html.game.side(pov, (data\"game"\"initialFen").asOpt[String], tour, withTourStanding = true, simul),
|
||||
side = views.html.game.side(pov, (data\"game"\"initialFen").asOpt[String], tour, simul),
|
||||
chat = pov.game.hasChat.option(base.chatDom(trans.chatRoom.str(), ctx.isAuth)),
|
||||
underchat = views.html.game.watchers().some,
|
||||
moreJs = moreJs,
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
@(pov: Pov, data: play.api.libs.json.JsObject, tour: Option[lila.tournament.Tournament], simul: Option[lila.simul.Simul], cross: Option[lila.game.Crosstable], userTv: Option[User] = None)(implicit ctx: Context)
|
||||
@(pov: Pov, data: play.api.libs.json.JsObject, tour: Option[lila.tournament.MiniStanding], simul: Option[lila.simul.Simul], cross: Option[lila.game.Crosstable], userTv: Option[User] = None)(implicit ctx: Context)
|
||||
|
||||
@title = @{ s"${playerText(pov.player)} vs ${playerText(pov.opponent)} in ${pov.gameId}" }
|
||||
|
||||
|
@ -17,7 +17,7 @@ i18n: @jsI18n()
|
|||
|
||||
@round.layout(
|
||||
title = title,
|
||||
side = views.html.game.side(pov, (data\"game"\"initialFen").asOpt[String], tour, withTourStanding = false, simul = simul, userTv = userTv),
|
||||
side = views.html.game.side(pov, (data\"game"\"initialFen").asOpt[String], tour, simul = simul, userTv = userTv),
|
||||
chat = base.chatDom(trans.spectatorRoom.str()).some,
|
||||
underchat = views.html.game.watchers().some,
|
||||
moreJs = moreJs,
|
||||
|
|
|
@ -14,7 +14,7 @@ orientation: "@pov.color.name"
|
|||
|
||||
@round.layout(
|
||||
title = title,
|
||||
side = views.html.game.side(pov, initialFen, none, withTourStanding = false, simul = none, userTv = none),
|
||||
side = views.html.game.side(pov, initialFen, none, simul = none, userTv = none),
|
||||
chat = base.chatDom(trans.spectatorRoom.str()).some,
|
||||
underchat = views.html.game.watchers().some,
|
||||
moreJs = moreJs,
|
||||
|
|
|
@ -1,23 +1,15 @@
|
|||
@(t: Tournament, withStanding: Boolean)(implicit ctx: Context)
|
||||
@(m: lila.tournament.MiniStanding)(implicit ctx: Context)
|
||||
|
||||
<div class="game_tournament side_box no_padding scroll-shadow-soft">
|
||||
<p class="top text" data-icon="g"><a href="@routes.Tournament.show(t.id)">@t.fullName</a></p>
|
||||
<div class="clock" data-time="@t.remainingSeconds">
|
||||
<div class="time text" data-icon="p">@t.clockStatus</div>
|
||||
<p class="top text" data-icon="g"><a href="@routes.Tournament.show(m.tour.id)">@m.tour.fullName</a></p>
|
||||
<div class="clock" data-time="@m.tour.remainingSeconds">
|
||||
<div class="time text" data-icon="p">@m.tour.clockStatus</div>
|
||||
</div>
|
||||
@if(withStanding) {
|
||||
<table class="slist standing">
|
||||
<tbody>
|
||||
@t.rankedPlayers.take(50).map {
|
||||
@m.standing.map {
|
||||
case lila.tournament.RankedPlayer(rank, player) => {
|
||||
@defining((
|
||||
t scoreSheet player,
|
||||
// TODO FIXME that's a little ugly I must say.
|
||||
t.system.scoringSystem match {
|
||||
case ss @ lila.tournament.arena.ScoringSystem => ss.scoreSheet(t, player.id).onFire
|
||||
case _ => false
|
||||
})) {
|
||||
case (scoreSheet, onFire) => {
|
||||
<tr @if(ctx.userId.exists(player.id==)) { class="me" }>
|
||||
<td class="name">
|
||||
@if(player.withdraw) {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
@(tour: lila.tournament.Tournament)
|
||||
@(tour: Tournament)
|
||||
|
||||
@notification.view("tournament_reminder", closable = false, glow = true) {
|
||||
<a data-icon="g" href="@routes.Tournament.show(tour.id)"> @tour.name</a> in progress!
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
@(tour: lila.tournament.Tournament, variantLink: Boolean = false)(implicit ctx: Context)
|
||||
@(tour: Tournament, variantLink: Boolean = false)(implicit ctx: Context)
|
||||
<span class="setup">
|
||||
@tour.clock.show •
|
||||
@if(tour.variant.exotic) {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
@(tour: lila.tournament.Tournament, socketVersion: Int, data: play.api.libs.json.JsObject, chat: Option[lila.chat.UserChat])(implicit ctx: Context)
|
||||
@(tour: Tournament, socketVersion: Int, data: play.api.libs.json.JsObject, chat: Option[lila.chat.UserChat])(implicit ctx: Context)
|
||||
|
||||
@underchat = {
|
||||
<div class="watchers" data-icon="v">
|
||||
|
@ -29,7 +29,7 @@ chessground = false) {
|
|||
<div id="tournament" @tour.schedule.map { sched =>
|
||||
class="scheduled @sched.freq @sched.speed @sched.variant"
|
||||
}></div>
|
||||
@if(!tour.isRunning && !tour.isFinished) {
|
||||
@if(tour.isCreated) {
|
||||
<div id="tournament_faq" class="none">
|
||||
@faq(tour.rated.some, tour.system.some, tour.`private`.option(tour.id))
|
||||
</div>
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
@(tour: lila.tournament.Tournament)(implicit ctx: Context)
|
||||
@(tour: Tournament)(implicit ctx: Context)
|
||||
|
||||
<div class="side_box padded">
|
||||
<div class="game_infos" data-icon="@tour.perfType.map(_.iconChar)">
|
||||
|
|
|
@ -78,7 +78,8 @@ object BSONHandlers {
|
|||
withdraw = r boolD "w",
|
||||
score = r int "s",
|
||||
perf = r int "p",
|
||||
magicScore = r int "m")
|
||||
magicScore = r int "m",
|
||||
fire = r boolD "f")
|
||||
def writes(w: BSON.Writer, o: Player) = BSONDocument(
|
||||
"_id" -> o.id,
|
||||
"tid" -> o.tourId,
|
||||
|
@ -88,7 +89,8 @@ object BSONHandlers {
|
|||
"w" -> w.boolO(o.withdraw),
|
||||
"s" -> o.score,
|
||||
"p" -> o.perf,
|
||||
"m" -> o.magicScore)
|
||||
"m" -> o.magicScore,
|
||||
"f" -> w.boolO(o.fire))
|
||||
}
|
||||
|
||||
implicit val pairingHandler = new BSON[Pairing] {
|
||||
|
@ -104,9 +106,7 @@ object BSONHandlers {
|
|||
turns = r intO "t",
|
||||
date = r date "d",
|
||||
berserk1 = r intD "b1",
|
||||
berserk2 = r intD "b2",
|
||||
perf1 = r intD "p1",
|
||||
perf2 = r intD "p2")
|
||||
berserk2 = r intD "b2")
|
||||
}
|
||||
def writes(w: BSON.Writer, o: Pairing) = BSONDocument(
|
||||
"_id" -> o.id,
|
||||
|
@ -117,9 +117,7 @@ object BSONHandlers {
|
|||
"t" -> o.turns,
|
||||
"d" -> w.date(o.date),
|
||||
"b1" -> w.intO(o.berserk1),
|
||||
"b2" -> w.intO(o.berserk2),
|
||||
"p1" -> w.intO(o.perf1),
|
||||
"p2" -> w.intO(o.perf2))
|
||||
"b2" -> w.intO(o.berserk2))
|
||||
}
|
||||
|
||||
private implicit val eventHandler = new BSON[Event] {
|
||||
|
|
|
@ -6,7 +6,7 @@ import lila.game.{ Game, PovRef, IdGenerator }
|
|||
import org.joda.time.DateTime
|
||||
|
||||
case class Pairing(
|
||||
id: String, // game ID
|
||||
id: String, // game In
|
||||
tourId: String,
|
||||
status: chess.Status,
|
||||
user1: String,
|
||||
|
@ -15,9 +15,7 @@ case class Pairing(
|
|||
turns: Option[Int],
|
||||
date: DateTime,
|
||||
berserk1: Int,
|
||||
berserk2: Int,
|
||||
perf1: Int,
|
||||
perf2: Int) {
|
||||
berserk2: Int) {
|
||||
|
||||
def gameId = id
|
||||
|
||||
|
@ -51,11 +49,6 @@ case class Pairing(
|
|||
else if (userId == user2) berserk2
|
||||
else 0
|
||||
|
||||
def perfOf(userId: String): Int =
|
||||
if (userId == user1) perf1
|
||||
else if (userId == user2) perf2
|
||||
else 0
|
||||
|
||||
def validBerserkOf(userId: String): Int =
|
||||
notSoQuickFinish ?? berserkOf(userId)
|
||||
|
||||
|
@ -65,9 +58,7 @@ case class Pairing(
|
|||
def finish(g: Game) = copy(
|
||||
status = g.status,
|
||||
winner = g.winnerUserId,
|
||||
turns = g.turns.some,
|
||||
perf1 = ~g.whitePlayer.ratingDiff,
|
||||
perf2 = ~g.blackPlayer.ratingDiff)
|
||||
turns = g.turns.some)
|
||||
}
|
||||
|
||||
private[tournament] object Pairing {
|
||||
|
@ -87,7 +78,5 @@ private[tournament] object Pairing {
|
|||
turns = none,
|
||||
date = d | DateTime.now,
|
||||
berserk1 = 0,
|
||||
berserk2 = 0,
|
||||
perf1 = 0,
|
||||
perf2 = 0)
|
||||
berserk2 = 0)
|
||||
}
|
||||
|
|
|
@ -4,8 +4,6 @@ import lila.game.PerfPicker
|
|||
import lila.rating.Perf
|
||||
import lila.user.{ User, Perfs }
|
||||
|
||||
import ornicar.scalalib.Random
|
||||
|
||||
private[tournament] case class Player(
|
||||
id: String, // random
|
||||
tourId: String,
|
||||
|
@ -16,7 +14,7 @@ private[tournament] case class Player(
|
|||
score: Int = 0,
|
||||
perf: Int = 0,
|
||||
magicScore: Int = 0,
|
||||
rank: Int = Int.MaxValue) {
|
||||
fire: Boolean = false) {
|
||||
|
||||
def active = !withdraw
|
||||
|
||||
|
@ -28,13 +26,13 @@ private[tournament] case class Player(
|
|||
def unWithdraw = copy(withdraw = false)
|
||||
|
||||
def recomputeMagicScore = copy(
|
||||
magicScore = (score * 1000000) + (perf * 1000) + rating)
|
||||
magicScore = (score * 1000000) + (perf * 1000) + rating + withdraw.fold(Int.MinValue / 2, 0))
|
||||
}
|
||||
|
||||
private[tournament] object Player {
|
||||
|
||||
private[tournament] def make(tourId: String, user: User, perfLens: Perfs => Perf): Player = new Player(
|
||||
id = Random nextStringUppercase 8,
|
||||
id = lila.game.IdGenerator.game,
|
||||
tourId = tourId,
|
||||
userId = user.id,
|
||||
rating = perfLens(user.perfs).intRating,
|
||||
|
|
|
@ -17,6 +17,9 @@ object PlayerRepo {
|
|||
private def selectId(id: String) = BSONDocument("_id" -> id)
|
||||
private def selectTour(tourId: String) = BSONDocument("tid" -> tourId)
|
||||
private def selectUser(userId: String) = BSONDocument("uid" -> userId)
|
||||
private def selectTourUser(tourId: String, userId: String) = BSONDocument(
|
||||
"tid" -> tourId,
|
||||
"uid" -> userId)
|
||||
private val selectActive = BSONDocument("w" -> BSONDocument("$ne" -> true))
|
||||
private val selectWithdraw = BSONDocument("w" -> true)
|
||||
private val bestSort = BSONDocument("m" -> -1)
|
||||
|
@ -44,9 +47,12 @@ object PlayerRepo {
|
|||
def remove(tourId: String, userId: String) =
|
||||
coll.remove(selectTour(tourId) ++ selectUser(userId)).void
|
||||
|
||||
def exists(tourId: String, userId: String) =
|
||||
coll.db command Count(coll.name, selectTourUser(tourId, userId).some) map (0!=)
|
||||
|
||||
def existsActive(tourId: String, userId: String) =
|
||||
coll.db command Count(coll.name, Some(
|
||||
selectTour(tourId) ++ selectUser(userId) ++ selectActive
|
||||
selectTourUser(tourId, userId) ++ selectActive
|
||||
)) map (0!=)
|
||||
|
||||
def unWithdraw(tourId: String) = coll.update(
|
||||
|
@ -57,6 +63,11 @@ object PlayerRepo {
|
|||
def find(tourId: String, userId: String): Fu[Option[Player]] =
|
||||
coll.find(selectTour(tourId) ++ selectUser(userId)).one[Player]
|
||||
|
||||
def update(tourId: String, userId: String)(f: Player => Fu[Player]) =
|
||||
find(tourId, userId) flatten s"No such player: $tourId/$userId" flatMap f flatMap { player =>
|
||||
coll.update(selectId(player.id), player).void
|
||||
}
|
||||
|
||||
def join(tourId: String, user: User, perfLens: Perfs => Perf) =
|
||||
find(tourId, user.id) flatMap {
|
||||
case Some(p) if p.withdraw => coll.update(selectId(p.id), BSONDocument("$unset" -> BSONDocument("w" -> true)))
|
||||
|
|
|
@ -36,6 +36,7 @@ trait Score {
|
|||
trait ScoreSheet {
|
||||
def scores: List[Score]
|
||||
def total: Int
|
||||
def onFire: Boolean
|
||||
}
|
||||
|
||||
trait ScoringSystem {
|
||||
|
|
|
@ -168,12 +168,25 @@ private[tournament] final class TournamentApi(
|
|||
def finishGame(game: Game) {
|
||||
game.tournamentId foreach { tourId =>
|
||||
Sequencing(tourId)(TournamentRepo.startedById) { tour =>
|
||||
PairingRepo.update(game.id, _ finish game) >>-
|
||||
PairingRepo.update(game.id, _ finish game) >>
|
||||
game.userIds.map(updatePlayer(tour)).sequenceFu.void >>-
|
||||
socketReload(tour.id) >>- updateTournamentStanding(tour)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def updatePlayer(tour: Tournament)(userId: String): Funit =
|
||||
(tour.perfType ?? { UserRepo.ratingOf(userId, _) }) flatMap { rating =>
|
||||
PlayerRepo.update(tour.id, userId) { player =>
|
||||
tour.system.scoringSystem.sheet(tour, userId) map { sheet =>
|
||||
player.copy(
|
||||
score = sheet.total,
|
||||
fire = sheet.onFire,
|
||||
perf = rating.fold(player.perf)(_.toInt - player.rating))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def ejectCheater(userId: String) {
|
||||
TournamentRepo.allEnterable foreach {
|
||||
_ foreach { tour =>
|
||||
|
@ -190,6 +203,23 @@ private[tournament] final class TournamentApi(
|
|||
}
|
||||
}
|
||||
|
||||
def miniStanding(tourId: String, withStanding: Boolean): Fu[Option[MiniStanding]] =
|
||||
TournamentRepo byId tourId flatMap {
|
||||
_ ?? { tour =>
|
||||
if (withStanding) PlayerRepo.bestByTourWithRank(tour.id, 20) map { rps =>
|
||||
MiniStanding(tour, rps.some).some
|
||||
}
|
||||
else fuccess(MiniStanding(tour, none).some)
|
||||
}
|
||||
}
|
||||
|
||||
def miniStanding(tourId: String, userId: Option[String], withStanding: Boolean): Fu[Option[MiniStanding]] =
|
||||
userId ?? { uid =>
|
||||
PlayerRepo.exists(tourId, uid) flatMap {
|
||||
_ ?? miniStanding(tourId, withStanding)
|
||||
}
|
||||
}
|
||||
|
||||
private def sequence(tourId: String)(work: => Funit) {
|
||||
sequencers ! Tell(tourId, Sequencer work work)
|
||||
}
|
||||
|
|
|
@ -31,7 +31,7 @@ object ScoringSystem extends AbstractScoringSystem {
|
|||
|
||||
val emptySheet = Sheet(Nil)
|
||||
|
||||
def sheet(tour: Tournament, userId: String) =
|
||||
def sheet(tour: Tournament, userId: String): Fu[Sheet] =
|
||||
PairingRepo.finishedByPlayerChronological(tour.id, userId) map { pairings =>
|
||||
Sheet {
|
||||
val nexts = (pairings drop 1 map Some.apply) :+ None
|
||||
|
|
5
modules/tournament/src/main/model.scala
Normal file
5
modules/tournament/src/main/model.scala
Normal file
|
@ -0,0 +1,5 @@
|
|||
package lila.tournament
|
||||
|
||||
case class MiniStanding(
|
||||
tour: Tournament,
|
||||
standing: Option[RankedPlayers])
|
|
@ -259,6 +259,9 @@ trait UserRepo {
|
|||
|
||||
def email(id: ID): Fu[Option[String]] = $primitive.one($select(id), F.email)(_.asOpt[String])
|
||||
|
||||
def ratingOf(id: ID, perfType: PerfType) =
|
||||
$primitive.one($select(id), s"${F.perfs}.${perfType.key}.gl.r")(_.asOpt[Double])
|
||||
|
||||
def setSeenAt(id: ID) {
|
||||
$update.fieldUnchecked(id, "seenAt", $date(DateTime.now))
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue