make storm puzzle reviews unrated - closes #8008

This commit is contained in:
Thibault Duplessis 2021-01-27 21:55:37 +01:00
parent 25b4674c14
commit 2dfda8d5c2
4 changed files with 108 additions and 78 deletions

View file

@ -33,13 +33,20 @@ final class Puzzle(
else
env.puzzle.jsonView(puzzle = puzzle, theme = theme, replay = replay, user = newUser orElse ctx.me)
private def renderShow(puzzle: Puz, theme: PuzzleTheme, replay: Option[PuzzleReplay] = None)(implicit
private def renderShow(
puzzle: Puz,
theme: PuzzleTheme,
replay: Option[PuzzleReplay] = None
)(implicit
ctx: Context
) =
renderJson(puzzle, theme, replay) zip
ctx.me.??(u => env.puzzle.session.getDifficulty(u) dmap some) map { case (json, difficulty) =>
EnableSharedArrayBuffer(
Ok(views.html.puzzle.show(puzzle, json, env.puzzle.jsonView.pref(ctx.pref), difficulty))
Ok(
views.html.puzzle
.show(puzzle, json, env.puzzle.jsonView.pref(ctx.pref), difficulty)
)
)
}
@ -216,8 +223,11 @@ final class Puzzle(
nextPuzzleForMe(theme.key) flatMap {
renderShow(_, theme)
}
case None if themeOrId.size == 5 =>
OptionFuResult(env.puzzle.api.puzzle find Puz.Id(themeOrId)) { renderShow(_, PuzzleTheme.mix) }
case None if themeOrId.size == Puz.idSize =>
OptionFuResult(env.puzzle.api.puzzle find Puz.Id(themeOrId)) { puz =>
ctx.me.ifTrue(getBool("casual")) foreach { env.puzzle.api.casual.set(_, puz.id) }
renderShow(puz, PuzzleTheme.mix)
}
case None =>
themeOrId.toLongOption
.flatMap(Puz.numericalId.apply)

View file

@ -146,4 +146,15 @@ final class PuzzleApi(
}
}
}
object casual {
private val store = new lila.memo.ExpireSetMemo(30 minutes)
private def key(user: User, id: Puzzle.Id) = s"${user.id}:${id}"
def set(user: User, id: Puzzle.Id) = store.put(key(user, id))
def apply(user: User, id: Puzzle.Id) = store.get(key(user, id))
}
}

View file

