lila/modules/bot/src/main/BotPlayer.scala

103 lines
3.3 KiB
Scala
Raw Normal View History

2018-04-15 16:17:09 -06:00
package lila.bot
2018-04-17 15:42:39 -06:00
import akka.actor._
2019-04-07 09:03:05 -06:00
2018-04-17 15:42:39 -06:00
import scala.concurrent.duration._
2018-04-15 16:17:09 -06:00
import scala.concurrent.Promise
2018-04-15 16:17:09 -06:00
import chess.format.Uci
2019-04-07 09:03:05 -06:00
import lila.game.{ Game, GameRepo, Pov }
2018-04-15 16:17:09 -06:00
import lila.hub.actorApi.map.Tell
2019-11-01 03:05:16 -06:00
import lila.game.Game.{ PlayerId, FullId }
2019-04-07 09:03:05 -06:00
import lila.hub.actorApi.round.{ Abort, BotPlay, RematchNo, RematchYes, Resign }
import lila.round.actorApi.round.{ DrawNo, DrawYes }
import lila.user.User
2018-04-15 16:17:09 -06:00
2018-04-18 08:02:23 -06:00
final class BotPlayer(
2019-11-25 14:36:39 -07:00
chatApi: lila.chat.ChatApi,
2019-08-24 09:20:36 -06:00
isOfferingRematch: Pov => Boolean
2018-05-10 09:58:39 -06:00
)(implicit system: ActorSystem) {
2018-04-15 16:17:09 -06:00
def apply(pov: Pov, me: User, uciStr: String, offeringDraw: Option[Boolean]): Funit =
2018-05-10 09:58:39 -06:00
lila.common.Future.delay((pov.game.hasAi ?? 500) millis) {
Uci(uciStr).fold(fufail[Unit](s"Invalid UCI: $uciStr")) { uci =>
lila.mon.bot.moves(me.username)()
if (!pov.isMyTurn) fufail("Not your turn, or game already over")
else {
val promise = Promise[Unit]
if (pov.player.isOfferingDraw && (offeringDraw contains false)) declineDraw(pov)
else if (!pov.player.isOfferingDraw && (offeringDraw contains true)) offerDraw(pov)
2018-08-21 07:38:15 -06:00
system.lilaBus.publish(
Tell(pov.gameId, BotPlay(pov.playerId, uci, promise.some)),
'roundMapTell
)
2018-05-10 09:58:39 -06:00
promise.future
}
2018-04-15 16:17:09 -06:00
}
}
2018-04-18 08:02:23 -06:00
def chat(gameId: Game.ID, me: User, d: BotForm.ChatData) = fuccess {
2018-04-22 21:25:21 -06:00
lila.mon.bot.chats(me.username)()
2018-04-18 08:02:23 -06:00
val chatId = lila.chat.Chat.Id {
if (d.room == "player") gameId else s"$gameId/w"
}
val source = d.room == "spectator" option {
lila.hub.actorApi.shutup.PublicSource.Watcher(gameId)
}
2019-11-25 14:36:39 -07:00
chatApi.userChat.write(chatId, me.id, d.text, publicSource = source)
2018-04-18 08:02:23 -06:00
}
def rematchAccept(id: Game.ID, me: User): Fu[Boolean] = rematch(id, me, true)
2018-04-18 08:02:23 -06:00
def rematchDecline(id: Game.ID, me: User): Fu[Boolean] = rematch(id, me, false)
2018-04-17 15:42:39 -06:00
private def rematch(id: Game.ID, me: User, accept: Boolean): Fu[Boolean] =
GameRepo game id map {
2019-08-26 02:05:56 -06:00
_.flatMap(Pov(_, me)).filter(p => isOfferingRematch(!p)) ?? { pov =>
2018-04-17 15:42:39 -06:00
// delay so it feels more natural
lila.common.Future.delay(if (accept) 100.millis else 2.seconds) {
2018-04-17 15:42:39 -06:00
fuccess {
2018-08-21 07:38:15 -06:00
system.lilaBus.publish(
Tell(pov.gameId, (if (accept) RematchYes else RematchNo)(pov.playerId)),
'roundMapTell
)
2018-04-17 15:42:39 -06:00
}
}(system)
true
}
}
2018-04-18 17:57:02 -06:00
def abort(pov: Pov): Funit =
if (!pov.game.abortable) fufail("This game can no longer be aborted")
2018-08-21 07:38:15 -06:00
else fuccess {
system.lilaBus.publish(
Tell(pov.gameId, Abort(pov.playerId)),
'roundMapTell
)
}
2018-04-28 20:11:43 -06:00
def resign(pov: Pov): Funit =
if (pov.game.abortable) abort(pov)
2018-08-21 07:38:15 -06:00
else if (pov.game.resignable) fuccess {
system.lilaBus.publish(
Tell(pov.gameId, Resign(pov.playerId)),
'roundMapTell
)
}
2018-04-28 20:11:43 -06:00
else fufail("This game cannot be resigned")
2019-04-07 09:03:05 -06:00
def declineDraw(pov: Pov): Unit =
if (pov.game.drawable && pov.opponent.isOfferingDraw)
system.lilaBus.publish(
2019-11-01 03:05:16 -06:00
Tell(pov.gameId, DrawNo(PlayerId(pov.playerId))),
'roundMapTell
)
2019-04-07 09:03:05 -06:00
def offerDraw(pov: Pov): Unit =
if (pov.game.drawable && pov.game.playerCanOfferDraw(pov.color) && pov.isMyTurn)
system.lilaBus.publish(
2019-11-01 03:05:16 -06:00
Tell(pov.gameId, DrawYes(PlayerId(pov.playerId))),
'roundMapTell
)
2018-04-15 16:17:09 -06:00
}