Merge branch 'master' into no-howler

* master:
  validate chess960 fen in api challenges
  oauth token input autofocus
  create API chess960 challenge with defined position
  update sound test page
  update sound test page
  code style
  avoid analysing empty games (swiss timeout)
  fix mobile app BC - closes #7195 and #7196
  fix prev commit
  wait for Chessground to render miniGames
This commit is contained in:
Thibault Duplessis 2020-08-28 10:01:43 +02:00
commit 886a15f084
12 changed files with 133 additions and 127 deletions

View file

@ -1,5 +1,7 @@
package controllers
import play.api.libs.json.Json
import play.api.mvc.Result
import scala.annotation.nowarn
@ -231,16 +233,17 @@ final class Challenge(
} orElse config.days.map {
TimeControl.Correspondence.apply
} getOrElse TimeControl.Unlimited
val challenge = lila.challenge.Challenge.make(
variant = config.variant,
initialFen = config.position,
timeControl = timeControl,
mode = config.mode,
color = config.color.name,
challenger = ChallengeModel.toRegistered(config.variant, timeControl)(me),
destUser = destUser,
rematchOf = none
)
val challenge = lila.challenge.Challenge
.make(
variant = config.variant,
initialFen = config.position,
timeControl = timeControl,
mode = config.mode,
color = config.color.name,
challenger = ChallengeModel.toRegistered(config.variant, timeControl)(me),
destUser = destUser,
rematchOf = none
)
(destUser, config.acceptByToken) match {
case (Some(dest), Some(strToken)) => apiChallengeAccept(dest, challenge, strToken)
case _ =>

View file

@ -114,7 +114,6 @@ object side {
},
initialFen
.ifTrue(game.variant.chess960)
.map(_.value)
.flatMap {
chess.variant.Chess960.positionNumber
}

View file

@ -26,7 +26,7 @@ object create {
form("description"),
raw("Token description"),
help = raw("For you to remember what this token is for").some
)(form3.input(_)),
)(form3.input(_)(autofocus)),
br,
br,
h2("Scopes define the access for personal tokens:"),

View file

