progressive takeback delay - closes #2024
parent
ebb271543d
commit
f98136240c
|
@ -1,18 +1,17 @@
|
|||
package lila.round
|
||||
|
||||
import scala.concurrent.duration._
|
||||
|
||||
import akka.actor._
|
||||
import akka.pattern.{ ask, pipe }
|
||||
import org.joda.time.DateTime
|
||||
import scala.concurrent.duration._
|
||||
|
||||
import actorApi._, round._
|
||||
import chess.Color
|
||||
import lila.game.{ Game, Pov, PovRef, PlayerRef, Event, Progress }
|
||||
import lila.game.{ Game, Pov, Event }
|
||||
import lila.hub.actorApi.DeployPost
|
||||
import lila.hub.actorApi.map._
|
||||
import lila.hub.actorApi.round.FishnetPlay
|
||||
import lila.hub.SequentialActor
|
||||
import lila.i18n.I18nKey.{ Select => SelectI18nKey }
|
||||
import makeTimeout.large
|
||||
|
||||
private[round] final class Round(
|
||||
|
@ -51,6 +50,8 @@ private[round] final class Round(
|
|||
}
|
||||
}
|
||||
|
||||
var takebackSituation = Round.TakebackSituation()
|
||||
|
||||
def process = {
|
||||
|
||||
case ReceiveTimeout => fuccess {
|
||||
|
@ -157,11 +158,23 @@ private[round] final class Round(
|
|||
}
|
||||
}
|
||||
|
||||
case RematchYes(playerRef) => handle(playerRef)(rematcher.yes)
|
||||
case RematchNo(playerRef) => handle(playerRef)(rematcher.no)
|
||||
case RematchYes(playerRef) => handle(playerRef)(rematcher.yes)
|
||||
case RematchNo(playerRef) => handle(playerRef)(rematcher.no)
|
||||
|
||||
case TakebackYes(playerRef) => handle(playerRef)(takebacker.yes)
|
||||
case TakebackNo(playerRef) => handle(playerRef)(takebacker.no)
|
||||
case TakebackYes(playerRef) => handle(playerRef) { pov =>
|
||||
takebacker.yes(takebackSituation)(pov) map {
|
||||
case (events, situation) =>
|
||||
takebackSituation = situation
|
||||
events
|
||||
}
|
||||
}
|
||||
case TakebackNo(playerRef) => handle(playerRef) { pov =>
|
||||
takebacker.no(takebackSituation)(pov) map {
|
||||
case (events, situation) =>
|
||||
takebackSituation = situation
|
||||
events
|
||||
}
|
||||
}
|
||||
|
||||
case Moretime(playerRef) => handle(playerRef) { pov =>
|
||||
pov.game.clock.ifTrue(pov.game moretimeable !pov.color) ?? { clock =>
|
||||
|
@ -249,3 +262,20 @@ private[round] final class Round(
|
|||
case e: Exception => logger.warn(s"$name: ${e.getMessage}")
|
||||
}
|
||||
}
|
||||
|
||||
object Round {
|
||||
|
||||
case class TakebackSituation(
|
||||
nbDeclined: Int = 0,
|
||||
lastDeclined: Option[DateTime] = none) {
|
||||
|
||||
def decline = TakebackSituation(nbDeclined + 1, DateTime.now.some)
|
||||
|
||||
def delaySeconds = (math.pow(nbDeclined min 10, 2) * 10).toInt
|
||||
|
||||
def offerable = lastDeclined.fold(true) { _ isBefore DateTime.now.minusSeconds(delaySeconds) }
|
||||
|
||||
def reset = TakebackSituation()
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
package lila.round
|
||||
|
||||
import org.joda.time.DateTime
|
||||
|
||||
import lila.game.{ GameRepo, Game, UciMemo, Pov, Rewind, Event, Progress }
|
||||
import lila.pref.{ Pref, PrefApi }
|
||||
|
||||
|
@ -8,31 +10,37 @@ private[round] final class Takebacker(
|
|||
uciMemo: UciMemo,
|
||||
prefApi: PrefApi) {
|
||||
|
||||
def yes(pov: Pov)(implicit proxy: GameProxy): Fu[Events] = IfAllowed(pov.game) {
|
||||
def yes(situation: Round.TakebackSituation)(pov: Pov)(implicit proxy: GameProxy): Fu[(Events, Round.TakebackSituation)] = IfAllowed(pov.game) {
|
||||
pov match {
|
||||
case Pov(game, _) if pov.opponent.isProposingTakeback =>
|
||||
case Pov(game, _) if pov.opponent.isProposingTakeback => {
|
||||
if (pov.opponent.proposeTakebackAt == pov.game.turns) single(game)
|
||||
else double(game)
|
||||
case Pov(game, _) if pov.opponent.isAi => double(game)
|
||||
case Pov(game, color) if (game playerCanProposeTakeback color) =>
|
||||
} map (_ -> situation.reset)
|
||||
case Pov(game, _) if pov.opponent.isAi => double(game) map (_ -> situation)
|
||||
case Pov(game, color) if (game playerCanProposeTakeback color) && situation.offerable => {
|
||||
messenger.system(game, _.takebackPropositionSent)
|
||||
val progress = Progress(game) map { g =>
|
||||
g.updatePlayer(color, _ proposeTakeback g.turns)
|
||||
}
|
||||
proxy.save(progress) inject List(Event.TakebackOffers(color.white, color.black))
|
||||
} map (_ -> situation)
|
||||
case _ => fufail(ClientError("[takebacker] invalid yes " + pov))
|
||||
}
|
||||
}
|
||||
|
||||
def no(pov: Pov)(implicit proxy: GameProxy): Fu[Events] = pov match {
|
||||
def no(situation: Round.TakebackSituation)(pov: Pov)(implicit proxy: GameProxy): Fu[(Events, Round.TakebackSituation)] = pov match {
|
||||
case Pov(game, color) if pov.player.isProposingTakeback => proxy.save {
|
||||
messenger.system(game, _.takebackPropositionCanceled)
|
||||
Progress(game) map { g => g.updatePlayer(color, _.removeTakebackProposition) }
|
||||
} inject List(Event.TakebackOffers(false, false))
|
||||
} inject {
|
||||
List(Event.TakebackOffers(false, false)) -> situation
|
||||
}
|
||||
case Pov(game, color) if pov.opponent.isProposingTakeback => proxy.save {
|
||||
messenger.system(game, _.takebackPropositionDeclined)
|
||||
Progress(game) map { g => g.updatePlayer(!color, _.removeTakebackProposition) }
|
||||
} inject List(Event.TakebackOffers(false, false))
|
||||
} inject {
|
||||
List(Event.TakebackOffers(false, false)) -> situation.decline
|
||||
}
|
||||
case _ => fufail(ClientError("[takebacker] invalid no " + pov))
|
||||
}
|
||||
|
||||
|
@ -46,7 +54,7 @@ private[round] final class Takebacker(
|
|||
}
|
||||
}
|
||||
|
||||
private def IfAllowed(game: Game)(f: => Fu[Events]): Fu[Events] =
|
||||
private def IfAllowed[A](game: Game)(f: => Fu[A]): Fu[A] =
|
||||
if (!game.playable) fufail(ClientError("[takebacker] game is over " + game.id))
|
||||
else isAllowedByPrefs(game) flatMap {
|
||||
_.fold(f, fufail(ClientError("[takebacker] disallowed by preferences " + game.id)))
|
||||
|
|
Loading…
Reference in New Issue