arbitrary starting positions for swiss tournaments

arena-from-position
Thibault Duplessis 2020-10-18 13:59:22 +02:00
parent 0068e53d65
commit e1443f92b7
8 changed files with 50 additions and 9 deletions

View File

@ -26,7 +26,7 @@ object form {
form3.split(fields.name, fields.nbRounds),
form3.split(fields.rated, fields.variant),
fields.clock,
fields.description,
form3.split(fields.description, fields.position),
form3.split(
fields.roundInterval,
fields.startsAt
@ -60,7 +60,7 @@ object form {
form3.split(fields.name, fields.nbRounds),
form3.split(fields.rated, fields.variant),
fields.clock,
fields.description,
form3.split(fields.description, swiss.settings.position.isDefined option fields.position),
form3.split(
fields.roundInterval,
swiss.isCreated option fields.startsAt
@ -168,8 +168,17 @@ final private class SwissFields(form: Form[_])(implicit ctx: Context) {
frag("Tournament description"),
help = frag(
"Anything special you want to tell the participants? Try to keep it short. Markdown links are available: [name](https://url)"
).some
).some,
half = true
)(form3.textarea(_)(rows := 4))
def position =
form3.group(
form("position"),
trans.startPosition(),
klass = "position",
half = true,
help = views.html.tournament.form.positionInputHelp.some
)(form3.input(_))
def startsAt =
form3.group(
form("startsAt"),

View File

@ -50,6 +50,20 @@ object side {
st.section(cls := "description")(markdownLinksOrRichText(d))
},
s.looksLikePrize option views.html.tournament.bits.userPrizeDisclaimer(s.createdBy),
s.settings.position.flatMap(lila.tournament.Thematic.byFen) map { pos =>
div(
a(targetBlank, href := pos.url)(strong(pos.eco), " ", pos.name),
" • ",
a(href := routes.UserAnalysis.parseArg(pos.fen.replace(" ", "_")))(
trans.analysis()
)
)
} orElse s.settings.position.map { fen =>
div(
"Custom position • ",
a(href := routes.UserAnalysis.parseArg(fen.value.replace(" ", "_")))(trans.analysis())
)
},
teamLink(s.teamId),
if (verdicts.relevant)
st.section(

View File

@ -1,14 +1,15 @@
package lila.swiss
import scala.concurrent.duration._
import chess.Clock.{ Config => ClockConfig }
import chess.format.FEN
import chess.variant.Variant
import chess.{ Color, StartingPosition }
import reactivemongo.api.bson._
import scala.concurrent.duration._
import lila.db.BSON
import lila.db.dsl._
import lila.user.User
import reactivemongo.api.bson._
private object BsonHandlers {
@ -128,6 +129,7 @@ private object BsonHandlers {
nbRounds = r.get[Int]("n"),
rated = r.boolO("r") | true,
description = r.strO("d"),
position = r.getO[FEN]("f"),
chatFor = r.intO("c") | Swiss.ChatFor.default,
roundInterval = (r.intO("i") | 60).seconds,
password = r.strO("p"),
@ -138,6 +140,7 @@ private object BsonHandlers {
"n" -> s.nbRounds,
"r" -> (!s.rated).option(false),
"d" -> s.description,
"f" -> s.position,
"c" -> (s.chatFor != Swiss.ChatFor.default).option(s.chatFor),
"i" -> s.roundInterval.toSeconds.toInt,
"p" -> s.password,

View File

@ -8,6 +8,7 @@ import scala.concurrent.duration._
import lila.hub.LightTeam.TeamID
import lila.rating.PerfType
import lila.user.User
import chess.format.FEN
case class Swiss(
_id: Swiss.Id,
@ -91,6 +92,7 @@ object Swiss {
nbRounds: Int,
rated: Boolean,
description: Option[String] = None,
position: Option[FEN],
chatFor: ChatFor = ChatFor.default,
password: Option[String] = None,
conditions: SwissCondition.All,

View File

@ -72,6 +72,7 @@ final class SwissApi(
nbRounds = data.nbRounds,
rated = data.rated | true,
description = data.description,
position = data.realPosition,
chatFor = data.realChatFor,
roundInterval = data.realRoundInterval,
password = data.password,
@ -97,6 +98,9 @@ final class SwissApi(
nbRounds = data.nbRounds,
rated = data.rated | old.settings.rated,
description = data.description orElse old.settings.description,
position =
if (old.isCreated || old.settings.position.isDefined) data.realPosition
else old.settings.position,
chatFor = data.chatFor | old.settings.chatFor,
roundInterval =
if (data.roundInterval.isDefined) data.realRoundInterval

View File

@ -84,8 +84,11 @@ final private class SwissDirector(
Game
.make(
chess = chess.Game(
variantOption = Some(swiss.variant),
fen = none
variantOption = Some {
if (swiss.settings.position.isEmpty) swiss.variant
else chess.variant.FromPosition
},
fen = swiss.settings.position.map(_.value)
) pipe { g =>
val turns = g.player.fold(0, 1)
g.copy(

View File

@ -1,6 +1,7 @@
package lila.swiss
import chess.Clock.{ Config => ClockConfig }
import chess.format.FEN
import chess.variant.Variant
import org.joda.time.DateTime
import play.api.data._
@ -28,6 +29,7 @@ final class SwissForm(implicit mode: Mode) {
"rated" -> optional(boolean),
"nbRounds" -> number(min = minRounds, max = 100),
"description" -> optional(clean(nonEmptyText)),
"position" -> optional(lila.common.Form.fen.playableStrict),
"chatFor" -> optional(numberIn(chatForChoices.map(_._1))),
"roundInterval" -> optional(numberIn(roundIntervals)),
"password" -> optional(clean(nonEmptyText)),
@ -46,6 +48,7 @@ final class SwissForm(implicit mode: Mode) {
rated = true.some,
nbRounds = 7,
description = none,
position = none,
chatFor = Swiss.ChatFor.default.some,
roundInterval = Swiss.RoundInterval.auto.some,
password = None,
@ -61,6 +64,7 @@ final class SwissForm(implicit mode: Mode) {
rated = s.settings.rated.some,
nbRounds = s.settings.nbRounds,
description = s.settings.description,
position = s.settings.position,
chatFor = s.settings.chatFor.some,
roundInterval = s.settings.roundInterval.toSeconds.toInt.some,
password = s.settings.password,
@ -137,6 +141,7 @@ object SwissForm {
rated: Option[Boolean],
nbRounds: Int,
description: Option[String],
position: Option[FEN],
chatFor: Option[Int],
roundInterval: Option[Int],
password: Option[String],
@ -160,5 +165,6 @@ object SwissForm {
case i => i
}
}.seconds
def realPosition = position ifTrue realVariant.standard
}
}

View File

@ -3,7 +3,7 @@ import flatpickr from "flatpickr";
lichess.load.then(() => {
const $variant = $('#form3-variant'),
showPosition = () => $('.form3 .position').toggleClass('none', $variant.val() != '1');
showPosition = () => $('.form3 .position').toggleClass('none', !['1', 'standard'].includes($variant.val() as string));
$variant.on('change', showPosition);
showPosition();