Skip to content

Commit

Permalink
more swiss WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
ornicar committed Apr 29, 2020
1 parent 4145df8 commit f92322c
Show file tree
Hide file tree
Showing 21 changed files with 238 additions and 64 deletions.
12 changes: 7 additions & 5 deletions app/mashup/TeamInfo.scala
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,16 @@ import lila.forum.MiniForumPost
import lila.team.{ RequestRepo, RequestWithUser, Team, TeamApi }
import lila.tournament.{ Tournament, TournamentApi }
import lila.user.User
import lila.swiss.{ Swiss, SwissApi }

case class TeamInfo(
mine: Boolean,
ledByMe: Boolean,
requestedByMe: Boolean,
requests: List[RequestWithUser],
forumPosts: List[MiniForumPost],
tournaments: List[Tournament]
tournaments: List[Tournament],
swisses: List[Swiss]
) {

def hasRequests = requests.nonEmpty
Expand All @@ -25,6 +27,7 @@ final class TeamInfoApi(
forumRecent: lila.forum.Recent,
teamCached: lila.team.Cached,
tourApi: TournamentApi,
swissApi: SwissApi,
requestRepo: RequestRepo
)(implicit ec: scala.concurrent.ExecutionContext) {

Expand All @@ -35,15 +38,14 @@ final class TeamInfoApi(
requestedByMe <- !mine ?? me.??(m => requestRepo.exists(team.id, m.id))
forumPosts <- forumRecent.team(team.id)
tours <- tourApi.featuredInTeam(team.id)
_ <- tours.nonEmpty ?? {
teamCached.preloadSet(tours.flatMap(_.teamBattle.??(_.teams)).toSet)
}
swisses <- swissApi.featuredInTeam(team.id)
} yield TeamInfo(
mine = mine,
ledByMe = me.exists(m => team.leaders(m.id)),
requestedByMe = requestedByMe,
requests = requests,
forumPosts = forumPosts,
tournaments = tours
tournaments = tours,
swisses = swisses
)
}
66 changes: 40 additions & 26 deletions app/templating/SetupHelper.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package lila.app
package templating

import chess.{ Mode, Speed }
import chess.variant.Variant
import play.api.i18n.Lang

import lila.i18n.{ I18nKeys => trans }
Expand Down Expand Up @@ -97,44 +98,57 @@ trait SetupHelper { self: I18nHelper =>
(Mode.Rated.id.toString, trans.ratedTournament.txt(), none)
)

private def variantTuple(variant: chess.variant.Variant): SelectChoice =
(variant.id.toString, variant.name, variant.title.some)
private val encodeId = (v: Variant) => v.id.toString

def translatedVariantChoices(implicit lang: Lang) = List(
(chess.variant.Standard.id.toString, trans.standard.txt(), chess.variant.Standard.title.some)
private def variantTupleId = variantTuple(encodeId) _

private def variantTuple(encode: Variant => String)(variant: Variant) =
(encode(variant), variant.name, variant.title.some)

def translatedVariantChoices(implicit lang: Lang): List[SelectChoice] =
translatedVariantChoices(encodeId)

def translatedVariantChoices(encode: Variant => String)(implicit lang: Lang): List[SelectChoice] = List(
(encode(chess.variant.Standard), trans.standard.txt(), chess.variant.Standard.title.some)
)

def translatedVariantChoicesWithVariants(implicit lang: Lang) =
translatedVariantChoices :+
variantTuple(chess.variant.Crazyhouse) :+
variantTuple(chess.variant.Chess960) :+
variantTuple(chess.variant.KingOfTheHill) :+
variantTuple(chess.variant.ThreeCheck) :+
variantTuple(chess.variant.Antichess) :+
variantTuple(chess.variant.Atomic) :+
variantTuple(chess.variant.Horde) :+
variantTuple(chess.variant.RacingKings)
def translatedVariantChoicesWithVariants(implicit lang: Lang): List[SelectChoice] =
translatedVariantChoicesWithVariants(encodeId)

def translatedVariantChoicesWithVariants(
encode: Variant => String
)(implicit lang: Lang): List[SelectChoice] =
translatedVariantChoices(encode) ::: List(
chess.variant.Crazyhouse,
chess.variant.Chess960,
chess.variant.KingOfTheHill,
chess.variant.ThreeCheck,
chess.variant.Antichess,
chess.variant.Atomic,
chess.variant.Horde,
chess.variant.RacingKings
).map(variantTuple(encode))

def translatedVariantChoicesWithFen(implicit lang: Lang) =
translatedVariantChoices :+
variantTuple(chess.variant.Chess960) :+
variantTuple(chess.variant.FromPosition)
variantTupleId(chess.variant.Chess960) :+
variantTupleId(chess.variant.FromPosition)

def translatedAiVariantChoices(implicit lang: Lang) =
translatedVariantChoices :+
variantTuple(chess.variant.Crazyhouse) :+
variantTuple(chess.variant.Chess960) :+
variantTuple(chess.variant.KingOfTheHill) :+
variantTuple(chess.variant.ThreeCheck) :+
variantTuple(chess.variant.Antichess) :+
variantTuple(chess.variant.Atomic) :+
variantTuple(chess.variant.Horde) :+
variantTuple(chess.variant.RacingKings) :+
variantTuple(chess.variant.FromPosition)
variantTupleId(chess.variant.Crazyhouse) :+
variantTupleId(chess.variant.Chess960) :+
variantTupleId(chess.variant.KingOfTheHill) :+
variantTupleId(chess.variant.ThreeCheck) :+
variantTupleId(chess.variant.Antichess) :+
variantTupleId(chess.variant.Atomic) :+
variantTupleId(chess.variant.Horde) :+
variantTupleId(chess.variant.RacingKings) :+
variantTupleId(chess.variant.FromPosition)

def translatedVariantChoicesWithVariantsAndFen(implicit lang: Lang) =
translatedVariantChoicesWithVariants :+
variantTuple(chess.variant.FromPosition)
variantTupleId(chess.variant.FromPosition)

def translatedSpeedChoices(implicit lang: Lang) = Speed.limited map { s =>
val minutes = s.range.max / 60 + 1
Expand Down
72 changes: 72 additions & 0 deletions app/views/swiss/bits.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
package views.html.swiss

import lila.api.Context
import lila.app.templating.Environment._
import lila.app.ui.ScalatagsTemplate._
import lila.i18n.{ I18nKeys => trans }
import lila.swiss.Swiss

import controllers.routes

object bits {

def iconChar(swiss: Swiss): String =
swiss.perfType.fold('g')(_.iconChar).toString

def notFound()(implicit ctx: Context) =
views.html.base.layout(
title = trans.tournamentNotFound.txt()
) {
main(cls := "page-small box box-pad")(
h1(trans.tournamentNotFound()),
p(trans.tournamentDoesNotExist()),
p(trans.tournamentMayHaveBeenCanceled()),
br,
br,
a(href := routes.Tournament.home())(trans.returnToTournamentsHomepage())
)
}

def forTeam(swisses: List[Swiss])(implicit ctx: Context) =
table(cls := "slist")(
tbody(
swisses map { s =>
tr(
cls := List(
"enterable" -> s.isEnterable,
"soon" -> s.isNowOrSoon
)
)(
td(cls := "icon")(iconTag(iconChar(s))),
td(cls := "header")(
a(href := routes.Swiss.show(s.id.value))(
span(cls := "name")(s.name),
span(cls := "setup")(
s.clock.show,
"",
if (s.variant.exotic) s.variant.name else s.perfType.map(_.trans),
"",
if (s.rated) trans.ratedTournament() else trans.casualTournament(),
"",
s.estimatedDurationString
)
)
),
td(cls := "infos")(
momentFromNowOnce(s.startsAt)
),
td(cls := "text", dataIcon := "r")(s.nbPlayers.localize)
)
}
)
)

def jsI18n(implicit ctx: Context) = i18nJsObject(i18nKeys)

private val i18nKeys = List(
trans.join,
trans.withdraw,
trans.joinTheGame,
trans.signIn
).map(_.key)
}
19 changes: 13 additions & 6 deletions app/views/swiss/form.scala
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,18 @@ object form {
def create(form: Form[_], teamId: TeamID)(implicit ctx: Context) =
views.html.base.layout(
title = "New Swiss tournament",
moreCss = cssTag("clas"),
moreJs = jsAt("compiled/clas.js")
moreCss = cssTag("swiss.form"),
moreJs = frag(
flatpickrTag,
jsTag("tournamentForm.js")
)
) {
val fields = new SwissFields(form)
main(cls := "page-small")(
div(cls := "swiss__form box box-pad")(
div(cls := "swiss__form tour__form box box-pad")(
h1("New Swiss tournament"),
postForm(cls := "form3", action := routes.Swiss.create(teamId))(
fields.name,
form3.split(fields.name, fields.nbRounds),
form3.split(fields.rated, fields.variant),
fields.clock,
fields.description,
Expand Down Expand Up @@ -55,6 +58,10 @@ final private class SwissFields(form: Form[_])(implicit ctx: Context) {
)
)
}
def nbRounds =
form3.group(form("nbRounds"), "Number of rounds", half = true)(
form3.input(_, typ = "number")
)

def rated = form3.checkbox(
form("rated"),
Expand All @@ -63,12 +70,12 @@ final private class SwissFields(form: Form[_])(implicit ctx: Context) {
)
def variant =
form3.group(form("variant"), trans.variant(), half = true)(
form3.select(_, translatedVariantChoicesWithVariants.map(x => x._1 -> x._2))
form3.select(_, translatedVariantChoicesWithVariants(_.key).map(x => x._1 -> x._2))
)
def clock =
form3.split(
form3.group(form("clock.limit"), trans.clockInitialTime(), half = true)(
form3.select(_, TourForm.clockTimeChoices)
form3.select(_, SwissForm.clockLimitChoices)
),
form3.group(form("clock.increment"), trans.clockIncrement(), half = true)(
form3.select(_, TourForm.clockIncrementChoices)
Expand Down
19 changes: 19 additions & 0 deletions app/views/team/show.scala
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,16 @@ object show {
em(teamTournamentOverview())
)
),
a(
href := s"${routes.Swiss.form(t.id)}",
cls := "button button-empty text",
dataIcon := "g"
)(
span(
strong("Swiss tournament"),
em("Slow and clunky, a boomer's favourite")
)
),
a(
href := routes.Team.pmAll(t.id),
cls := "button button-empty text",
Expand Down Expand Up @@ -166,6 +176,15 @@ object show {
}
)
),
info.swisses.nonEmpty option frag(
st.section(cls := "team-show__tour team-swisses")(
h2("Swiss tournaments"),
info.swisses.span(_.isCreated) match {
case (created, started) =>
views.html.swiss.bits.forTeam(created.sortBy(_.startsAt) ::: started)
}
)
),
ctx.noKid option
st.section(cls := "team-show__forum")(
h2(a(href := teamForumUrl(t.id))(trans.forum())),
Expand Down
1 change: 1 addition & 0 deletions bin/mongodb/swiss.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
db.swiss.ensureIndex({teamId:1,startsAt:1})
4 changes: 4 additions & 0 deletions modules/common/src/main/Form.scala
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,10 @@ object Form {
s"$d$code" -> (pluralize(pattern, d) format d)
}

def options(it: Iterable[Int], format: Int => String): Options[Int] = it map { d =>
d -> format(d)
}

def optionsDouble(it: Iterable[Double], format: Double => String): Options[Double] = it map { d =>
d -> format(d)
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package lila.tournament
package lila.common

object GreatPlayer {

Expand Down
3 changes: 1 addition & 2 deletions modules/round/src/main/RoundDuct.scala
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ import lila.hub.actorApi.round.{
}
import lila.hub.Duct
import lila.room.RoomSocket.{ Protocol => RP, _ }
import lila.socket.RemoteSocket.{ Protocol => _, _ }
import lila.socket.Socket.{ makeMessage, GetVersion, SocketVersion }
import lila.socket.UserLagCache
import lila.user.User
Expand Down Expand Up @@ -77,7 +76,7 @@ final private[round] class RoundDuct(
RoundSocket.povDisconnectTimeout(g pov color)
} | RoundSocket.disconnectTimeout
}.toMillis * goneWeight
base atLeast RoundSocket.ragequitTimeout.toMillis
base atLeast RoundSocket.ragequitTimeout.toMillis.toFloat
}.toLong

def isLongGone: Fu[Boolean] = {
Expand Down
1 change: 0 additions & 1 deletion modules/socket/src/main/AnaDrop.scala
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ package lila.socket
import chess.format.{ Uci, UciCharPair }
import chess.opening._
import chess.variant.Variant
import play.api.libs.json._
import play.api.libs.json.JsObject
import scalaz.Validation.FlatMap._

Expand Down
30 changes: 27 additions & 3 deletions modules/swiss/src/main/Swiss.scala
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
package lila.swiss

import org.joda.time.DateTime
import chess.Clock.{ Config => ClockConfig }
import lila.hub.LightTeam.TeamID
import chess.Speed
import org.joda.time.DateTime
import scala.concurrent.duration._

import lila.game.{ Game, PerfPicker }
import lila.hub.LightTeam.TeamID
import lila.rating.PerfType
import lila.user.User
import lila.game.Game

case class Swiss(
_id: Swiss.Id,
Expand All @@ -25,6 +28,27 @@ case class Swiss(
hasChat: Boolean = true
) {
def id = _id

def isCreated = status == Status.Created
def isStarted = status == Status.Started
def isFinished = status == Status.Finished
def isEnterable = !isFinished

def isNowOrSoon = startsAt.isBefore(DateTime.now plusMinutes 15) && !isFinished

def speed = Speed(clock)

def perfType: Option[PerfType] = PerfPicker.perfType(speed, variant, none)

def estimatedDuration: FiniteDuration = {
(clock.limit.toSeconds + clock.increment.toSeconds * 80 + 10) * nbRounds
}.toInt.seconds

def estimatedDurationString = {
val minutes = estimatedDuration.toMinutes
if (minutes < 60) s"${minutes}m"
else s"${minutes / 60}h" + (if (minutes % 60 != 0) s" ${(minutes % 60)}m" else "")
}
}

object Swiss {
Expand Down
Loading

0 comments on commit f92322c

Please sign in to comment.