lila/modules/puzzle/src/main/PuzzlePath.scala

73 lines
2.3 KiB
Scala

package lila.puzzle
import scala.concurrent.duration._
import scala.concurrent.ExecutionContext
import lila.db.dsl._
import lila.memo.CacheApi
import lila.user.User
private object PuzzlePath {
case class Id(value: String) {
val parts = value split '_'
private[puzzle] def tier = PuzzleTier.from(~parts.lift(1))
def theme = PuzzleTheme.findOrAny(~parts.headOption).key
}
implicit val pathIdIso = lila.common.Iso.string[Id](Id.apply, _.value)
}
final private class PuzzlePathApi(
colls: PuzzleColls
)(implicit ec: ExecutionContext) {
import BsonHandlers._
def nextFor(
user: User,
theme: PuzzleTheme.Key,
tier: PuzzleTier,
difficulty: PuzzleDifficulty,
previousPaths: Set[PuzzlePath.Id],
compromise: Int = 0
): Fu[Option[PuzzlePath.Id]] = {
val actualTier =
if (tier == PuzzleTier.Top && PuzzleDifficulty.isExtreme(difficulty)) PuzzleTier.Good
else tier
colls
.path {
_.aggregateOne() { framework =>
import framework._
val rating = user.perfs.puzzle.glicko.intRating + difficulty.ratingDelta
val ratingFlex = (100 + math.abs(1500 - rating) / 4) * compromise.atMost(4)
Match(
select(theme, actualTier, (rating - ratingFlex) to (rating + ratingFlex)) ++
((compromise != 5 && previousPaths.nonEmpty) ?? $doc("_id" $nin previousPaths))
) -> List(
Sample(1),
Project($id(true))
)
}.dmap(_.flatMap(_.getAsOpt[PuzzlePath.Id]("_id")))
}
.flatMap {
case Some(path) => fuccess(path.some)
case _ if actualTier == PuzzleTier.Top =>
nextFor(user, theme, PuzzleTier.Good, difficulty, previousPaths)
case _ if actualTier == PuzzleTier.Good && compromise == 2 =>
nextFor(user, theme, PuzzleTier.All, difficulty, previousPaths, compromise = 1)
case _ if compromise < 5 =>
nextFor(user, theme, actualTier, difficulty, previousPaths, compromise + 1)
case _ => fuccess(none)
}
}.mon(_.puzzle.path.nextFor(theme.value, tier.key, difficulty.key, previousPaths.size, compromise))
def select(theme: PuzzleTheme.Key, tier: PuzzleTier, rating: Range) = $doc(
"min" $lte f"${theme}_${tier}_${rating.max}%04d",
"max" $gte f"${theme}_${tier}_${rating.min}%04d"
)
}