avoid stalled tournament with only 2 players left
parent
f1c10f762c
commit
9258b9e575
|
@ -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))
|
||||
})
|
||||
|
|
|
@ -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)
|
||||
)
|
||||
}
|
||||
|
|
|
@ -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._
|
||||
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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}")
|
||||
}
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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") {
|
|||
<label for="@form("clockTime").id">Clock time</label>
|
||||
</th>
|
||||
<td>
|
||||
@base.select(form("clockTime"), Tournament.clockTimeChoices)
|
||||
@base.select(form("clockTime"), config.clockTimeChoices)
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
|
@ -25,7 +25,7 @@ title = "New tournament") {
|
|||
<label for="@form("clockIncrement").id">Clock increment</label>
|
||||
</th>
|
||||
<td>
|
||||
@base.select(form("clockIncrement"), Tournament.clockIncrementChoices)
|
||||
@base.select(form("clockIncrement"), config.clockIncrementChoices)
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
|
@ -33,7 +33,7 @@ title = "New tournament") {
|
|||
<label for="@form("minutes").id">Duration</label>
|
||||
</th>
|
||||
<td>
|
||||
@base.select(form("minutes"), Tournament.minuteChoices)
|
||||
@base.select(form("minutes"), config.minuteChoices)
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
|
@ -41,7 +41,7 @@ title = "New tournament") {
|
|||
<label for="@form("minPlayers").id">Players</label>
|
||||
</th>
|
||||
<td>
|
||||
@base.select(form("minPlayers"), Tournament.minPlayerChoices)
|
||||
@base.select(form("minPlayers"), config.minPlayerChoices)
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
|
|
2
todo
2
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
|
||||
|
|
Loading…
Reference in New Issue