@ -86,8 +86,8 @@ case class Challenge(
def notableInitialFen: Option[FEN] =
variant match {
case FromPosition | Horde | RacingKings => initialFen
case _ => none
case FromPosition | Horde | RacingKings | Chess960 => initialFen
case _ => none
}
def isOpen = ~open
@ -202,7 +202,9 @@ object Challenge {
variant = variant,
initialFen =
if (variant == FromPosition) initialFen
else if (variant == Chess960) none // only decided on game start
else if (variant == Chess960) initialFen filter { fen =>
Chess960.positionNumber(fen).isDefined
}
else !variant.standardInitialPosition option FEN(variant.initialFen),
timeControl = timeControl,
mode = finalMode,

View file

@ -23,19 +23,20 @@ final private class Joiner(
def makeChess(variant: chess.variant.Variant): chess.Game =
chess.Game(situation = Situation(variant), clock = c.clock.map(_.config.toClock))
val baseState = c.initialFen.ifTrue(c.variant.fromPosition) flatMap { fen =>
Forsyth.<<<@(chess.variant.FromPosition, fen.value)
val baseState = c.initialFen.ifTrue(c.variant.fromPosition || c.variant.chess960) flatMap { fen =>
Forsyth.<<<@(c.variant, fen.value)
}
val (chessGame, state) = baseState.fold(makeChess(c.variant) -> none[SituationPlus]) {
case sit @ SituationPlus(s, _) =>
case SituationPlus(sit, turns) =>
val game = chess.Game(
situation = s,
turns = sit.turns,
startedAtTurn = sit.turns,
situation = sit,
turns = turns,
startedAtTurn = turns,
clock = c.clock.map(_.config.toClock)
)
if (Forsyth.>>(game) == Forsyth.initial) makeChess(chess.variant.Standard) -> none
else game -> baseState
if (c.variant.fromPosition && Forsyth.>>(game) == Forsyth.initial)
makeChess(chess.variant.Standard) -> none
else game -> baseState
}
val perfPicker = (perfs: lila.user.Perfs) => perfs(c.perfType)
val game = Game
@ -55,10 +56,7 @@ final private class Joiner(
g.copy(
chess = g.chess.copy(
situation = g.situation.copy(
board = g.board.copy(
history = board.history,
variant = chess.variant.FromPosition
)
board = g.board.copy(history = board.history)
),
turns = sit.turns
)

View file

@ -25,8 +25,8 @@ final class Analyser(
def apply(game: Game, sender: Work.Sender): Fu[Boolean] =
(game.metadata.analysed ?? analysisRepo.exists(game.id)) flatMap {
case true => fuFalse
case _ if Game.isOldHorde(game) => fuFalse
case true => fuFalse
case _ if game.analysable => fuFalse
case _ =>
limiter(sender, ignoreConcurrentCheck = false) flatMap { accepted =>
accepted ?? {

View file

@ -28,7 +28,8 @@ final class Cached(
.build(gameRepo.lastPlayedPlayingId)
lila.common.Bus.subscribeFun("startGame") {
case lila.game.actorApi.StartGame(game) => game.userIds foreach { lastPlayedPlayingIdCache.invalidate(_) }
case lila.game.actorApi.StartGame(game) =>
game.userIds foreach lastPlayedPlayingIdCache.invalidate
}
private val nbPlayingCache = cacheApi[User.ID, Int](256, "game.nbPlaying") {

View file

@ -1,11 +1,14 @@
package lila.setup
import chess.{ Clock, Speed }
import chess.format.{ FEN, Forsyth }
import chess.variant.Chess960
import chess.variant.FromPosition
import chess.{ Clock, Speed }
import lila.game.PerfPicker
import lila.lobby.Color
import lila.rating.PerfType
import lila.game.PerfPicker
import chess.variant.Variant
final case class ApiConfig(
variant: chess.variant.Variant,
@ -17,18 +20,11 @@ final case class ApiConfig(
acceptByToken: Option[String] = None
) {
val strictFen = false
def >> = (variant.key.some, clock, days, rated, color.name.some, position.map(_.value), acceptByToken).some
def perfType: Option[PerfType] = PerfPicker.perfType(chess.Speed(clock), variant, days)
def validFen =
variant != FromPosition || {
position ?? { f =>
~(Forsyth <<< f.value).map(_.situation playable strictFen)
}
}
def validFen = ApiConfig.validFen(variant, position)
def validSpeed(isBot: Boolean) =
!isBot || clock.fold(true) { c =>
@ -64,4 +60,12 @@ object ApiConfig extends BaseHumanConfig {
position = pos map FEN,
acceptByToken = tok
).autoVariant
def validFen(variant: Variant, fen: Option[FEN]) =
if (variant.chess960) fen.forall(f => Chess960.positionNumber(f).isDefined)
else if (variant.fromPosition)
fen exists { f =>
(Forsyth <<< f.value).exists(_.situation playable false)
}
else true
}

View file

@ -3,8 +3,9 @@ package lila.setup
import chess.Clock
import chess.format.{ FEN, Forsyth }
import chess.variant.FromPosition
import lila.rating.PerfType
import lila.game.PerfPicker
import lila.rating.PerfType
final case class OpenConfig(
variant: chess.variant.Variant,
@ -12,18 +13,11 @@ final case class OpenConfig(
position: Option[FEN] = None
) {
val strictFen = false
def >> = (variant.key.some, clock, position.map(_.value)).some
def perfType: Option[PerfType] = PerfPicker.perfType(chess.Speed(clock), variant, none)
def validFen =
variant != FromPosition || {
position ?? { f =>
~(Forsyth <<< f.value).map(_.situation playable strictFen)
}
}
def validFen = ApiConfig.validFen(variant, position)
def autoVariant =
if (variant.standard && position.exists(_.value != Forsyth.initial)) copy(variant = FromPosition)

View file

@ -278,6 +278,7 @@ final class JsonView(
"id" -> game.id,
"fen" -> chess.format.Forsyth.boardAndColor(game.situation),
"orientation" -> game.naturalOrientation.name,
"color" -> game.naturalOrientation.name, // app BC https://github.com/ornicar/lila/issues/7195
"lastMove" -> ~game.lastMoveKeys,
"white" -> ofPlayer(featured.white, game player chess.White),
"black" -> ofPlayer(featured.black, game player chess.Black)

View file

@ -8,7 +8,7 @@ object Dependencies {
val scalalib = "com.github.ornicar" %% "scalalib" % "7.0.1"
val hasher = "com.roundeights" %% "hasher" % "1.2.1"
val jodaTime = "joda-time" % "joda-time" % "2.10.6"
val chess = "org.lichess" %% "scalachess" % "10.0.2"
val chess = "org.lichess" %% "scalachess" % "10.0.3"
val compression = "org.lichess" %% "compression" % "1.6"
val maxmind = "com.sanoma.cda" %% "maxmind-geoip2-scala" % "1.3.1-THIB"
val prismic = "io.prismic" %% "scala-kit" % "1.2.19-THIB213"

View file

@ -1,83 +1,87 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>lichess - Sound Test Page</title>
<style type="text/css">
html, body {
font:16px monospace;
background: #000;
color: #ebd488
}
button {
width: 100%;
}
</style>
<meta content="noindex, nofollow" name="robots">
</head>
<body>
<h1>Sound Test Page</h1>
<script src="../compiled/lichess.site.js"></script>
<table>
<thead>
<tr id="sets"></tr>
</thead>
<tbody id="sounds">
</tbody>
</table>
<script>
var soundSets = ["standard", "piano", "nes", "sfx", "futuristic", "robot"];
var soundNames = {
genericNotify: 'GenericNotify',
move: 'Move',
capture: 'Capture',
explode: 'Explosion',
lowtime: 'LowTime',
victory: 'Victory',
defeat: 'Defeat',
draw: 'Draw',
tournament1st: 'Tournament1st',
<head>
<meta charset="utf-8">
<title>lichess - Sound Test Page</title>
<style type="text/css">
html,
body {
font: 16px monospace;
background: #000;
color: #ebd488
}
button {
width: 100%;
}
</style>
<meta content="noindex, nofollow" name="robots">
</head>
<body>
<h1>Sound Test Page</h1>
<script src="http://l1.org/assets/_dl41cQ/compiled/lichess.deps.js"></script>
<script src="http://l1.org/assets/_dl41cQ/compiled/lichess.site.js"></script>
<table>
<thead>
<tr id="sets"></tr>
</thead>
<tbody id="sounds">
</tbody>
</table>
<script>
var soundSets = ["standard", "piano", "nes", "sfx", "futuristic", "robot"];
var soundNames = {
genericNotify: 'GenericNotify',
move: 'Move',
capture: 'Capture',
explode: 'Explosion',
lowtime: 'LowTime',
victory: 'Victory',
defeat: 'Defeat',
draw: 'Draw',
tournament1st: 'Tournament1st',
tournament2nd: 'Tournament2nd',
tournament3rd: 'Tournament3rd',
tournamentOther: 'TournamentOther',
berserk: 'Berserk',
check: 'Check',
tournament3rd: 'Tournament3rd',
tournamentOther: 'TournamentOther',
berserk: 'Berserk',
check: 'Check',
newChallenge: 'NewChallenge',
newPM: 'NewPM',
};
for(var i = 0; i <= 10; i++) soundNames['countDown' + i] = 'CountDown' + i;
$.each(soundSets, function (i, soundSet) {
$('#sets').append($('<th>' + soundSet + '</th>'));
};
for (var i = 0; i <= 10; i++) soundNames['countDown' + i] = 'CountDown' + i;
$.each(soundSets, function(i, soundSet) {
$('#sets').append($('<th>' + soundSet + '</th>'));
});
$.each(soundNames, function(soundKey, soundName) {
var tr = $('<tr>');
$.each(soundSets, function(i, soundSet) {
var id = "soundSet_" + soundSet;
$('<td>').append($("<button>").click(function() {
// lichess.sound.changeSet(soundSet);
// lichess.sound[soundKey]();
new Audio(`${soundSet}/${soundName}.ogg`).play();
}).text(soundName)).appendTo(tr);
});
$.each(soundNames, function (i, soundName) {
var tr = $('<tr>');
$.each(soundSets, function (i, soundSet) {
var id = "soundSet_" + soundSet;
$('<td>').append($("<button>").click(function() {
new Howl({
src: ["ogg", "mp3"].map(function(ext) {
return [soundSet, soundName + "." + ext].join("/");
}),
}).play();
}).text(soundName)).appendTo(tr);
});
tr.appendTo($('#sounds'));
});
var tr = $('<tr>');
$.each(soundSets, function (i, soundSet) {
$('<td>').append($("<button>").click(function() {
var i = 10;
var tId = setInterval(function() {
new Howl({
src: ["ogg", "mp3"].map(function(ext) {
return [soundSet, "CountDown" + i + "." + ext].join("/");
}),
}).play();
i-- || clearInterval(tId);
}, 1000);
}).text("CountDown10 --1> 0")).appendTo(tr);
tr.appendTo($('#sounds'));
});
</script>
</body>
</html>
tr.appendTo($('#sounds'));
});
var tr = $('<tr>');
$.each(soundSets, function(i, soundSet) {
$('<td>').append($("<button>").click(function() {
var i = 10;
var tId = setInterval(function() {
new Howl({
src: ["ogg", "mp3"].map(function(ext) {
return [soundSet, "CountDown" + i + "." + ext].join("/");
}),
}).play();
i-- || clearInterval(tId);
}, 1000);
}).text("CountDown10 --1> 0")).appendTo(tr);
tr.appendTo($('#sounds'));
});
</script>
</body>
</html>