study server eval variations

pull/3990/head
Thibault Duplessis 2018-01-21 15:54:21 -05:00
parent b58325d20d
commit 1e366b76a7
6 changed files with 84 additions and 18 deletions

View File

@ -156,7 +156,7 @@ object BSONHandlers {
}
}
private implicit def NodeBSONHandler: BSON[Node] = new BSON[Node] {
implicit def NodeBSONHandler: BSON[Node] = new BSON[Node] {
def reads(r: Reader) = Node(
id = r.get[UciCharPair]("i"),
ply = r int "p",

View File

@ -113,6 +113,16 @@ final class ChapterRepo(coll: Coll) {
s"root.n.${indexes.mkString(".n.")}.$subField"
}
private[study] def setChild(chapter: Chapter, path: Path, child: Node): Funit =
pathToField(chapter, path, "n") ?? { parentChildrenPath =>
coll.update(
$id(chapter.id) ++ $doc(s"$parentChildrenPath.i" -> child.id),
$set(s"$parentChildrenPath.$$" -> child)
) flatMap { res =>
(res.n == 0) ?? coll.update($id(chapter.id), $push(parentChildrenPath -> child)).void
}
}
private[study] def idNamesByStudyIds(studyIds: Seq[Study.Id]): Fu[Map[Study.Id, Vector[Chapter.IdName]]] =
coll.find(
$doc("studyId" $in studyIds),

View File

@ -20,6 +20,7 @@ sealed trait RootOrNode {
val gamebook: Option[Gamebook]
val glyphs: Glyphs
val score: Option[Score]
def addChild(node: Node): RootOrNode
def fullMoveNumber = 1 + ply / 2
def mainline: List[Node]
def color = chess.Color(ply % 2 == 0)
@ -50,6 +51,8 @@ case class Node(
def withoutChildren = copy(children = Node.emptyChildren)
def addChild(child: Node) = copy(children = children addNode child)
def withClock(centis: Option[Centis]) = copy(clock = centis)
def isCommented = comments.value.nonEmpty
@ -78,7 +81,20 @@ case class Node(
score = none
)
override def toString = s"$id:${move.san} $score"
def merge(n: Node): Node = copy(
shapes = shapes ++ n.shapes,
comments = comments ++ n.comments,
gamebook = n.gamebook orElse gamebook,
glyphs = glyphs merge n.glyphs,
score = n.score orElse score,
clock = n.clock orElse clock,
crazyData = n.crazyData orElse crazyData,
children = n.children.nodes.foldLeft(children) {
case (cs, c) => children addNode c
}
)
override def toString = s"$ply.${move.san} ${children.nodes}"
}
object Node {
@ -97,11 +113,14 @@ object Node {
}
def addNodeAt(node: Node, path: Path): Option[Children] = path.split match {
case None if has(node.id) => this.some
case None => Children(nodes :+ node).some
case None => addNode(node).some
case Some((head, tail)) => updateChildren(head, _.addNodeAt(node, tail))
}
def addNode(node: Node): Children = get(node.id).fold(Children(nodes :+ node)) { prev =>
Children(nodes.filterNot(_.id == node.id) :+ prev.merge(node))
}
def deleteNodeAt(path: Path): Option[Children] = path.split match {
case None => none
case Some((head, Path(Nil))) if has(head) => Children(nodes.filterNot(_.id == head)).some
@ -203,6 +222,8 @@ object Node {
def withoutChildren = copy(children = Node.emptyChildren)
def addChild(child: Node) = copy(children = children addNode child)
def nodeAt(path: Path): Option[RootOrNode] =
if (path.isEmpty) this.some else children nodeAt path

View File

@ -2,9 +2,11 @@ package lila.study
import play.api.libs.json._
import lila.analyse.Analysis
import chess.format.{ Forsyth, FEN, Uci, UciCharPair }
import lila.analyse.{ Analysis, Info }
import lila.hub.actorApi.fishnet.StudyChapterRequest
import lila.hub.actorApi.map.Tell
import lila.socket.Socket.Uid
import lila.tree._
import lila.tree.Node.Comment
import lila.user.User
@ -44,30 +46,64 @@ object ServerEval {
sequencer.sequenceStudyWithChapter(Study.Id(studyId), Chapter.Id(analysis.id)) {
case Study.WithChapter(study, chapter) =>
(complete ?? chapterRepo.setAnalysed(chapter.id, true.some)) >> {
val allInfoAdvices = analysis.infos.headOption.map(_ -> none).toList ::: analysis.infoAdvices
lila.common.Future.fold(chapter.root.mainline zip allInfoAdvices)(Path.root) {
lila.common.Future.fold(chapter.root.mainline zip analysis.infoAdvices)(Path.root) {
case (path, (node, (info, advOpt))) => info.eval.score.ifTrue(node.score.isEmpty).?? { score =>
chapterRepo.setScore(chapter, path + node, score.some) >>
advOpt.?? { adv =>
chapterRepo.setComments(chapter, path, node.comments + Comment(
chapterRepo.setComments(chapter, path + node, node.comments + Comment(
Comment.Id.make,
Comment.Text(adv.makeComment(false, true)),
Comment.Author.Lichess
))
)) >> {
chapter.root.nodeAt(path).flatMap { parent =>
analysisLine(parent, chapter.setup.variant, info) flatMap { child =>
parent.addChild(child).children.get(child.id)
}
} ?? { chapterRepo.setChild(chapter, path, _) }
}
}
} inject path + node
} void
} >>- chapterRepo.byId(Chapter.Id(analysis.id)).foreach {
_ ?? { chapter =>
socketHub ! Tell(studyId, ServerEval.Progress(
chapterId = chapter.id,
tree = lila.study.TreeBuilder(chapter.root, chapter.setup.variant),
analysis = toJson(chapter, analysis)
))
} >>- {
chapterRepo.byId(Chapter.Id(analysis.id)).foreach {
_ ?? { chapter =>
socketHub ! Tell(studyId, ServerEval.Progress(
chapterId = chapter.id,
tree = lila.study.TreeBuilder(chapter.root, chapter.setup.variant),
analysis = toJson(chapter, analysis)
))
}
}
} logFailure logger
}
}
private def analysisLine(root: RootOrNode, variant: chess.variant.Variant, info: Info): Option[Node] = {
chess.Replay.gameMoveWhileValid(info.variation take 20, root.fen.value, variant) match {
case (init, games, error) =>
error foreach { logger.info(_) }
games.reverse match {
case Nil => none
case (g, m) :: rest => rest.foldLeft(makeBranch(g, m)) {
case (node, (g, m)) => makeBranch(g, m) addChild node
} some
}
}
}
private def makeBranch(g: chess.Game, m: Uci.WithSan) = {
val fen = FEN(Forsyth >> g)
Node(
id = UciCharPair(m.uci),
ply = g.turns,
move = m,
fen = fen,
check = g.situation.check,
crazyData = g.situation.board.crazyData,
clock = none,
children = Node.emptyChildren
)
}
}
case class Progress(chapterId: Chapter.Id, tree: Root, analysis: JsObject)

View File

@ -18,7 +18,6 @@ lichess.advantageChart = function(data, trans, el) {
var color = node.ply & 1, cp;
console.log(node.eval);
if (node.eval && node.eval.mate) {
cp = node.eval.mate > 0 ? Infinity : -Infinity;
} else if (node.san.indexOf('#') > 0) {

View File

@ -29,7 +29,7 @@ export function ctrl(root: AnalyseCtrl, chapterId: () => string): ServerEvalCtrl
if (!li.advantageChart || lastPly() === mainlinePly) return;
const lp = lastPly(typeof mainlinePly === 'undefined' ? lastPly() : mainlinePly),
el = chartEl();
if (el) {
if (el && window.HighCharts) {
const $chart = $(el);
if ($chart.length) {
const chart = $chart.highcharts();