more puzzle ui v2 wip

This commit is contained in:
Thibault Duplessis 2016-11-28 00:18:19 +01:00
parent 05ede51670
commit 2b94cf9da7
17 changed files with 212 additions and 84 deletions

View file

@ -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 =>

View file

@ -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,

View file

@ -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

View file

@ -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 =>

View 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
}
}

View file

@ -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
}
}

View file

@ -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,

View file

@ -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
View 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']);

View 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"
}
}