convert new puzzle IDs to/from numerical IDs for mobile app BC
parent
abd05773f8
commit
e1954ca63a
|
@ -61,16 +61,6 @@ final class Puzzle(
|
|||
}
|
||||
}
|
||||
|
||||
def load(id: String) =
|
||||
Open { implicit ctx =>
|
||||
NoBot {
|
||||
XhrOnly {
|
||||
???
|
||||
// OptionFuOk(env.puzzle.api.puzzle find Puz.Id(id))(puzzleJson _).dmap(_ as JSON)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private def nextPuzzleForMe(theme: PuzzleTheme.Key)(implicit ctx: Context): Fu[Puz] =
|
||||
ctx.me match {
|
||||
case Some(me) => env.puzzle.session.nextPuzzleFor(me, theme)
|
||||
|
@ -173,6 +163,17 @@ final class Puzzle(
|
|||
}
|
||||
}
|
||||
|
||||
def mobileBcLoad(nid: Long) =
|
||||
Open { implicit ctx =>
|
||||
negotiate(
|
||||
html = notFound,
|
||||
_ =>
|
||||
OptionFuOk(env.puzzle.api.puzzle find Puz.numericalId(nid)) { puz =>
|
||||
env.puzzle.jsonView.bc(puzzle = puz, theme = PuzzleTheme.any, user = ctx.me)
|
||||
}.dmap(_ as JSON)
|
||||
)
|
||||
}
|
||||
|
||||
/* Mobile API: select a bunch of puzzles for offline use */
|
||||
def batchSelect =
|
||||
Auth { implicit ctx => me =>
|
||||
|
|
|
@ -81,15 +81,16 @@ GET /training controllers.Puzzle.home
|
|||
GET /training/daily controllers.Puzzle.daily
|
||||
GET /training/frame controllers.Puzzle.frame
|
||||
GET /training/export/gif/thumbnail/:id.gif controllers.Export.puzzleThumbnail(id: String)
|
||||
GET /training/batch controllers.Puzzle.batchSelect
|
||||
POST /training/batch controllers.Puzzle.batchSolve
|
||||
GET /training/themes controllers.Puzzle.themes
|
||||
GET /training/:id/load controllers.Puzzle.mobileBcLoad(id: Long)
|
||||
GET /training/:themeOrId controllers.Puzzle.show(themeOrId: String)
|
||||
GET /training/:theme/$id<\w{5}> controllers.Puzzle.showWithTheme(theme: String, id: String)
|
||||
POST /training/$id<\w{5}>/vote controllers.Puzzle.vote(id: String)
|
||||
POST /training/$id<\w{5}>/vote/:theme controllers.Puzzle.voteTheme(id: String, theme: String)
|
||||
POST /training/complete/:theme/$id<\w{5}> controllers.Puzzle.complete(theme: String, id: String)
|
||||
POST /training/difficulty/:theme controllers.Puzzle.setDifficulty(theme: String)
|
||||
GET /training/batch controllers.Puzzle.batchSelect
|
||||
POST /training/batch controllers.Puzzle.batchSolve
|
||||
|
||||
# User Analysis
|
||||
GET /analysis/help controllers.UserAnalysis.help
|
||||
|
|
|
@ -101,7 +101,7 @@ final class JsonView(
|
|||
.obj(
|
||||
"game" -> gameJson,
|
||||
"puzzle" -> Json.obj(
|
||||
"id" -> puzzle.id,
|
||||
"id" -> Puzzle.numericalId(puzzle.id),
|
||||
"rating" -> puzzle.glicko.intRating,
|
||||
"attempts" -> puzzle.plays,
|
||||
"fen" -> puzzle.fenAfterInitialMove,
|
||||
|
|
|
@ -32,8 +32,47 @@ case class Puzzle(
|
|||
|
||||
object Puzzle {
|
||||
|
||||
val idSize = 5
|
||||
|
||||
case class Id(value: String) extends AnyVal with StringValue
|
||||
|
||||
/* The mobile app requires numerical IDs.
|
||||
* We convert string ids from and to Longs using base 62
|
||||
*/
|
||||
object numericalId {
|
||||
|
||||
private val powers: List[Long] =
|
||||
(0 until idSize).toList.map(m => Math.pow(62, m).toLong)
|
||||
|
||||
def apply(id: Id): Long = id.value.toList
|
||||
.zip(powers)
|
||||
.foldLeft(0L) { case (l, (char, pow)) =>
|
||||
l + charToInt(char) * pow
|
||||
}
|
||||
|
||||
def apply(l: Long): Id = Id {
|
||||
powers.reverse
|
||||
.foldLeft(("", l)) { case ((id, rest), pow) =>
|
||||
val frac = rest / pow
|
||||
(s"${intToChar(frac.toInt)}$id", rest - frac * pow)
|
||||
}
|
||||
._1
|
||||
}
|
||||
|
||||
private def charToInt(c: Char) = {
|
||||
val i = c.toInt
|
||||
if (i > 96) i - 71
|
||||
else if (i > 64) i - 65
|
||||
else i + 4
|
||||
}
|
||||
|
||||
private def intToChar(i: Int): Char = {
|
||||
if (i < 26) i + 65
|
||||
else if (i < 52) i + 71
|
||||
else i - 4
|
||||
}.toChar
|
||||
}
|
||||
|
||||
case class UserResult(
|
||||
puzzleId: Id,
|
||||
userId: lila.user.User.ID,
|
||||
|
|
Loading…
Reference in New Issue