tournament organizer

This commit is contained in:
Thibault Duplessis 2013-05-12 08:27:05 -03:00
parent b085fbf35d
commit 9e7d912c98
5 changed files with 98 additions and 100 deletions

View file

@ -25,6 +25,9 @@ object GameRepo {
def game(gameId: ID): Fu[Option[Game]] = $find byId gameId
def finished(gameId: ID): Fu[Option[Game]] =
$find.one($select(gameId) ++ Query.finished)
def player(gameId: ID, color: Color): Fu[Option[Player]] =
$find byId gameId map2 { (game: Game) game player color }

View file

@ -0,0 +1,73 @@
package lila.tournament
import actorApi._
import lila.hub.actorApi.round.FinishGame
import makeTimeout.short
import akka.actor._
import akka.pattern.{ ask, pipe }
private[tournament] final class Organizer(
api: TournamentApi,
reminder: ActorRef,
socketHub: ActorRef) extends Actor {
def receive = {
case CreatedTournaments createdTournaments
case CreatedTournament(tour: Created) createdTournament(tour)
case StartedTournaments startedTournaments
case StartedTournament(tour: Started) startedTournament(tour)
case StartPairings startPairings
case StartPairing(tour: Started) startPairing(tour)
case FinishGame(gameId)
api.finishGame(gameId) foreach { _ map (_.id) foreach api.socketReload }
}
def createdTournaments {
TournamentRepo.created foreach { _ foreach createdTournament }
}
def createdTournament(tour: Created) {
if (tour.isEmpty) api wipeEmpty tour
else if (tour.readyToStart) api startIfReady tour
else withUserIds(tour.id) { ids
(tour.userIds diff ids) foreach { api.withdraw(tour, _) }
}
}
def startedTournaments {
TournamentRepo.started foreach { tours
tours foreach startedTournament
reminder ! RemindTournaments(tours)
}
}
def startedTournament(tour: Started) {
if (tour.readyToFinish) api finish tour
}
def startPairings {
TournamentRepo.started foreach { _ foreach startPairing }
}
def startPairing(tour: Started) {
withUserIds(tour.id) { ids
(tour.activeUserIds intersect ids) |> { users
Pairing.createNewPairings(users, tour.pairings, tour.nbActiveUsers).toNel foreach { pairings
api.makePairings(tour, pairings)
}
}
}
}
private def withUserIds(tourId: String)(f: List[String] Unit) {
(socketHub ? GetTournamentUserIds(tourId)).mapTo[Iterable[String]] foreach { ids
f(ids.toList)
}
}
}

View file

@ -5,7 +5,7 @@ import tube.roomTube
import tube.tournamentTubes._
import lila.db.api._
import chess.{ Mode, Variant }
import lila.game.Game
import lila.game.{ Game, GameRepo }
import lila.user.User
import lila.hub.actorApi.lobby.{ SysTalk, UnTalk, ReloadTournaments }
import lila.hub.actorApi.router.Tourney
@ -27,7 +27,7 @@ private[tournament] final class TournamentApi(
site: ActorRef,
lobby: ActorRef,
roundMeddler: lila.round.Meddler,
incToints: String Int Funit) {
incToints: String Int Funit) extends scalaz.OptionTs {
def makePairings(tour: Started, pairings: NonEmptyList[Pairing]): Funit =
(tour addPairings pairings) |> { tour2
@ -56,24 +56,24 @@ private[tournament] final class TournamentApi(
sendLobbyMessage(created) inject created
}
def startIfReady(created: Created): Option[Fu[Unit]] = created.startIfReady map doStart
def startIfReady(created: Created): Option[Funit] = created.startIfReady map doStart
def earlyStart(created: Created): Option[Fu[Unit]] =
def earlyStart(created: Created): Option[Funit] =
created.readyToEarlyStart option doStart(created.start)
private def doStart(started: Started): Fu[Unit] =
private def doStart(started: Started): Funit =
$update(started) >>-
sendTo(started.id, Start) >>-
reloadSiteSocket >>-
lobbyReload
def wipeEmpty(created: Created): Fu[Unit] = created.isEmpty ?? {
def wipeEmpty(created: Created): Funit = created.isEmpty ?? {
$remove(created) >>
$remove.byId[Room](created.id) >>-
reloadSiteSocket >>-
lobbyReload >>-
(lobby ! UnTalk("%s tournament created".format(created.name).r))
}
$remove.byId[Room](created.id) >>-
reloadSiteSocket >>-
lobbyReload >>-
(lobby ! UnTalk("%s tournament created".format(created.name).r))
}
def finish(started: Started): Fu[Tournament] = started.readyToFinish.fold({
val pairingsToAbort = started.playingPairings
@ -111,13 +111,16 @@ private[tournament] final class TournamentApi(
case finished: Finished fufail("Cannot withdraw from finished tournament " + finished.id)
}
def finishGame(game: Game): Fu[Option[Tournament]] = for {
tourOption ~(game.tournamentId map TournamentRepo.startedById)
result ~(tourOption.filter(_ game.finished).map(tour {
def finishGame(gameId: String): Fu[Option[Tournament]] = for {
game optionT(GameRepo finished gameId)
tour optionT(game.tournamentId zmap TournamentRepo.startedById)
result optionT {
val tour2 = tour.updatePairing(game.id, _.finish(game.status, game.winnerUserId, game.turns))
$update(tour2) >> tripleQuickLossWithdraw(tour2, game.loserUserId) inject tour2.some
}))
} yield result
$update(tour2) >>
tripleQuickLossWithdraw(tour2, game.loserUserId) inject
tour2.some
}
} yield result.value
private def tripleQuickLossWithdraw(tour: Started, loser: Option[String]): Funit =
loser.filter(tour.quickLossStreak).zmap(withdraw(tour, _))
@ -135,7 +138,7 @@ private[tournament] final class TournamentApi(
}
}
private def socketReload(tourId: String) {
def socketReload(tourId: String) {
sendTo(tourId, Reload)
}

View file

@ -1,82 +0,0 @@
package lila.app
package tournament
import game.DbGame
import round.FinishGame
import akka.actor._
import scala.concurrent.duration._
import akka.util.Timeout
import akka.pattern.{ ask, pipe }
import scala.concurrent.{ Future, Promise }
import play.api.libs.concurrent._
import play.api.libs.concurrent.Execution.Implicits._
private[tournament] final class Organizer(
api: TournamentApi,
repo: TournamentRepo,
reminder: ActorRef,
hubMaster: ActorRef) extends Actor {
implicit val timeout = Timeout(1 second)
def receive = {
case CreatedTournaments createdTournaments
case CreatedTournament(tour: Created) createdTournament(tour)
case StartedTournaments startedTournaments
case StartedTournament(tour: Started) startedTournament(tour)
case StartPairings startPairings
case StartPairing(tour: Started) startPairing(tour)
case FinishGame(game) finishGame(game)
}
def finishGame(game: DbGame) {
api.finishGame(game).unsafePerformIO foreach { tour
hubMaster ! Forward(tour.id, Reload)
}
}
def createdTournaments {
repo.created.unsafePerformIO foreach createdTournament
}
def createdTournament(tour: Created) {
if (tour.isEmpty) (api wipeEmpty tour).unsafePerformIO
else if (tour.readyToStart) api startIfReady tour map (_.unsafePerformIO)
else (hubMaster ? GetTournamentUsernames(tour.id)).mapTo[Iterable[String]] onSuccess {
case usernames (tour.userIds diff usernames.toList.map(_.toLowerCase)) |> { leavers
leavers.map(u api.withdraw(tour, u)).sequence.unsafePerformIO
}
}
}
def startedTournaments {
repo.started.unsafePerformIO ~ { tours
tours foreach startedTournament
reminder ! RemindTournaments(tours)
}
}
def startedTournament(tour: Started) {
if (tour.readyToFinish) (api finish tour).unsafePerformIO
}
def startPairings {
repo.started.unsafePerformIO foreach startPairing
}
def startPairing(tour: Started) {
(hubMaster ? GetTournamentUsernames(tour.id)).mapTo[Iterable[String]] onSuccess {
case usernames
(tour.activeUserIds intersect usernames.toList.map(_.toLowerCase)) |> { users
Pairing.createNewPairings(users, tour.pairings, tour.nbActiveUsers).toNel foreach { pairings
api.makePairings(tour, pairings).unsafePerformIO
}
}
}
}
}

1
todo
View file

@ -80,6 +80,7 @@ chess variants https://github.com/ornicar/lila/issues/2://github.com/ornicar/lil
publish scalastic 0.90.0-thib
stream game export
show fen only after game is finished http://en.lichess.org/forum/lichess-feedback/please-disable-live-fen-notation?page=1
I owe the admins decent tools
DEPLOY p21
----------