more puzzle ui v2 wip
This commit is contained in:
parent
05ede51670
commit
2b94cf9da7
|
@ -27,18 +27,15 @@ object Puzzle extends LilaController {
|
|||
voted: Option[Boolean],
|
||||
round: Option[lila.puzzle.Round] = None,
|
||||
win: Option[Boolean] = None)(implicit ctx: Context): Fu[JsObject] =
|
||||
(GameRepo game puzzle.gameId).flatten(s"Missing puzzle ${puzzle.id} game!") map { game =>
|
||||
lila.puzzle.JsonView(
|
||||
puzzle = puzzle,
|
||||
game = game,
|
||||
userInfos = userInfos,
|
||||
mode = mode,
|
||||
animationDuration = env.AnimationDuration,
|
||||
pref = ctx.pref,
|
||||
isMobileApi = ctx.isMobileApi,
|
||||
win = win,
|
||||
voted = voted)
|
||||
}
|
||||
lila.puzzle.JsonView(
|
||||
puzzle = puzzle,
|
||||
userInfos = userInfos,
|
||||
mode = mode,
|
||||
animationDuration = env.AnimationDuration,
|
||||
pref = ctx.pref,
|
||||
isMobileApi = ctx.isMobileApi,
|
||||
win = win,
|
||||
voted = voted)
|
||||
|
||||
private def renderShow(puzzle: PuzzleModel, mode: String)(implicit ctx: Context) =
|
||||
env userInfos ctx.me flatMap { infos =>
|
||||
|
|
|
@ -11,6 +11,7 @@ import lila.round.{ JsonView, Forecast }
|
|||
import lila.security.Granter
|
||||
import lila.simul.Simul
|
||||
import lila.tournament.{ Tournament, SecondsToDoFirstMove, TourAndRanks }
|
||||
import lila.tree.Node.partitionTreeJsonWriter
|
||||
import lila.user.User
|
||||
|
||||
private[api] final class RoundApi(
|
||||
|
@ -107,7 +108,6 @@ private[api] final class RoundApi(
|
|||
jsonView.userAnalysisJson(pov, pref, orientation, owner = false) map
|
||||
withTree(pov, analysis = none, initialFen, withOpening = true)_
|
||||
|
||||
import lila.tree.Node.partitionTreeJsonWriter
|
||||
private def withTree(pov: Pov, analysis: Option[Analysis], initialFen: Option[String], withOpening: Boolean)(obj: JsObject) =
|
||||
obj + ("treeParts" -> partitionTreeJsonWriter.writes(lila.round.TreeBuilder(
|
||||
id = pov.game.id,
|
||||
|
|
|
@ -12,6 +12,7 @@ final class UserGameApi(
|
|||
bookmarkApi: lila.bookmark.BookmarkApi,
|
||||
lightUser: LightUser.Getter) {
|
||||
|
||||
import lila.game.JsonView._
|
||||
import lila.round.JsonView._
|
||||
import LightUser.lightUserWrites
|
||||
|
||||
|
|
|
@ -6,6 +6,12 @@ import chess.variant.Crazyhouse
|
|||
|
||||
object JsonView {
|
||||
|
||||
implicit val statusWriter: OWrites[chess.Status] = OWrites { s =>
|
||||
Json.obj(
|
||||
"id" -> s.id,
|
||||
"name" -> s.name)
|
||||
}
|
||||
|
||||
implicit val crosstableResultWrites = Json.writes[Crosstable.Result]
|
||||
|
||||
implicit val crosstableWrites = OWrites[Crosstable] { c =>
|
||||
|
|
35
modules/puzzle/src/main/GameJson.scala
Normal file
35
modules/puzzle/src/main/GameJson.scala
Normal file
|
@ -0,0 +1,35 @@
|
|||
package lila.puzzle
|
||||
|
||||
import play.api.libs.json._
|
||||
import scala.concurrent.duration._
|
||||
|
||||
import lila.common.PimpedJson._
|
||||
import lila.game.{ Game, GameRepo, PerfPicker }
|
||||
import lila.tree.Node.partitionTreeJsonWriter
|
||||
|
||||
object GameJson {
|
||||
|
||||
import lila.game.JsonView._
|
||||
|
||||
private val cache = lila.memo.AsyncCache[Game.ID, JsObject](
|
||||
f = generate,
|
||||
maxCapacity = 500)
|
||||
|
||||
def apply(gameId: Game.ID): Fu[JsObject] = cache(gameId)
|
||||
|
||||
def generate(gameId: Game.ID): Fu[JsObject] =
|
||||
(GameRepo game gameId).flatten(s"Missing puzzle game $gameId!") map { game =>
|
||||
Json.obj(
|
||||
"id" -> game.id,
|
||||
"speed" -> game.speed.key,
|
||||
"perf" -> PerfPicker.key(game),
|
||||
"rated" -> game.rated,
|
||||
"winner" -> game.winnerColor.map(_.name),
|
||||
"turns" -> game.turns,
|
||||
"status" -> game.status,
|
||||
"tournamentId" -> game.tournamentId,
|
||||
"createdAt" -> game.createdAt,
|
||||
"treeParts" -> partitionTreeJsonWriter.writes(TreeBuilder(game))
|
||||
).noNull
|
||||
}
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
package lila.puzzle
|
||||
|
||||
import play.api.libs.json.{ JsArray, Json }
|
||||
import play.api.libs.json._
|
||||
|
||||
import lila.common.PimpedJson._
|
||||
import lila.game.Game
|
||||
|
@ -10,7 +10,6 @@ object JsonView {
|
|||
|
||||
def apply(
|
||||
puzzle: Puzzle,
|
||||
game: Game,
|
||||
userInfos: Option[UserInfos],
|
||||
mode: String,
|
||||
animationDuration: scala.concurrent.duration.Duration,
|
||||
|
@ -18,65 +17,69 @@ object JsonView {
|
|||
isMobileApi: Boolean,
|
||||
round: Option[Round] = None,
|
||||
win: Option[Boolean] = None,
|
||||
voted: Option[Boolean]) = Json.obj(
|
||||
"puzzle" -> Json.obj(
|
||||
"id" -> puzzle.id,
|
||||
"rating" -> puzzle.perf.intRating,
|
||||
"attempts" -> puzzle.attempts,
|
||||
"fen" -> puzzle.fen,
|
||||
"color" -> puzzle.color.name,
|
||||
"initialMove" -> puzzle.initialMove,
|
||||
"initialPly" -> puzzle.initialPly,
|
||||
"gameId" -> puzzle.gameId,
|
||||
"lines" -> lila.puzzle.Line.toJson(puzzle.lines),
|
||||
"enabled" -> puzzle.enabled,
|
||||
"vote" -> puzzle.vote.sum
|
||||
),
|
||||
"pref" -> Json.obj(
|
||||
"coords" -> pref.coords
|
||||
),
|
||||
"chessground" -> Json.obj(
|
||||
"highlight" -> Json.obj(
|
||||
"lastMove" -> pref.highlight,
|
||||
"check" -> pref.highlight
|
||||
),
|
||||
"movable" -> Json.obj(
|
||||
"showDests" -> pref.destination
|
||||
),
|
||||
"draggable" -> Json.obj(
|
||||
"showGhost" -> pref.highlight
|
||||
),
|
||||
"premovable" -> Json.obj(
|
||||
"showDests" -> pref.destination
|
||||
)
|
||||
),
|
||||
"animation" -> Json.obj(
|
||||
"duration" -> pref.animationFactor * animationDuration.toMillis
|
||||
),
|
||||
"mode" -> mode,
|
||||
"round" -> round.map { a =>
|
||||
voted: Option[Boolean]): Fu[JsObject] =
|
||||
(!isMobileApi ?? GameJson(puzzle.gameId).map(_.some)) map { gameJson =>
|
||||
Json.obj(
|
||||
"ratingDiff" -> a.ratingDiff,
|
||||
"win" -> a.win
|
||||
)
|
||||
},
|
||||
"win" -> win,
|
||||
"voted" -> voted,
|
||||
"user" -> userInfos.map { i =>
|
||||
Json.obj(
|
||||
"rating" -> i.user.perfs.puzzle.intRating,
|
||||
"history" -> isMobileApi.option(i.history.map(_.rating)), // for mobile BC
|
||||
"recent" -> i.history.map { r =>
|
||||
Json.arr(r.puzzleId, r.ratingDiff, r.rating)
|
||||
}
|
||||
).noNull
|
||||
},
|
||||
"difficulty" -> isMobileApi.option {
|
||||
Json.obj(
|
||||
"choices" -> Json.arr(
|
||||
Json.arr(2, "Normal")
|
||||
"game" -> gameJson,
|
||||
"puzzle" -> Json.obj(
|
||||
"id" -> puzzle.id,
|
||||
"rating" -> puzzle.perf.intRating,
|
||||
"attempts" -> puzzle.attempts,
|
||||
"fen" -> puzzle.fen,
|
||||
"color" -> puzzle.color.name,
|
||||
"initialMove" -> puzzle.initialMove,
|
||||
"initialPly" -> puzzle.initialPly,
|
||||
"gameId" -> puzzle.gameId,
|
||||
"lines" -> lila.puzzle.Line.toJson(puzzle.lines),
|
||||
"enabled" -> puzzle.enabled,
|
||||
"vote" -> puzzle.vote.sum
|
||||
),
|
||||
"current" -> 2
|
||||
)
|
||||
}).noNull
|
||||
"pref" -> Json.obj(
|
||||
"coords" -> pref.coords
|
||||
),
|
||||
"chessground" -> Json.obj(
|
||||
"highlight" -> Json.obj(
|
||||
"lastMove" -> pref.highlight,
|
||||
"check" -> pref.highlight
|
||||
),
|
||||
"movable" -> Json.obj(
|
||||
"showDests" -> pref.destination
|
||||
),
|
||||
"draggable" -> Json.obj(
|
||||
"showGhost" -> pref.highlight
|
||||
),
|
||||
"premovable" -> Json.obj(
|
||||
"showDests" -> pref.destination
|
||||
)
|
||||
),
|
||||
"animation" -> Json.obj(
|
||||
"duration" -> pref.animationFactor * animationDuration.toMillis
|
||||
),
|
||||
"mode" -> mode,
|
||||
"round" -> round.map { a =>
|
||||
Json.obj(
|
||||
"ratingDiff" -> a.ratingDiff,
|
||||
"win" -> a.win
|
||||
)
|
||||
},
|
||||
"win" -> win,
|
||||
"voted" -> voted,
|
||||
"user" -> userInfos.map { i =>
|
||||
Json.obj(
|
||||
"rating" -> i.user.perfs.puzzle.intRating,
|
||||
"history" -> isMobileApi.option(i.history.map(_.rating)), // for mobile BC
|
||||
"recent" -> i.history.map { r =>
|
||||
Json.arr(r.puzzleId, r.ratingDiff, r.rating)
|
||||
}
|
||||
).noNull
|
||||
},
|
||||
"difficulty" -> isMobileApi.option {
|
||||
Json.obj(
|
||||
"choices" -> Json.arr(
|
||||
Json.arr(2, "Normal")
|
||||
),
|
||||
"current" -> 2
|
||||
)
|
||||
}).noNull
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,17 +2,17 @@ package lila.puzzle
|
|||
|
||||
import chess.format.{ Forsyth, Uci, UciCharPair }
|
||||
import chess.opening.FullOpeningDB
|
||||
import chess.variant.Standard
|
||||
import lila.game.Game
|
||||
import lila.tree
|
||||
|
||||
object TreeBuilder {
|
||||
|
||||
private type Ply = Int
|
||||
|
||||
def apply(id: String, pgnMoves: List[String]): tree.Root = {
|
||||
chess.Replay.gameMoveWhileValid(pgnMoves, Forsyth.initial, Standard) match {
|
||||
def apply(game: Game): tree.Root = {
|
||||
chess.Replay.gameMoveWhileValid(game.pgnMoves, Forsyth.initial, game.variant) match {
|
||||
case (init, games, error) =>
|
||||
error foreach logChessError(id)
|
||||
error foreach logChessError(game.id)
|
||||
val fen = Forsyth >> init
|
||||
val root = tree.Root(
|
||||
ply = init.turns,
|
||||
|
|
|
@ -321,12 +321,6 @@ object JsonView {
|
|||
"short" -> v.shortName)
|
||||
}
|
||||
|
||||
implicit val statusWriter: OWrites[chess.Status] = OWrites { s =>
|
||||
Json.obj(
|
||||
"id" -> s.id,
|
||||
"name" -> s.name)
|
||||
}
|
||||
|
||||
implicit val clockWriter: OWrites[Clock] = OWrites { c =>
|
||||
import lila.common.Maths.truncateAt
|
||||
Json.obj(
|
||||
|
|
54
ui/puzzle-old/gulpfile.js
Normal file
54
ui/puzzle-old/gulpfile.js
Normal file
|
@ -0,0 +1,54 @@
|
|||
var source = require('vinyl-source-stream');
|
||||
var gulp = require('gulp');
|
||||
var gutil = require('gulp-util');
|
||||
var watchify = require('watchify');
|
||||
var browserify = require('browserify');
|
||||
var uglify = require('gulp-uglify');
|
||||
var streamify = require('gulp-streamify');
|
||||
|
||||
var sources = ['./src/main.js'];
|
||||
var destination = '../../public/compiled/';
|
||||
var onError = function(error) {
|
||||
gutil.log(gutil.colors.red(error.message));
|
||||
};
|
||||
var standalone = 'LichessPuzzle';
|
||||
|
||||
gulp.task('prod', function() {
|
||||
return browserify('./src/main.js', {
|
||||
standalone: standalone
|
||||
}).bundle()
|
||||
.on('error', onError)
|
||||
.pipe(source('lichess.puzzle.min.js'))
|
||||
.pipe(streamify(uglify()))
|
||||
.pipe(gulp.dest(destination));
|
||||
});
|
||||
|
||||
gulp.task('dev', function() {
|
||||
return browserify('./src/main.js', {
|
||||
standalone: standalone
|
||||
}).bundle()
|
||||
.on('error', onError)
|
||||
.pipe(source('lichess.puzzle.js'))
|
||||
.pipe(gulp.dest(destination));
|
||||
});
|
||||
|
||||
gulp.task('watch', function() {
|
||||
var opts = watchify.args;
|
||||
opts.debug = true;
|
||||
opts.standalone = standalone;
|
||||
|
||||
var bundleStream = watchify(browserify(sources, opts))
|
||||
.on('update', rebundle)
|
||||
.on('log', gutil.log);
|
||||
|
||||
function rebundle() {
|
||||
return bundleStream.bundle()
|
||||
.on('error', onError)
|
||||
.pipe(source('lichess.puzzle.js'))
|
||||
.pipe(gulp.dest(destination));
|
||||
}
|
||||
|
||||
return rebundle();
|
||||
});
|
||||
|
||||
gulp.task('default', ['watch']);
|
38
ui/puzzle-old/package.json
Normal file
38
ui/puzzle-old/package.json
Normal file
|
@ -0,0 +1,38 @@
|
|||
{
|
||||
"name": "puzzle",
|
||||
"version": "1.0.0",
|
||||
"description": "lichess.org puzzle solver",
|
||||
"main": "src/main.js",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/ornicar/lila"
|
||||
},
|
||||
"keywords": [
|
||||
"chess",
|
||||
"lichess",
|
||||
"puzzle",
|
||||
"training"
|
||||
],
|
||||
"author": "Thibault Duplessis",
|
||||
"license": "AGPL-3.0",
|
||||
"bugs": {
|
||||
"url": "https://github.com/ornicar/lila/issues"
|
||||
},
|
||||
"homepage": "https://github.com/ornicar/lila",
|
||||
"devDependencies": {
|
||||
"browserify": "~13.0",
|
||||
"gulp": "~3.9",
|
||||
"gulp-streamify": "~1.0",
|
||||
"gulp-uglify": "~1.5",
|
||||
"gulp-util": "~3.0",
|
||||
"vinyl-source-stream": "~1.1",
|
||||
"watchify": "~3.7"
|
||||
},
|
||||
"dependencies": {
|
||||
"chessground": "github:ornicar/chessground#v4.3.10",
|
||||
"chessli.js": "file:../chessli",
|
||||
"lodash": "~3.7.0",
|
||||
"merge": "~1.2.0",
|
||||
"mithril": "github:ornicar/mithril.js#v1.0.1"
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue