lila/modules/round/src/main/Takebacker.scala

80 lines
3.1 KiB
Scala
Raw Normal View History

package lila.round
import lila.game.{ GameRepo, Game, UciMemo, Pov, Rewind, Event, Progress }
2014-05-01 06:08:54 -06:00
import lila.pref.{ Pref, PrefApi }
2014-05-01 06:08:54 -06:00
private[round] final class Takebacker(
messenger: Messenger,
uciMemo: UciMemo,
prefApi: PrefApi) {
2016-03-22 06:56:01 -06:00
def yes(pov: Pov)(implicit save: GameProxy.Save): Fu[Events] = IfAllowed(pov.game) {
2014-05-01 06:08:54 -06:00
pov match {
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) =>
2014-05-01 06:08:54 -06:00
messenger.system(game, _.takebackPropositionSent)
val progress = Progress(game) map { g =>
g.updatePlayer(color, _ proposeTakeback g.turns)
}
2016-03-22 06:56:01 -06:00
save(progress) inject List(Event.TakebackOffers(color.white, color.black))
2016-03-19 23:15:30 -06:00
case _ => fufail(ClientError("[takebacker] invalid yes " + pov))
2014-05-01 06:08:54 -06:00
}
}
2014-05-01 06:08:54 -06:00
2016-03-22 06:56:01 -06:00
def no(pov: Pov)(implicit save: GameProxy.Save): Fu[Events] = IfAllowed(pov.game) {
2014-05-01 06:08:54 -06:00
pov match {
2016-03-22 06:56:01 -06:00
case Pov(game, color) if pov.player.isProposingTakeback => save {
2014-05-01 06:08:54 -06:00
messenger.system(game, _.takebackPropositionCanceled)
Progress(game) map { g => g.updatePlayer(color, _.removeTakebackProposition) }
} inject List(Event.TakebackOffers(false, false))
2016-03-22 06:56:01 -06:00
case Pov(game, color) if pov.opponent.isProposingTakeback => save {
2014-05-01 06:08:54 -06:00
messenger.system(game, _.takebackPropositionDeclined)
Progress(game) map { g => g.updatePlayer(!color, _.removeTakebackProposition) }
} inject List(Event.TakebackOffers(false, false))
2016-03-19 23:15:30 -06:00
case _ => fufail(ClientError("[takebacker] invalid no " + pov))
2014-05-01 06:08:54 -06:00
}
}
2014-05-01 06:08:54 -06:00
def isAllowedByPrefs(game: Game): Fu[Boolean] =
if (game.hasAi) fuccess(true)
else game.userIds.map { userId =>
2014-05-01 06:08:54 -06:00
prefApi.getPref(userId, (p: Pref) => p.takeback)
}.sequenceFu map {
_.forall { p =>
p == Pref.Takeback.ALWAYS || (p == Pref.Takeback.CASUAL && game.casual)
}
}
2015-08-12 05:53:20 -06:00
private def IfAllowed(game: Game)(f: => Fu[Events]): Fu[Events] =
2016-03-19 23:15:30 -06:00
if (!game.playable) fufail(ClientError("[takebacker] game is over " + game.id))
2015-08-12 05:53:20 -06:00
else isAllowedByPrefs(game) flatMap {
2016-03-19 23:15:30 -06:00
_.fold(f, fufail(ClientError("[takebacker] disallowed by preferences " + game.id)))
2014-05-01 06:08:54 -06:00
}
2016-03-22 06:56:01 -06:00
private def single(game: Game)(implicit save: GameProxy.Save): Fu[Events] = for {
2015-01-14 08:32:05 -07:00
fen GameRepo initialFen game
progress Rewind(game, fen).future
_ fuccess { uciMemo.drop(game, 1) }
2016-03-22 06:56:01 -06:00
events saveAndNotify(progress)
} yield events
2016-03-22 06:56:01 -06:00
private def double(game: Game)(implicit save: GameProxy.Save): Fu[Events] = for {
2015-01-14 08:32:05 -07:00
fen GameRepo initialFen game
prog1 Rewind(game, fen).future
2014-02-17 02:12:19 -07:00
prog2 Rewind(prog1.game, fen).future map { progress =>
prog1 withGame progress.game
}
_ fuccess { uciMemo.drop(game, 2) }
2016-03-22 06:56:01 -06:00
events saveAndNotify(prog2)
} yield events
2016-03-22 06:56:01 -06:00
private def saveAndNotify(p1: Progress)(implicit save: GameProxy.Save): Fu[Events] = {
val p2 = p1 + Event.Reload
2014-02-01 00:54:03 -07:00
messenger.system(p2.game, _.takebackPropositionAccepted)
2016-03-22 06:56:01 -06:00
save(p2) inject p2.events
}
}