@ -36,87 +36,96 @@ final private[puzzle] class PuzzleFinisher(
user: User,
result: Result
): Fu[Option[(PuzzleRound, Perf)]] =
sequencer(id.value) {
api.round.find(user, id) flatMap { prevRound =>
api.puzzle.find(id) flatMap {
_ ?? { puzzle =>
val now = DateTime.now
val formerUserRating = user.perfs.puzzle.intRating
if (api.casual(user, id)) fuccess {
PuzzleRound(
id = PuzzleRound.Id(user.id, id),
win = result.win,
fixedAt = none,
date = DateTime.now
) -> user.perfs.puzzle
} dmap some
else
sequencer(id.value) {
api.round.find(user, id) flatMap { prevRound =>
api.puzzle.find(id) flatMap {
_ ?? { puzzle =>
val now = DateTime.now
val formerUserRating = user.perfs.puzzle.intRating
val (round, newPuzzleGlicko, userPerf) = prevRound match {
case Some(prev) =>
(
prev.updateWithWin(result.win),
none,
user.perfs.puzzle
)
case None =>
val userRating = user.perfs.puzzle.toRating
val puzzleRating = new Rating(
puzzle.glicko.rating atLeast Glicko.minRating,
puzzle.glicko.deviation,
puzzle.glicko.volatility,
puzzle.plays,
null
)
updateRatings(userRating, puzzleRating, result.glicko)
val newPuzzleGlicko = ponder
.puzzle(
theme,
result,
puzzle.glicko -> Glicko(
rating = puzzleRating.getRating
.atMost(puzzle.glicko.rating + Glicko.maxRatingDelta)
.atLeast(puzzle.glicko.rating - Glicko.maxRatingDelta),
deviation = puzzleRating.getRatingDeviation,
volatility = puzzleRating.getVolatility
).cap,
player = user.perfs.puzzle.glicko
val (round, newPuzzleGlicko, userPerf) = prevRound match {
case Some(prev) =>
(
prev.updateWithWin(result.win),
none,
user.perfs.puzzle
)
.some
.filter(puzzle.glicko !=)
.filter(_.sanityCheck)
val round =
PuzzleRound(
id = PuzzleRound.Id(user.id, puzzle.id),
win = result.win,
fixedAt = none,
date = DateTime.now
case None =>
val userRating = user.perfs.puzzle.toRating
val puzzleRating = new Rating(
puzzle.glicko.rating atLeast Glicko.minRating,
puzzle.glicko.deviation,
puzzle.glicko.volatility,
puzzle.plays,
null
)
val userPerf =
user.perfs.puzzle
.addOrReset(_.puzzle.crazyGlicko, s"puzzle ${puzzle.id}")(userRating, now) pipe { p =>
p.copy(glicko =
ponder.player(theme, result, user.perfs.puzzle.glicko -> p.glicko, puzzle.glicko)
updateRatings(userRating, puzzleRating, result.glicko)
val newPuzzleGlicko = ponder
.puzzle(
theme,
result,
puzzle.glicko -> Glicko(
rating = puzzleRating.getRating
.atMost(puzzle.glicko.rating + Glicko.maxRatingDelta)
.atLeast(puzzle.glicko.rating - Glicko.maxRatingDelta),
deviation = puzzleRating.getRatingDeviation,
volatility = puzzleRating.getVolatility
).cap,
player = user.perfs.puzzle.glicko
)
}
(round, newPuzzleGlicko, userPerf)
}
api.round.upsert(round, theme) zip
colls.puzzle {
_.update
.one(
$id(puzzle.id),
$inc(Puzzle.BSONFields.plays -> $int(1)) ++ newPuzzleGlicko.?? { glicko =>
$set(Puzzle.BSONFields.glicko -> Glicko.glickoBSONHandler.write(glicko))
.some
.filter(puzzle.glicko !=)
.filter(_.sanityCheck)
val round =
PuzzleRound(
id = PuzzleRound.Id(user.id, puzzle.id),
win = result.win,
fixedAt = none,
date = DateTime.now
)
val userPerf =
user.perfs.puzzle
.addOrReset(_.puzzle.crazyGlicko, s"puzzle ${puzzle.id}")(userRating, now) pipe { p =>
p.copy(glicko =
ponder.player(theme, result, user.perfs.puzzle.glicko -> p.glicko, puzzle.glicko)
)
}
)
.void
} zip
(userPerf != user.perfs.puzzle).?? {
userRepo.setPerf(user.id, PerfType.Puzzle, userPerf.clearRecent) zip
historyApi.addPuzzle(user = user, completedAt = now, perf = userPerf) void
} >>- {
if (prevRound.isEmpty)
Bus.publish(
Puzzle.UserResult(puzzle.id, user.id, result, formerUserRating -> userPerf.intRating),
"finishPuzzle"
)
} inject (round -> userPerf).some
(round, newPuzzleGlicko, userPerf)
}
api.round.upsert(round, theme) zip
colls.puzzle {
_.update
.one(
$id(puzzle.id),
$inc(Puzzle.BSONFields.plays -> $int(1)) ++ newPuzzleGlicko.?? { glicko =>
$set(Puzzle.BSONFields.glicko -> Glicko.glickoBSONHandler.write(glicko))
}
)
.void
} zip
(userPerf != user.perfs.puzzle).?? {
userRepo.setPerf(user.id, PerfType.Puzzle, userPerf.clearRecent) zip
historyApi.addPuzzle(user = user, completedAt = now, perf = userPerf) void
} >>- {
if (prevRound.isEmpty)
Bus.publish(
Puzzle.UserResult(puzzle.id, user.id, result, formerUserRating -> userPerf.intRating),
"finishPuzzle"
)
} inject (round -> userPerf).some
}
}
}
}
}
private object ponder {

View file

@ -84,7 +84,7 @@ const renderHistory = (ctrl: StormCtrl): VNode =>
h('div.storm--end__history__round', [
h('a.storm--end__history__round__puzzle.mini-board.cg-wrap.is2d', {
attrs: {
href: `/training/${round.puzzle.id}`,
href: `/training/${round.puzzle.id}?casual=1`,
target: '_blank'
},
hook: onInsert(e => {