From 9258b9e575650474d4823803a842b9a189f5ed6b Mon Sep 17 00:00:00 2001 From: Thibault Duplessis Date: Sun, 16 Sep 2012 19:17:55 +0200 Subject: [PATCH] avoid stalled tournament with only 2 players left --- app/controllers/Tournament.scala | 4 +-- app/core/CoreEnv.scala | 3 ++- app/core/Settings.scala | 2 +- app/tournament/DataForm.scala | 38 ++++++++++++++++++++++------ app/tournament/Organizer.scala | 2 +- app/tournament/Pairing.scala | 7 ++--- app/tournament/Tournament.scala | 17 +------------ app/tournament/TournamentEnv.scala | 2 +- app/views/tournament/form.scala.html | 12 ++++----- todo | 2 +- 10 files changed, 49 insertions(+), 40 deletions(-) diff --git a/app/controllers/Tournament.scala b/app/controllers/Tournament.scala index 9f25eec500..32e20c4fd2 100644 --- a/app/controllers/Tournament.scala +++ b/app/controllers/Tournament.scala @@ -124,7 +124,7 @@ object Tournament extends LilaController { def form = Auth { implicit ctx ⇒ me ⇒ - Ok(html.tournament.form(forms.create)) + Ok(html.tournament.form(forms.create, forms)) } def create = AuthBody { implicit ctx ⇒ @@ -132,7 +132,7 @@ object Tournament extends LilaController { IOResult { implicit val req = ctx.body forms.create.bindFromRequest.fold( - err ⇒ io(BadRequest(html.tournament.form(err))), + err ⇒ io(BadRequest(html.tournament.form(err, forms))), setup ⇒ api.createTournament(setup, me) map { tour ⇒ Redirect(routes.Tournament.show(tour.id)) }) diff --git a/app/core/CoreEnv.scala b/app/core/CoreEnv.scala index 3a79de7be2..d78bf36c66 100644 --- a/app/core/CoreEnv.scala +++ b/app/core/CoreEnv.scala @@ -8,6 +8,7 @@ import akka.actor._ import play.api.libs.concurrent._ import play.api.Application +import play.api.Mode.Dev import ui._ @@ -167,6 +168,6 @@ object CoreEnv { def apply(app: Application) = new CoreEnv( app, - new Settings(app.configuration.underlying) + new Settings(app.configuration.underlying, app.mode == Dev) ) } diff --git a/app/core/Settings.scala b/app/core/Settings.scala index 84f543a1f2..9a05a42d60 100644 --- a/app/core/Settings.scala +++ b/app/core/Settings.scala @@ -4,7 +4,7 @@ package core import com.typesafe.config.Config import scalaz.{ Success, Failure } -final class Settings(config: Config) { +final class Settings(config: Config, val IsDev: Boolean) { import config._ diff --git a/app/tournament/DataForm.scala b/app/tournament/DataForm.scala index e99bf3a5d9..48e3e650f0 100644 --- a/app/tournament/DataForm.scala +++ b/app/tournament/DataForm.scala @@ -5,26 +5,48 @@ import play.api.data._ import play.api.data.Forms._ import play.api.data.validation.Constraints._ -final class DataForm { +final class DataForm(isDev: Boolean) { import lila.core.Form._ - import Tournament._ - val create = Form(mapping( + val clockTimes = 0 to 10 by 1 + val clockTimeDefault = 2 + val clockTimeChoices = options(clockTimes, "%d minute{s}") + + val clockIncrements = 0 to 2 by 1 + val clockIncrementDefault = 0 + val clockIncrementChoices = options(clockIncrements, "%d second{s}") + + val minutes = 10 to 60 by 5 + val minuteDefault = 30 + val minuteChoices = options(minutes, "%d minute{s}") + + val minPlayers = isDev.fold( + (2 to 9) ++ (10 to 30 by 5), + (5 to 9) ++ (10 to 30 by 5) + ) + val minPlayerDefault = 10 + val minPlayerChoices = options(minPlayers, "%d player{s}") + + lazy val create = Form(mapping( "clockTime" -> numberIn(clockTimeChoices), "clockIncrement" -> numberIn(clockIncrementChoices), "minutes" -> numberIn(minuteChoices), "minPlayers" -> numberIn(minPlayerChoices) )(TournamentSetup.apply)(TournamentSetup.unapply) .verifying("Invalid clock", _.validClock) - ) fill TournamentSetup() + ) fill TournamentSetup( + clockTime = clockTimeDefault, + clockIncrement = clockIncrementDefault, + minutes = minuteDefault, + minPlayers = minPlayerDefault) } case class TournamentSetup( - clockTime: Int = Tournament.clockTimeDefault, - clockIncrement: Int = Tournament.clockIncrementDefault, - minutes: Int = Tournament.minuteDefault, - minPlayers: Int = Tournament.minPlayerDefault) { + clockTime: Int, + clockIncrement: Int, + minutes: Int, + minPlayers: Int) { def validClock = (clockTime + clockIncrement) > 0 } diff --git a/app/tournament/Organizer.scala b/app/tournament/Organizer.scala index 234b42f65b..1c3f856d6f 100644 --- a/app/tournament/Organizer.scala +++ b/app/tournament/Organizer.scala @@ -71,7 +71,7 @@ final class Organizer( (hubMaster ? GetTournamentUsernames(tour.id)).mapTo[Iterable[String]] onSuccess { case usernames ⇒ (tour.activeUserIds intersect usernames.toList.map(_.toLowerCase)) |> { users ⇒ - Pairing.createNewPairings(users, tour.pairings).toNel foreach { pairings ⇒ + Pairing.createNewPairings(users, tour.pairings, tour.nbActiveUsers).toNel foreach { pairings ⇒ api.makePairings(tour, pairings).unsafePerformIO } } diff --git a/app/tournament/Pairing.scala b/app/tournament/Pairing.scala index 229fdcd0d7..f0297014a4 100644 --- a/app/tournament/Pairing.scala +++ b/app/tournament/Pairing.scala @@ -66,7 +66,7 @@ object Pairing { user2 = user2, winner = none) - def createNewPairings(users: List[String], pairings: Pairings): Pairings = + def createNewPairings(users: List[String], pairings: Pairings, nbActiveUsers: Int): Pairings = if (users.size < 2) Nil @@ -79,7 +79,7 @@ object Pairing { naivePairings(idles), (idles.size > 12).fold( naivePairings(idles), - smartPairings(idles, pairings) + smartPairings(idles, pairings, nbActiveUsers) ) ) } @@ -89,7 +89,7 @@ object Pairing { case List(u1, u2) ⇒ Pairing(u1, u2) } toList - private def smartPairings(users: List[String], pairings: Pairings): Pairings = { + private def smartPairings(users: List[String], pairings: Pairings, nbActiveUsers: Int): Pairings = { def lastOpponent(user: String): Option[String] = pairings find (_ contains user) flatMap (_ opponentOf user) @@ -109,6 +109,7 @@ object Pairing { (users match { case x if x.size < 2 ⇒ Nil + case List(u1, u2) if nbActiveUsers == 2 ⇒ List(u1 -> u2) case List(u1, u2) if justPlayedTogether(u1, u2) ⇒ Nil case List(u1, u2) ⇒ List(u1 -> u2) case us ⇒ allPairCombinations(us) diff --git a/app/tournament/Tournament.scala b/app/tournament/Tournament.scala index 6dd77a06b1..82b1743c57 100644 --- a/app/tournament/Tournament.scala +++ b/app/tournament/Tournament.scala @@ -42,6 +42,7 @@ sealed trait Tournament { def userIds = players map (_.id) def activeUserIds = players filter (_.active) map (_.id) + def nbActiveUsers = players count (_.active) def nbPlayers = players.size def minPlayers = data.minPlayers def playerRatio = "%d/%d".format(nbPlayers, minPlayers) @@ -255,20 +256,4 @@ object Tournament { minPlayers = minPlayers), players = List(Player(createdBy)) ) - - val clockTimes = 0 to 10 by 1 - val clockTimeDefault = 2 - val clockTimeChoices = options(clockTimes, "%d minute{s}") - - val clockIncrements = 0 to 2 by 1 - val clockIncrementDefault = 0 - val clockIncrementChoices = options(clockIncrements, "%d second{s}") - - val minutes = 10 to 60 by 5 - val minuteDefault = 20 - val minuteChoices = options(minutes, "%d minute{s}") - - val minPlayers = (5 to 9) ++ (10 to 30 by 5) - val minPlayerDefault = 10 - val minPlayerChoices = options(minPlayers, "%d player{s}") } diff --git a/app/tournament/TournamentEnv.scala b/app/tournament/TournamentEnv.scala index c8b1a2bb05..f251857306 100644 --- a/app/tournament/TournamentEnv.scala +++ b/app/tournament/TournamentEnv.scala @@ -29,7 +29,7 @@ final class TournamentEnv( implicit val ctx = app import settings._ - lazy val forms = new DataForm + lazy val forms = new DataForm(IsDev) lazy val repo = new TournamentRepo( collection = mongodb(TournamentCollectionTournament)) diff --git a/app/views/tournament/form.scala.html b/app/views/tournament/form.scala.html index 1909f3877f..b34aebede6 100644 --- a/app/views/tournament/form.scala.html +++ b/app/views/tournament/form.scala.html @@ -1,6 +1,6 @@ -@(form: Form[_])(implicit ctx: Context) +@(form: Form[_], config: lila.tournament.DataForm)(implicit ctx: Context) -@import lila.tournament.Tournament +@import config._ @tournament.layout( title = "New tournament") { @@ -17,7 +17,7 @@ title = "New tournament") { - @base.select(form("clockTime"), Tournament.clockTimeChoices) + @base.select(form("clockTime"), config.clockTimeChoices) @@ -25,7 +25,7 @@ title = "New tournament") { - @base.select(form("clockIncrement"), Tournament.clockIncrementChoices) + @base.select(form("clockIncrement"), config.clockIncrementChoices) @@ -33,7 +33,7 @@ title = "New tournament") { - @base.select(form("minutes"), Tournament.minuteChoices) + @base.select(form("minutes"), config.minuteChoices) @@ -41,7 +41,7 @@ title = "New tournament") { - @base.select(form("minPlayers"), Tournament.minPlayerChoices) + @base.select(form("minPlayers"), config.minPlayerChoices) diff --git a/todo b/todo index eb52303249..76018f9a7c 100644 --- a/todo +++ b/todo @@ -48,5 +48,5 @@ finish games when tournament is over add opera to list of supported browsers (with websocket trick) tournament ties tournament detect leavers and withdraw them (started) (also use force resign) -tournament stalled with 2 players http://en.lichess.org/tournament/6ad411tf tournament end when all but one players resigned +send lobby new forum posts html through websockets