typesafe puzzle round result

This commit is contained in:
Thibault Duplessis 2016-12-07 11:54:28 +01:00
parent d79dc12d03
commit 9804b5987e
7 changed files with 92 additions and 56 deletions

View file

@ -11,8 +11,7 @@ import play.twirl.api.Html
import lila.api.Context
import lila.app._
import lila.game.GameRepo
import lila.puzzle.PuzzleId
import lila.puzzle.{ Generated, Puzzle => PuzzleModel, UserInfos }
import lila.puzzle.{ PuzzleId, Result, Generated, Puzzle => PuzzleModel, UserInfos }
import lila.user.{ User => UserModel, UserRepo }
import views._
@ -26,7 +25,7 @@ object Puzzle extends LilaController {
mode: String,
voted: Option[Boolean],
round: Option[lila.puzzle.Round] = None,
win: Option[Boolean] = None)(implicit ctx: Context): Fu[JsObject] =
result: Option[Result] = None)(implicit ctx: Context): Fu[JsObject] =
lila.puzzle.JsonView(
puzzle = puzzle,
userInfos = userInfos,
@ -34,7 +33,7 @@ object Puzzle extends LilaController {
animationDuration = env.AnimationDuration,
pref = ctx.pref,
isMobileApi = ctx.isMobileApi,
win = win,
result = result,
voted = voted)
private def renderShow(puzzle: PuzzleModel, mode: String)(implicit ctx: Context) =
@ -97,36 +96,76 @@ object Puzzle extends LilaController {
else lila.mon.puzzle.round.material()
env.forms.round.bindFromRequest.fold(
err => fuccess(BadRequest(errorsAsJson(err))),
data => ctx.me match {
case Some(me) =>
lila.mon.puzzle.round.user()
env.finisher(puzzle, me, data) flatMap {
case (newAttempt, None) => UserRepo byId me.id map (_ | me) flatMap { me2 =>
env.api.puzzle find id zip
(env userInfos me2.some) zip
env.api.vote.value(id, me2) flatMap {
case ((p2, infos), voted) => renderJson(
p2 | puzzle, infos, "view", voted = voted, round = newAttempt.some
) map { Ok(_) }
resultInt => {
val result = Result(resultInt == 1)
ctx.me match {
case Some(me) =>
lila.mon.puzzle.round.user()
env.finisher(puzzle, me, result) flatMap {
case (newAttempt, None) => UserRepo byId me.id map (_ | me) flatMap { me2 =>
env.api.puzzle find id zip
(env userInfos me2.some) zip
env.api.vote.value(id, me2) flatMap {
case ((p2, infos), voted) => renderJson(
p2 | puzzle, infos, "view", voted = voted, round = newAttempt.some
) map { Ok(_) }
}
}
case (oldAttempt, Some(win)) => env.userInfos(me.some) zip
ctx.me.?? { env.api.vote.value(puzzle.id, _) } flatMap {
case (infos, voted) => renderJson(puzzle, infos, "view",
round = oldAttempt.some,
result = result.some,
voted = voted) map { Ok(_) }
}
}
case (oldAttempt, Some(win)) => env.userInfos(me.some) zip
ctx.me.?? { env.api.vote.value(puzzle.id, _) } flatMap {
case (infos, voted) => renderJson(puzzle, infos, "view",
round = oldAttempt.some,
win = win.some,
voted = voted) map { Ok(_) }
}
}
case None =>
lila.mon.puzzle.round.anon()
env.finisher.incPuzzleAttempts(puzzle)
renderJson(puzzle, none, "view", win = data.isWin.some, voted = none) map { Ok(_) }
case None =>
lila.mon.puzzle.round.anon()
env.finisher.incPuzzleAttempts(puzzle)
renderJson(puzzle, none, "view", result = result.some, voted = none) map { Ok(_) }
}
}
) map (_ as JSON)
}
}
// def round2(id: PuzzleId) = OpenBody { implicit ctx =>
// implicit val req = ctx.body
// OptionFuResult(env.api.puzzle find id) { puzzle =>
// if (puzzle.mate) lila.mon.puzzle.round.mate()
// else lila.mon.puzzle.round.material()
// env.forms.round.bindFromRequest.fold(
// err => fuccess(BadRequest(errorsAsJson(err))),
// data => ctx.me match {
// case Some(me) =>
// lila.mon.puzzle.round.user()
// env.finisher(puzzle, me, data) flatMap {
// case (newAttempt, None) => UserRepo byId me.id map (_ | me) flatMap { me2 =>
// env.api.puzzle find id zip
// (env userInfos me2.some) zip
// env.api.vote.value(id, me2) flatMap {
// case ((p2, infos), voted) => renderJson(
// p2 | puzzle, infos, "view", voted = voted, round = newAttempt.some
// ) map { Ok(_) }
// }
// }
// case (oldAttempt, Some(win)) => env.userInfos(me.some) zip
// ctx.me.?? { env.api.vote.value(puzzle.id, _) } flatMap {
// case (infos, voted) => renderJson(puzzle, infos, "view",
// round = oldAttempt.some,
// win = win.some,
// voted = voted) map { Ok(_) }
// }
// }
// case None =>
// lila.mon.puzzle.round.anon()
// env.finisher.incPuzzleAttempts(puzzle)
// renderJson(puzzle, none, "view", win = data.isWin.some, voted = none) map { Ok(_) }
// }
// ) map (_ as JSON)
// }
// }
def vote(id: PuzzleId) = AuthBody { implicit ctx => me =>
implicit val req = ctx.body
env.forms.vote.bindFromRequest.fold(

View file

@ -5,18 +5,9 @@ import play.api.data.Forms._
object DataForm {
val difficulty = Form(single(
"difficulty" -> number(min = 1, max = 3)
))
val round = Form(mapping(
val round = Form(single(
"win" -> number
)(RoundData.apply)(RoundData.unapply))
case class RoundData(win: Int) extends AnyVal {
def isWin = win == 1
}
))
val vote = Form(single(
"vote" -> number

View file

@ -13,15 +13,15 @@ private[puzzle] final class Finisher(
private val maxTime = 5 * 60 * 1000
def apply(puzzle: Puzzle, user: User, data: DataForm.RoundData): Fu[(Round, Option[Boolean])] =
def apply(puzzle: Puzzle, user: User, result: Result): Fu[(Round, Option[Result])] =
api.head.find(user) flatMap {
case Some(PuzzleHead(_, Some(c), _)) if c == puzzle.id =>
api.head.solved(user, puzzle.id) >>
api.learning.update(user, puzzle, data).flatMap { isLearning =>
api.learning.update(user, puzzle, result).flatMap { isLearning =>
val userRating = user.perfs.puzzle.toRating
val puzzleRating = puzzle.perf.toRating
updateRatings(userRating, puzzleRating,
result = data.isWin.fold(Glicko.Result.Win, Glicko.Result.Loss),
result = result.win.fold(Glicko.Result.Win, Glicko.Result.Loss),
isLearning = isLearning)
val date = DateTime.now
val puzzlePerf = puzzle.perf.addOrReset(_.puzzle.crazyGlicko, s"puzzle ${puzzle.id} user")(puzzleRating, date)
@ -30,7 +30,7 @@ private[puzzle] final class Finisher(
puzzleId = puzzle.id,
userId = user.id,
date = DateTime.now,
win = data.isWin,
result = result,
rating = user.perfs.puzzle.intRating,
ratingDiff = userPerf.intRating - user.perfs.puzzle.intRating)
(api.round add a) >> {
@ -47,10 +47,10 @@ private[puzzle] final class Finisher(
puzzleId = puzzle.id,
userId = user.id,
date = DateTime.now,
win = data.isWin,
result = result,
rating = user.perfs.puzzle.intRating,
ratingDiff = 0)
fuccess(a -> data.isWin.some)
fuccess(a -> result.some)
}
private val VOLATILITY = Glicko.default.volatility

View file

@ -17,7 +17,7 @@ object JsonView {
pref: lila.pref.Pref,
isMobileApi: Boolean,
round: Option[Round] = None,
win: Option[Boolean] = None,
result: Option[Result] = None,
voted: Option[Boolean]): Fu[JsObject] =
(!isMobileApi ?? GameJson(puzzle.gameId, puzzle.initialPly).map(_.some)) map { gameJson =>
Json.obj(
@ -62,17 +62,17 @@ object JsonView {
"round" -> round.map { a =>
Json.obj(
"ratingDiff" -> a.ratingDiff,
"win" -> a.win
"win" -> a.result.win
)
},
"attempt" -> round.ifTrue(isMobileApi).map { r =>
Json.obj(
"userRatingDiff" -> r.ratingDiff,
"win" -> r.win,
"win" -> r.result.win,
"seconds" -> "a few" // lol we don't have the value anymore
)
},
"win" -> win,
"win" -> result.ifTrue(isMobileApi).map(_.win),
"voted" -> voted,
"user" -> userInfos.map { i =>
Json.obj(

View file

@ -83,8 +83,8 @@ private[puzzle] final class PuzzleApi(
def add(l: Learning) = learningColl insert l void
def update(user: User, puzzle: Puzzle, data: DataForm.RoundData): Fu[Boolean] =
if (data.isWin) solved(user, puzzle.id)
def update(user: User, puzzle: Puzzle, result: Result): Fu[Boolean] =
if (result.win) solved(user, puzzle.id)
else failed(user, puzzle.id)
def solved(user: User, puzzleId: PuzzleId): Fu[Boolean] = learning find user flatMap {

View file

@ -8,12 +8,10 @@ case class Round(
puzzleId: PuzzleId,
userId: User.ID,
date: DateTime,
win: Boolean,
result: Result,
rating: Int,
ratingDiff: Int) {
def loss = !win
def userPostRating = rating + ratingDiff
}
@ -25,7 +23,7 @@ object Round {
val puzzleId = "p"
val userId = "u"
val date = "a"
val win = "w"
val result = "w"
val rating = "r"
val ratingDiff = "d"
}
@ -34,6 +32,9 @@ object Round {
import lila.db.BSON
import lila.db.dsl._
import BSON.BSONJodaDateTimeHandler
private implicit val ResultBSONHandler = booleanAnyValHandler[Result](_.win, Result.apply)
implicit val RoundBSONHandler = new BSON[Round] {
import BSONFields._
@ -42,7 +43,7 @@ object Round {
puzzleId = r int puzzleId,
userId = r str userId,
date = r.get[DateTime](date),
win = r bool win,
result = r.get[Result](result),
rating = r int rating,
ratingDiff = r int ratingDiff)
@ -50,7 +51,7 @@ object Round {
puzzleId -> o.puzzleId,
userId -> o.userId,
date -> o.date,
win -> o.win,
result -> o.result,
rating -> w.int(o.rating),
ratingDiff -> w.int(o.ratingDiff))
}

View file

@ -7,4 +7,9 @@ package object puzzle extends PackageObject with WithPlay {
type Lines = List[Line]
private[puzzle] def logger = lila.log("puzzle")
case class Result(win: Boolean) extends AnyVal {
def loss = !win
}
}