tournament conditions WIP

This commit is contained in:
Thibault Duplessis 2016-06-17 15:58:32 +02:00
parent 0ca7f0f153
commit eca28d4f9a
5 changed files with 122 additions and 2 deletions

View file

@ -30,7 +30,7 @@ final class Env(
lazy val jsonView = new JsonView(lightUser)
def get(user: lila.user.User, perfType: lila.rating.PerfType) =
def get(user: lila.user.User, perfType: lila.rating.PerfType): Fu[PerfStat] =
storage.find(user.id, perfType) orElse {
indexer.userPerf(user, perfType) >> storage.find(user.id, perfType)
} map (_ | PerfStat.init(user.id, perfType))

View file

@ -28,6 +28,8 @@ object BSONHandlers {
def write(x: LeaderboardApi.Ratio) = BSONInteger((x.value * 100000).toInt)
}
import Condition.BSONHandlers.AllBSONHandler
implicit val tournamentHandler = new BSON[Tournament] {
def reads(r: BSON.Reader) = {
val variant = r.intO("variant").fold[Variant](Variant.default)(Variant.orDefault)
@ -44,6 +46,7 @@ object BSONHandlers {
position = position,
mode = r.intO("mode") flatMap Mode.apply getOrElse Mode.Rated,
`private` = r boolD "private",
conditions = r.getO[Condition.All]("conditions") getOrElse Condition.All.empty,
schedule = for {
doc <- r.getO[BSONDocument]("schedule")
freq <- doc.getAs[String]("freq") flatMap Schedule.Freq.apply
@ -68,6 +71,7 @@ object BSONHandlers {
"eco" -> o.position.some.filterNot(_.initial).map(_.eco),
"mode" -> o.mode.some.filterNot(_.rated).map(_.id),
"private" -> w.boolO(o.`private`),
"conditions" -> o.conditions.ifNonEmpty,
"schedule" -> o.schedule.map { s =>
BSONDocument(
"freq" -> s.freq.name,

View file

@ -0,0 +1,113 @@
package lila.tournament
import lila.perfStat.PerfStat
import lila.rating.PerfType
import lila.user.User
sealed abstract class Condition(val key: String) {
def apply(stats: Condition.GetStats)(user: User): Fu[Condition.Verdict]
}
object Condition {
type GetStats = PerfType => Fu[PerfStat]
sealed trait Verdict
case object Accepted extends Verdict
case class Refused(reason: String) extends Verdict
case class NbRatedGame(perf: Option[PerfType], nb: Int) extends Condition("nb") {
def apply(stats: GetStats)(user: User) = fuccess {
perf match {
case Some(p) if user.perfs(p).nb >= nb => Accepted
case Some(p) => Refused(s"Only ${user.perfs(p).nb} of $nb rated ${p.name} games played")
case None if user.count.rated >= nb => Accepted
case None => Refused(s"Only ${user.count.rated} of $nb rated games played")
}
}
}
case class MaxRating(perf: PerfType, rating: Int) extends Condition("rating") {
def apply(stats: GetStats)(user: User) = stats(perf) map { s =>
s.highest match {
case None => Accepted
case Some(h) if h.int <= rating => Accepted
case Some(h) => Refused(s"Max ${perf.name} rating (${h.int}) is too high.")
}
}
}
case class All(
nbRatedGame: Option[NbRatedGame],
maxRating: Option[MaxRating]) {
def nonEmpty = nbRatedGame.isDefined || maxRating.isDefined
def ifNonEmpty = nonEmpty option this
}
object All {
val empty = All(nbRatedGame = none, maxRating = none)
}
object BSONHandlers {
import reactivemongo.bson._
import lila.db.BSON
import lila.db.BSON.{ Reader, Writer }
import lila.db.dsl._
private implicit val PerfTypeBSONHandler = new BSONHandler[BSONString, PerfType] {
def read(bs: BSONString): PerfType = PerfType(bs.value) err s"No such PerfType: ${bs.value}"
def write(x: PerfType) = BSONString(x.key)
}
private implicit val NbRatedGameHandler = Macros.handler[NbRatedGame]
private implicit val MaxRatingHandler = Macros.handler[MaxRating]
// private implicit val ConditionBSONHandler = new BSON[Condition] {
// def reads(r: Reader) = r.str("key") match {
// case "nb" => NbRatedGameHandler read r.doc
// case "rating" => MaxRatingHandler read r.doc
// case x => sys error s"Invalid condition key $x"
// }
// def writes(w: Writer, x: Condition) = x match {
// case x: NbRatedGame => NbRatedGameHandler write x
// case x: MaxRating => MaxRatingHandler write x
// }
// }
implicit val AllBSONHandler = Macros.handler[All]
}
object DataForm {
import play.api.data._
import play.api.data.Forms._
import lila.common.Form._
val nbRatedGames = Seq(5, 10, 20, 30, 40, 50, 75, 100, 150, 200)
val nbRatedGameChoices = options(nbRatedGames, "%d rated game{s}")
val nbRatedGame = mapping(
"enforce" -> optional(number),
"perf" -> optional(text.verifying(PerfType.byKey.contains _)),
"nb" -> numberIn(nbRatedGameChoices)
)(NbRatedGameSetup.apply)(NbRatedGameSetup.unapply)
case class NbRatedGameSetup(enforce: Option[Int], perf: Option[String], nb: Int) {
def convert = enforce.isDefined option NbRatedGame(PerfType(~perf), nb)
}
val maxRatings = Seq(1000, 1200, 1300, 1400, 1500, 1600, 1700, 1800, 1900, 2000, 2100, 2200)
val maxRatingChoices = options(maxRatings, "max rating of %d")
val maxRating = mapping(
"enforce" -> optional(number),
"perf" -> text.verifying(PerfType.byKey.contains _),
"rating" -> numberIn(maxRatingChoices)
)(MaxRatingSetup.apply)(MaxRatingSetup.unapply)
case class MaxRatingSetup(enforce: Option[Int], perf: String, rating: Int) {
def convert = enforce.isDefined option MaxRating(PerfType(perf) err perf, rating)
}
val all = Form(mapping(
"nbRatedGame" -> nbRatedGame,
"maxRating" -> maxRating
)(AllSetup.apply)(AllSetup.unapply))
case class AllSetup(nbRatedGame: NbRatedGameSetup, maxRating: MaxRatingSetup) {
def convert = All(nbRatedGame.convert, maxRating.convert)
}
}
}

View file

@ -18,6 +18,7 @@ case class Tournament(
position: StartingPosition,
mode: Mode,
`private`: Boolean,
conditions: Condition.All,
schedule: Option[Schedule],
nbPlayers: Int,
createdAt: DateTime,
@ -123,6 +124,7 @@ object Tournament {
position = position,
mode = mode,
`private` = `private`,
conditions = Condition.All.empty,
schedule = None,
startsAt = DateTime.now plusMinutes waitMinutes)
@ -140,6 +142,7 @@ object Tournament {
position = sched.position,
mode = Mode.Rated,
`private` = false,
conditions = Condition.All.empty,
schedule = Some(sched),
startsAt = sched.at)
}

View file

@ -213,7 +213,7 @@ object ApplicationBuild extends Build {
)
lazy val tournament = project("tournament", Seq(
common, hub, socket, chess, game, round, security, chat, memo, quote)).settings(
common, hub, socket, chess, game, round, security, chat, memo, quote, perfStat)).settings(
libraryDependencies ++= provided(play.api, RM)
)