API challenge the AI - closes #6449
parent
e4578072a1
commit
f4e755582c
|
@ -187,9 +187,9 @@ final class Challenge(
|
|||
|
||||
def apiCreate(userId: String) = ScopedBody(_.Challenge.Write, _.Bot.Play, _.Board.Play) {
|
||||
implicit req => me =>
|
||||
implicit val lang = lila.i18n.I18nLangPicker(req, me.lang)
|
||||
implicit val lang = reqLang
|
||||
env.setup.forms.api.bindFromRequest.fold(
|
||||
jsonFormErrorDefaultLang,
|
||||
err => BadRequest(apiFormError(err)).fuccess,
|
||||
config =>
|
||||
ChallengeIpRateLimit(HTTPRequest lastRemoteAddress req) {
|
||||
ChallengeUserRateLimit(me.id) {
|
||||
|
|
|
@ -245,6 +245,19 @@ final class Setup(
|
|||
}
|
||||
}
|
||||
|
||||
def apiAi = ScopedBody(_.Challenge.Write, _.Bot.Play, _.Board.Play) { implicit req => me =>
|
||||
implicit val lang = reqLang
|
||||
PostRateLimit(HTTPRequest lastRemoteAddress req) {
|
||||
forms.apiAi.bindFromRequest.fold(
|
||||
jsonFormError,
|
||||
config =>
|
||||
processor.apiAi(config, me) map { pov =>
|
||||
Created(env.game.jsonView(pov.game, config.fen)) as JSON
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private def process[A](form: Context => Form[A])(op: A => BodyContext[_] => Fu[Pov]) =
|
||||
OpenBody { implicit ctx =>
|
||||
PostRateLimit(HTTPRequest lastRemoteAddress ctx.req) {
|
||||
|
|
|
@ -544,6 +544,7 @@ GET /api/account/email controllers.Account.apiEmail
|
|||
GET /api/account/kid controllers.Account.apiKid
|
||||
POST /api/account/kid controllers.Account.apiKidPost
|
||||
GET /api/account/preferences controllers.Pref.apiGet
|
||||
POST /api/challenge/ai controllers.Setup.apiAi
|
||||
POST /api/challenge/:user controllers.Challenge.apiCreate(user: String)
|
||||
POST /api/challenge/$id<\w{8}>/accept controllers.Challenge.apiAccept(id: String)
|
||||
POST /api/challenge/$id<\w{8}>/decline controllers.Challenge.apiDecline(id: String)
|
||||
|
|
|
@ -0,0 +1,80 @@
|
|||
package lila.setup
|
||||
|
||||
import chess.Clock
|
||||
import chess.format.FEN
|
||||
import lila.game.{ Game, Player, Pov, Source }
|
||||
import lila.lobby.Color
|
||||
import lila.user.User
|
||||
|
||||
final case class ApiAiConfig(
|
||||
variant: chess.variant.Variant,
|
||||
clock: Option[Clock.Config],
|
||||
daysO: Option[Int],
|
||||
color: Color,
|
||||
level: Int,
|
||||
fen: Option[FEN] = None
|
||||
) extends Config
|
||||
with Positional {
|
||||
|
||||
val strictFen = false
|
||||
|
||||
def >> = (level, variant.key.some, clock, daysO, color.name.some, fen.map(_.value)).some
|
||||
|
||||
val days = ~daysO
|
||||
val increment = clock.??(_.increment.roundSeconds)
|
||||
val time = clock.??(_.limit.roundSeconds / 60)
|
||||
val timeMode =
|
||||
if (clock.isDefined) TimeMode.RealTime
|
||||
else if (daysO.isDefined) TimeMode.Correspondence
|
||||
else TimeMode.Unlimited
|
||||
|
||||
def game(user: Option[User]) =
|
||||
fenGame { chessGame =>
|
||||
val perfPicker = lila.game.PerfPicker.mainOrDefault(
|
||||
chess.Speed(chessGame.clock.map(_.config)),
|
||||
chessGame.situation.board.variant,
|
||||
makeDaysPerTurn
|
||||
)
|
||||
Game
|
||||
.make(
|
||||
chess = chessGame,
|
||||
whitePlayer = creatorColor.fold(
|
||||
Player.make(chess.White, user, perfPicker),
|
||||
Player.make(chess.White, level.some)
|
||||
),
|
||||
blackPlayer = creatorColor.fold(
|
||||
Player.make(chess.Black, level.some),
|
||||
Player.make(chess.Black, user, perfPicker)
|
||||
),
|
||||
mode = chess.Mode.Casual,
|
||||
source = if (chessGame.board.variant.fromPosition) Source.Position else Source.Ai,
|
||||
daysPerTurn = makeDaysPerTurn,
|
||||
pgnImport = None
|
||||
)
|
||||
.sloppy
|
||||
} start
|
||||
|
||||
def pov(user: Option[User]) = Pov(game(user), creatorColor)
|
||||
}
|
||||
|
||||
object ApiAiConfig extends BaseConfig {
|
||||
|
||||
// lazy val clockLimitSeconds: Set[Int] = Set(0, 15, 30, 45, 60, 90) ++ (2 to 180).view.map(60 *).toSet
|
||||
|
||||
def <<(
|
||||
l: Int,
|
||||
v: Option[String],
|
||||
cl: Option[Clock.Config],
|
||||
d: Option[Int],
|
||||
c: Option[String],
|
||||
pos: Option[String]
|
||||
) =
|
||||
new ApiAiConfig(
|
||||
variant = chess.variant.Variant.orDefault(~v),
|
||||
clock = cl,
|
||||
daysO = d,
|
||||
color = Color.orDefault(~c),
|
||||
level = l,
|
||||
fen = pos map FEN
|
||||
)
|
||||
}
|
|
@ -15,7 +15,7 @@ final case class ApiConfig(
|
|||
color: Color,
|
||||
position: Option[FEN] = None,
|
||||
acceptByToken: Option[String] = None
|
||||
) extends {
|
||||
) {
|
||||
|
||||
val strictFen = false
|
||||
|
||||
|
|
|
@ -147,6 +147,22 @@ final class FormFactory(
|
|||
)(ApiConfig.<<)(_.>>).verifying("invalidFen", _.validFen)
|
||||
)
|
||||
|
||||
lazy val apiAi = Form(
|
||||
mapping(
|
||||
"level" -> level,
|
||||
"variant" -> optional(text.verifying(Variant.byKey.contains _)),
|
||||
"clock" -> optional(
|
||||
mapping(
|
||||
"limit" -> number.verifying(ApiConfig.clockLimitSeconds.contains _),
|
||||
"increment" -> increment
|
||||
)(chess.Clock.Config.apply)(chess.Clock.Config.unapply)
|
||||
),
|
||||
"days" -> optional(days),
|
||||
"color" -> optional(color),
|
||||
"fen" -> fenField
|
||||
)(ApiAiConfig.<<)(_.>>).verifying("invalidFen", _.validFen)
|
||||
)
|
||||
|
||||
def savedConfig(implicit ctx: UserContext): Fu[UserConfig] =
|
||||
ctx.me.fold(anonConfigRepo config ctx.req)(userConfigRepo.config)
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@ import lila.common.Bus
|
|||
import lila.common.config.Max
|
||||
import lila.game.Pov
|
||||
import lila.lobby.actorApi.{ AddHook, AddSeek }
|
||||
import lila.user.UserContext
|
||||
import lila.user.{ User, UserContext }
|
||||
|
||||
final private[setup] class Processor(
|
||||
gameCache: lila.game.Cached,
|
||||
|
@ -28,6 +28,14 @@ final private[setup] class Processor(
|
|||
} inject pov
|
||||
}
|
||||
|
||||
def apiAi(config: ApiAiConfig, me: User): Fu[Pov] = {
|
||||
val pov = config pov me.some
|
||||
(gameRepo insertDenormalized pov.game) >>-
|
||||
onStart(pov.gameId) >> {
|
||||
pov.game.player.isAi ?? fishnetPlayer(pov.game)
|
||||
} inject pov
|
||||
}
|
||||
|
||||
def hook(
|
||||
configBase: HookConfig,
|
||||
sri: lila.socket.Socket.Sri,
|
||||
|
|
Loading…
Reference in New Issue