lila/modules/game/src/main/PgnDump.scala

98 lines
3.6 KiB
Scala
Raw Normal View History

2013-03-25 08:44:51 -06:00
package lila.game
2012-05-08 05:23:49 -06:00
2013-10-03 03:02:23 -06:00
import akka.actor._
import akka.pattern.ask
2012-05-08 05:23:49 -06:00
import chess.format.Forsyth
import chess.format.pgn.{ Pgn, Tag }
2014-02-17 02:12:19 -07:00
import chess.format.{ pgn => chessPgn }
2015-08-18 07:56:18 -06:00
import chess.OpeningExplorer
2013-10-03 03:02:23 -06:00
import makeTimeout.short
import org.joda.time.format.DateTimeFormat
import lila.common.LightUser
2012-05-08 05:23:49 -06:00
2014-01-27 15:20:08 -07:00
final class PgnDump(
netBaseUrl: String,
getLightUser: String => Option[LightUser]) {
2012-05-08 05:23:49 -06:00
2012-05-28 16:27:44 -06:00
import PgnDump._
def apply(game: Game, initialFen: Option[String]): Pgn = {
val ts = tags(game, initialFen)
val fenSituation = ts find (_.name == Tag.FEN) flatMap { case Tag(_, fen) => Forsyth <<< fen }
2014-11-16 16:58:59 -07:00
val moves2 = fenSituation.??(_.situation.color.black).fold(".." :: game.pgnMoves, game.pgnMoves)
Pgn(ts, turns(moves2, fenSituation.map(_.fullMoveNumber) | 1))
}
2012-05-08 05:23:49 -06:00
def filename(game: Game): String = gameLightUsers(game) match {
2014-02-17 02:12:19 -07:00
case (wu, bu) => "lichess_pgn_%s_%s_vs_%s.%s.pgn".format(
2013-10-03 03:02:23 -06:00
dateFormat.print(game.createdAt),
player(game.whitePlayer, wu),
player(game.blackPlayer, bu),
game.id)
}
private def gameUrl(id: String) = s"$netBaseUrl/$id"
2013-10-03 03:02:23 -06:00
private def gameLightUsers(game: Game): (Option[LightUser], Option[LightUser]) =
(game.whitePlayer.userId ?? getLightUser) -> (game.blackPlayer.userId ?? getLightUser)
2013-09-16 07:58:49 -06:00
private val dateFormat = DateTimeFormat forPattern "yyyy.MM.dd";
2012-05-08 05:23:49 -06:00
2013-12-17 15:20:18 -07:00
private def rating(p: Player) = p.rating.fold("?")(_.toString)
2012-05-08 05:23:49 -06:00
private def player(p: Player, u: Option[LightUser]) =
2014-12-02 04:01:50 -07:00
p.aiLevel.fold(u.fold(p.name | lila.user.User.anonymous)(_.name))("lichess AI level " + _)
2015-03-09 09:33:16 -06:00
private val customStartPosition: Set[chess.variant.Variant] =
Set(chess.variant.Chess960, chess.variant.FromPosition, chess.variant.Horde)
2014-08-05 13:34:16 -06:00
private def tags(game: Game, initialFen: Option[String]): List[Tag] = gameLightUsers(game) match {
case (wu, bu) => List(
Tag(_.Event,
if (game.imported) "Import"
else game.rated.fold("Rated game", "Casual game")),
Tag(_.Site, gameUrl(game.id)),
Tag(_.Date, dateFormat.print(game.createdAt)),
Tag(_.White, player(game.whitePlayer, wu)),
Tag(_.Black, player(game.blackPlayer, bu)),
Tag(_.Result, result(game)),
Tag("WhiteElo", rating(game.whitePlayer)),
Tag("BlackElo", rating(game.blackPlayer)),
Tag("PlyCount", game.turns),
Tag(_.Variant, game.variant.name.capitalize),
Tag(_.TimeControl, game.clock.fold("-") { c => s"${c.limit}+${c.increment}" }),
Tag(_.ECO, game.opening.fold("?")(_.code)),
2015-08-18 07:56:18 -06:00
Tag(_.Opening, game.opening.fold("?")(_.name)),
Tag(_.Termination, {
import chess.Status._
game.status match {
2015-08-18 07:58:36 -06:00
case Created | Started => "Unterminated"
case Aborted | NoStart => "Abandoned"
case Timeout | Outoftime => "Time forfeit"
case Resign | Draw | Stalemate | Mate | VariantEnd => "Normal"
case Cheat => "Rules infraction"
2015-08-18 07:56:18 -06:00
}
})
) ::: customStartPosition(game.variant).??(List(
Tag(_.FEN, initialFen | "?"),
Tag("SetUp", "1")
))
}
2013-11-25 16:02:44 -07:00
private def turns(moves: List[String], from: Int): List[chessPgn.Turn] =
(moves grouped 2).zipWithIndex.toList map {
2014-02-17 02:12:19 -07:00
case (moves, index) => chessPgn.Turn(
number = index + from,
white = moves.headOption filter (".." !=) map { chessPgn.Move(_) },
black = moves lift 1 map { chessPgn.Move(_) })
2013-10-06 10:18:51 -06:00
} filterNot (_.isEmpty)
2012-05-28 16:27:44 -06:00
}
object PgnDump {
2012-05-08 05:23:49 -06:00
2013-03-25 08:44:51 -06:00
def result(game: Game) = game.finished.fold(
2014-02-17 02:12:19 -07:00
game.winnerColor.fold("1/2-1/2")(color => color.white.fold("1-0", "0-1")),
2012-05-08 05:23:49 -06:00
"*")
}