lila/modules/tournament/src/main/AutoPairing.scala

82 lines
2.8 KiB
Scala

package lila.tournament
import scala.concurrent.duration._
import akka.actor.{ ActorRef, ActorSystem, ActorSelection }
import chess.Color
import lila.game.{ Game, Player => GamePlayer, GameRepo, Pov, PovRef, Source, PerfPicker }
import lila.hub.actorApi.map.Tell
import lila.round.actorApi.round.NoStartColor
import lila.user.{ User, UserRepo }
object SecondsToDoFirstMove {
def secondsToMoveFor(tour: Tournament) = tour.speed match {
case chess.Speed.Bullet => 20
case chess.Speed.Blitz => 25
case _ => 30
}
}
final class AutoPairing(
roundMap: ActorRef,
system: ActorSystem,
onStart: String => Unit) {
def apply(tour: Tournament, pairing: Pairing): Fu[Game] = for {
user1 getUser(pairing.user1)
user2 getUser(pairing.user2)
game1 = Game.make(
game = chess.Game(
variantOption = tour.variant.some,
fen = tour.position.some.filterNot(_.initial).map(_.fen)
) |> { g =>
val turns = g.player.fold(0, 1)
g.copy(
clock = tour.clock.toClock.some,
turns = turns,
startedAtTurn = turns)
},
whitePlayer = GamePlayer.white,
blackPlayer = GamePlayer.black,
mode = tour.mode,
variant =
if (tour.position.initial) tour.variant
else chess.variant.FromPosition,
source = Source.Tournament,
pgnImport = None)
game2 = game1
.updatePlayer(Color.White, _.withUser(user1.id, PerfPicker.mainOrDefault(game1)(user1.perfs)))
.updatePlayer(Color.Black, _.withUser(user2.id, PerfPicker.mainOrDefault(game1)(user2.perfs)))
.withTournamentId(tour.id)
.withId(pairing.gameId)
.start
_ (GameRepo insertDenormalized game2) >>-
scheduleIdleCheck(PovRef(game2.id, game2.turnColor), SecondsToDoFirstMove.secondsToMoveFor(tour), true) >>-
onStart(game2.id)
} yield game2
private def getUser(username: String): Fu[User] =
UserRepo named username flatMap {
_.fold(fufail[User]("No user named " + username))(fuccess)
}
private def scheduleIdleCheck(povRef: PovRef, secondsToMove: Int, thenAgain: Boolean) {
system.scheduler.scheduleOnce(secondsToMove seconds)(idleCheck(povRef, secondsToMove, thenAgain))
}
private def idleCheck(povRef: PovRef, secondsToMove: Int, thenAgain: Boolean) {
GameRepo pov povRef foreach {
_.filter(_.game.playable) foreach { pov =>
if (pov.game.playerHasMoved(pov.color)) {
if (thenAgain && !pov.game.playerHasMoved(pov.opponent.color))
scheduleIdleCheck(!pov.ref, pov.game.lastMoveTimeInSeconds.fold(secondsToMove) { lmt =>
lmt - nowSeconds + secondsToMove
}, false)
}
else roundMap ! Tell(pov.gameId, NoStartColor(pov.color))
}
}
}
}