Merge branch 'master' into simulation
* master: only load 5 games per page in user profile is "Íslenska" translation #5030. Author: Anonymous. tr "Türkçe" translation #5029. Author: Yemliha İpek. correct word is "tabii" not tabi lv "latviešu valoda" translation #5025. Author: krauzand. id "Bahasa Indonesia" translation #5024. Author: Anonymous. nn "Norsk nynorsk" translation #5020. Author: A. If by preferences you mean options, this will work as a translation. et "eesti, eesti keel" translation #5019. Author: luuletaja. corrected translations and typos publish AI server IP in move stream publish move metadata in stream Conflicts: modules/round/src/main/Env.scala
This commit is contained in:
commit
ad67e8b579
10
README.md
10
README.md
|
@ -94,15 +94,15 @@ Vary: Accept-Encoding
|
|||
1a
|
||||
4om0thb7 d1e1 91.121.7.111
|
||||
1b
|
||||
o2eg9xu3 c8c2 89.77.165.159
|
||||
o2eg9xu3 c8c2x 89.77.165.159
|
||||
18
|
||||
g3ag6xm6 g7f7 83.149.8.9
|
||||
g3ag6xm6 g7f7+ 83.149.8.9
|
||||
1b
|
||||
hl0zbh3g c4c5 109.237.157.8
|
||||
hl0zbh3g c4c5# 109.237.157.8
|
||||
1a
|
||||
g3ag6xm6 c2c3 91.121.7.111
|
||||
g3ag6xm6 c2c3x+ 91.121.7.111
|
||||
1c
|
||||
tj2u3hus a7a6 117.199.47.140
|
||||
tj2u3hus a7a6x# 117.199.47.140
|
||||
```
|
||||
|
||||
By comparing game IDs, you can guess who plays against who.
|
||||
|
|
|
@ -21,7 +21,7 @@ object Ai extends LilaController {
|
|||
logwarn("[ai] stochfish server play: " + err)
|
||||
InternalServerError(err.toString)
|
||||
},
|
||||
Ok(_)
|
||||
res ⇒ Ok(res.move)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,15 +21,9 @@ object Main extends LilaController {
|
|||
}
|
||||
|
||||
def stream = Action.async {
|
||||
import lila.hub.actorApi.round.MoveEvent
|
||||
import lila.round.MoveBroadcast
|
||||
val format = Enumeratee.map[MoveEvent] { move ⇒
|
||||
s"${move.gameId} ${move.move} ${move.ip}"
|
||||
}
|
||||
Env.round.moveBroadcast ? MoveBroadcast.GetEnumerator mapTo
|
||||
manifest[Enumerator[MoveEvent]] map { enumerator ⇒
|
||||
Ok.feed(enumerator &> format)
|
||||
}
|
||||
manifest[Enumerator[String]] map { e ⇒ Ok.feed(e) }
|
||||
}
|
||||
|
||||
def captchaCheck(id: String) = Open { implicit ctx ⇒
|
||||
|
|
|
@ -17,6 +17,7 @@ checkmate=Matt
|
|||
stalemate=Patt
|
||||
white=Valge
|
||||
black=Must
|
||||
randomColor=Suvaline värv
|
||||
createAGame=Loo mäng
|
||||
noGameAvailableRightNowCreateOne=Mängu pole hetkel saadaval - loo üks!
|
||||
whiteIsVictorious=Valge on võitnud
|
||||
|
@ -24,16 +25,16 @@ blackIsVictorious=Must on võitnud
|
|||
playWithTheSameOpponentAgain=Mängi uuesti sama vastasega
|
||||
newOpponent=Uus vastane
|
||||
playWithAnotherOpponent=Mängi teise vastasega
|
||||
yourOpponentWantsToPlayANewGameWithYou=Sinu vastane soovib mängida uut mägu sinuga
|
||||
yourOpponentWantsToPlayANewGameWithYou=Sinu vastane soovib mängida uut mängu sinuga
|
||||
joinTheGame=Liitu mänguga
|
||||
whitePlays=Valge mängib
|
||||
blackPlays=Must mängib
|
||||
theOtherPlayerHasLeftTheGameYouCanForceResignationOrWaitForHim=Vastane on lahkunud mängust. Sa võid sundida, et mängija alistuks või ootad.
|
||||
makeYourOpponentResign=Pane vastane alistuma
|
||||
forceResignation=Sunni alistuma
|
||||
forceDraw=Sunni viik
|
||||
forceDraw=Sunni viiki
|
||||
talkInChat=Räägi jututoas
|
||||
theFirstPersonToComeOnThisUrlWillPlayWithYou=Esimene inimene kes selle URLi peale klikkab, mängib sinuga.
|
||||
theFirstPersonToComeOnThisUrlWillPlayWithYou=Esimene inimene kes selle URLi peale klikib, mängib sinuga.
|
||||
whiteCreatesTheGame=Valge on mängu looja
|
||||
blackCreatesTheGame=Must on mängu looja
|
||||
whiteJoinsTheGame=Valge liitus mänguga
|
||||
|
@ -42,7 +43,7 @@ whiteResigned=Valge alistus
|
|||
blackResigned=Must alistus
|
||||
whiteLeftTheGame=Valge lahkus mängust
|
||||
blackLeftTheGame=Must lahkus mängust
|
||||
shareThisUrlToLetSpectatorsSeeTheGame=Jaga seda linki, et lasta pealtvaatajatel seda mängu näha
|
||||
shareThisUrlToLetSpectatorsSeeTheGame=Jaga seda linki, et pealtvaatajad näeksid mängu
|
||||
youAreViewingThisGameAsASpectator=Sa vaatad seda mängu pealt
|
||||
replayAndAnalyse=Korda ja analüüsi
|
||||
computerAnalysisInProgress=Arvuti analüüs on pooleli
|
||||
|
@ -51,8 +52,8 @@ theComputerAnalysisHasFailed=Arvuti analüüs ei tulnud välja
|
|||
viewTheComputerAnalysis=Vaata arvuti analüüsi
|
||||
requestAComputerAnalysis=Nõua arvuti analüüsi
|
||||
blunders=vigu
|
||||
mistakes=vead
|
||||
inaccuracies=ebatäpsed
|
||||
mistakes=eksimusi
|
||||
inaccuracies=ebatäpsused
|
||||
viewGameStats=Vaata mängu statistikat
|
||||
flipBoard=Keera lauda
|
||||
threefoldRepetition=Kolmekordne kordus
|
||||
|
@ -86,13 +87,14 @@ timeControl=Aja kontroll
|
|||
time=Aeg
|
||||
start=Start
|
||||
username=Kasutajanimi
|
||||
password=Parool
|
||||
password=Salasõna
|
||||
haveAnAccount=Kas sul on kasutaja?
|
||||
allYouNeedIsAUsernameAndAPassword=Kõik, mida vajad on kasutajanime ja parooli.
|
||||
allYouNeedIsAUsernameAndAPassword=Kõik, mida vajad on kasutajanime ja salasõna.
|
||||
changePassword=Muuda salasõna
|
||||
learnMoreAboutLichess=Uuri rohkem Lichessi kohta
|
||||
rank=Asetus
|
||||
gamesPlayed=Mänge mängitud
|
||||
nbGamesWithYou=%s mängud sinuga
|
||||
nbGamesWithYou=%s mängudest sinuga
|
||||
declineInvitation=Keeldu kutsest
|
||||
cancel=Katkesta
|
||||
timeOut=Aja ületus
|
||||
|
@ -104,7 +106,7 @@ yourOpponentOffersADraw=Su vastane pakub viiki
|
|||
accept=Nõustu
|
||||
decline=Keeldu
|
||||
playingRightNow=Mängime kohe
|
||||
finished=Finalizado
|
||||
finished=Lõpetatud
|
||||
abortGame=Katkesta mäng
|
||||
gameAborted=Mäng katkestatud
|
||||
standard=Standard
|
||||
|
@ -157,7 +159,7 @@ toggleBackground=Muuda tausta värvi
|
|||
search=Otsi
|
||||
advancedSearch=Täpsem otsing
|
||||
tournament=Turniir
|
||||
tournaments=Torneos
|
||||
tournaments=Turniirid
|
||||
tournamentPoints=Turniiri punktid
|
||||
viewTournament=Vaata turniiri
|
||||
freeOnlineChessGamePlayChessNowInACleanInterfaceNoRegistrationNoAdsNoPluginRequiredPlayChessWithComputerFriendsOrRandomOpponents=Tasuta online malemäng. Mängi malet nüüd puhtas kasutajaliideses. Pole registreerimist, pole reklaami, pole pluginaid vaja. Mängi malet arvuti, sõbrade või juhusliku vastasega.
|
||||
|
@ -215,34 +217,41 @@ memberSince=Liige alates
|
|||
lastLogin=Viimane sisenemine
|
||||
challengeToPlay=Väljakutse mängule
|
||||
player=Mängija
|
||||
list=Lista
|
||||
graph=Gráfico
|
||||
all=Todo
|
||||
lessThanNbMinutes=Menos de %s minutos
|
||||
xToYMinutes=entre %s y %s minutos
|
||||
textIsTooShort=El texto is demasiado corto
|
||||
textIsTooLong=El texto es demasiado largo
|
||||
required=Requerido
|
||||
addToChrome=Agregar a Chrome
|
||||
openTournaments=Torneos abiertos
|
||||
duration=Duración
|
||||
winner=Ganador
|
||||
standing=Permanecer
|
||||
createANewTournament=Crear un nuevo Torneo
|
||||
join=Unirse
|
||||
withdraw=Retirarse
|
||||
points=Puntos
|
||||
wins=Gana
|
||||
losses=Pérdidas
|
||||
winStreak=Victorias consecutivas
|
||||
createdBy=Creado por
|
||||
waitingForNbPlayers=Aguardando por %s jugadores
|
||||
tournamentIsStarting=El torneo está comenzando
|
||||
nbMinutesPerSidePlusNbSecondsPerMove=%s minutos/lado + %s segundos/movimiento
|
||||
membersOnly=ainult liikmetele
|
||||
boardEditor=Editor de tablero
|
||||
startPosition=Posición inicial
|
||||
clearBoard=Limpiar el tablero
|
||||
savePosition=Guardar posición
|
||||
list=Nimekiri
|
||||
graph=Graafik
|
||||
all=Kõik
|
||||
lessThanNbMinutes=Alla %s minuti
|
||||
xToYMinutes=%s kuni %s minutit
|
||||
textIsTooShort=Tekst on liiga lühike
|
||||
textIsTooLong=Tekst on liiga pikk
|
||||
required=Nõutud
|
||||
addToChrome=Lisa Chrome
|
||||
openTournaments=Avatud turniirid
|
||||
duration=Kestvus
|
||||
winner=Võitja
|
||||
standing=Tulemus
|
||||
createANewTournament=Loo uus turniir
|
||||
join=UnirseLiitu
|
||||
withdraw=Loobu
|
||||
points=Punkte
|
||||
wins=Võite
|
||||
losses=Kaotusi
|
||||
winStreak=Järjest võidetuid
|
||||
createdBy=Lõi kasutaja
|
||||
waitingForNbPlayers=Ootan %s mängijat
|
||||
tournamentIsStarting=Turniir algab
|
||||
nbMinutesPerSidePlusNbSecondsPerMove=%s minutit/pool + %s sekundit/liigutus
|
||||
membersOnly=Ainult liikmetele
|
||||
boardEditor=Laua muutja
|
||||
startPosition=Algseis
|
||||
clearBoard=Puhasta laud
|
||||
savePosition=Salvesta seis
|
||||
isPrivate=Privaatne
|
||||
reportXToModerators=Teata kasutajast %s moderaatoritele
|
||||
profile=Profiil
|
||||
editProfile=Muuda profiili
|
||||
firstName=Eesnimi
|
||||
lastName=Perekonnanimi
|
||||
biography=Elulugu
|
||||
country=Maa
|
||||
preferences=Sätted
|
||||
|
|
|
@ -254,3 +254,4 @@ firstName=Nama awal
|
|||
lastName=Nama akhir
|
||||
biography=Biografi
|
||||
country=Negara
|
||||
preferences=Preferensi
|
||||
|
|
|
@ -90,6 +90,7 @@ username=Notandanafn
|
|||
password=Lykilorð
|
||||
haveAnAccount=Hafa reikning
|
||||
allYouNeedIsAUsernameAndAPassword=Allt sem þú þarft er notandanafn og lykilorð
|
||||
changePassword=Skipta um lykilorð
|
||||
learnMoreAboutLichess=Lærðu meira um Lichess
|
||||
rank=Staða
|
||||
gamesPlayed=Leikir spilaðir
|
||||
|
|
|
@ -17,6 +17,7 @@ checkmate=Šahs un mats
|
|||
stalemate=Pats
|
||||
white=Baltie
|
||||
black=Melnie
|
||||
randomColor=Nejauša krāsa
|
||||
createAGame=Izveidot spēli
|
||||
noGameAvailableRightNowCreateOne=Pagaidām nav pieejamas spēles, izveidojiet jaunu!
|
||||
whiteIsVictorious=Baltie uzvarēja
|
||||
|
@ -89,6 +90,7 @@ username=Lietotājvārds
|
|||
password=Parole
|
||||
haveAnAccount=Vai tev ir konts?
|
||||
allYouNeedIsAUsernameAndAPassword=Viss kas nepieciešams ir lietotājvārds un parole.
|
||||
changePassword=Mainīt paroli
|
||||
learnMoreAboutLichess=Uzzināt vairāk par Lichess.
|
||||
rank=Rangs
|
||||
gamesPlayed=Izspēlētās spēles
|
||||
|
@ -247,3 +249,9 @@ savePosition=Saglabāt pozīciju
|
|||
isPrivate=Privāts
|
||||
reportXToModerators=Ziņot par %s moderatoriem
|
||||
profile=Profils
|
||||
editProfile=Labot profilu
|
||||
firstName=Vārds
|
||||
lastName=Uzvārds
|
||||
biography=Biogrāfija
|
||||
country=Valsts
|
||||
preferences=Uzstādījumi
|
||||
|
|
|
@ -254,3 +254,4 @@ firstName=Førenamn
|
|||
lastName=Etternamn
|
||||
biography=Biografi
|
||||
country=Land
|
||||
preferences=Innstillingar
|
||||
|
|
|
@ -113,8 +113,8 @@ standard=Standart
|
|||
unlimited=Sınırsız
|
||||
mode=Mod
|
||||
casual=Rastgele
|
||||
rated=Değerlendirmeye tabi
|
||||
thisGameIsRated=Bu oyun değerlendirmeye tabidir
|
||||
rated=Değerlendirmeye tabii
|
||||
thisGameIsRated=Bu oyun değerlendirmeye tabiidir
|
||||
rematch=Rövanş
|
||||
rematchOfferSent=Yeniden oynama teklifi yollandı
|
||||
rematchOfferAccepted=Yeniden oynama teklifi kabul edildi
|
||||
|
|
|
@ -6,27 +6,31 @@ import chess.Move
|
|||
import lila.analyse.Info
|
||||
import lila.game.{ Game, Progress, GameRepo, PgnRepo, UciMemo }
|
||||
|
||||
case class AiHost(host: String, ip: String)
|
||||
case class MoveResult(move: String, server: AiHost)
|
||||
case class PlayResult(progress: Progress, move: Move, server: AiHost)
|
||||
|
||||
trait Ai {
|
||||
|
||||
def play(game: Game, level: Int): Fu[Progress] = withValidSituation(game) {
|
||||
def play(game: Game, level: Int): Fu[PlayResult] = withValidSituation(game) {
|
||||
for {
|
||||
fen ← game.variant.exotic ?? { GameRepo initialFen game.id }
|
||||
pgn ← PgnRepo get game.id
|
||||
uciMoves ← uciMemo.get(game, pgn)
|
||||
moveStr ← move(uciMoves.toList, fen, level)
|
||||
uciMove ← (UciMove(moveStr) toValid s"${game.id} wrong bestmove: $moveStr").future
|
||||
moveResult ← move(uciMoves.toList, fen, level)
|
||||
uciMove ← (UciMove(moveResult.move) toValid s"${game.id} wrong bestmove: $moveResult").future
|
||||
result ← (game.toChess withPgnMoves pgn)(uciMove.orig, uciMove.dest).future
|
||||
(c, m) = result
|
||||
(progress, pgn2) = game.update(c, m)
|
||||
(c, move) = result
|
||||
(progress, pgn2) = game.update(c, move)
|
||||
_ ← (GameRepo save progress) >>
|
||||
PgnRepo.save(game.id, pgn2) >>-
|
||||
uciMemo.add(game, uciMove.uci)
|
||||
} yield progress
|
||||
} yield PlayResult(progress, move, moveResult.server)
|
||||
}
|
||||
|
||||
def uciMemo: UciMemo
|
||||
|
||||
def move(uciMoves: List[String], initialFen: Option[String], level: Int): Fu[String]
|
||||
def move(uciMoves: List[String], initialFen: Option[String], level: Int): Fu[MoveResult]
|
||||
|
||||
def analyse(uciMoves: List[String], initialFen: Option[String]): Fu[List[Info]]
|
||||
|
||||
|
|
43
modules/ai/src/main/DNSLookup.scala
Normal file
43
modules/ai/src/main/DNSLookup.scala
Normal file
|
@ -0,0 +1,43 @@
|
|||
package lila.ai
|
||||
|
||||
import javax.naming.directory.{ InitialDirContext, Attribute }
|
||||
import javax.naming.NamingException
|
||||
import scala.collection.JavaConversions._
|
||||
import scala.concurrent.Future
|
||||
|
||||
import lila.memo.AsyncCache
|
||||
|
||||
private[ai] object DNSLookup {
|
||||
|
||||
private val cache = AsyncCache(lookupInFuture)
|
||||
|
||||
def apply(url: String): Fu[AiHost] = cache(url)
|
||||
|
||||
private def lookupInFuture(url: String): Fu[AiHost] = Future {
|
||||
val host = new java.net.URL(url).getHost
|
||||
lookup(host).headOption map { AiHost(host, _) }
|
||||
} flatten s"Can't lookup $url IP address"
|
||||
|
||||
// based on http://ujihisa.blogspot.fr/2012/09/dns-lookup-in-scala.html
|
||||
private def lookup(host: String): List[String] = {
|
||||
val attributes = try {
|
||||
new InitialDirContext getAttributes ("dns:/%s" format host)
|
||||
}
|
||||
catch {
|
||||
case _: NamingException ⇒ return Nil
|
||||
}
|
||||
val list = {
|
||||
val attributeEnumeration = attributes.getAll
|
||||
var list = List[Attribute]()
|
||||
while (attributeEnumeration.hasMore)
|
||||
list = attributeEnumeration.next :: list
|
||||
attributeEnumeration.close
|
||||
list.reverse
|
||||
}
|
||||
list map (x ⇒ x.getID -> x.get.toString) flatMap {
|
||||
case ("A", x) ⇒ List(x)
|
||||
case ("CNAME", x) ⇒ lookup(x)
|
||||
case (_, x) ⇒ Nil
|
||||
}
|
||||
}
|
||||
}
|
|
@ -18,6 +18,7 @@ final class Env(
|
|||
val IsServer = config getBoolean "server"
|
||||
val IsClient = config getBoolean "client"
|
||||
val StockfishRemotes = config getStringList "stockfish.remotes" toList
|
||||
val StockfishLocal = config getString "stockfish.local"
|
||||
val StockfishPlayRoute = config getString "stockfish.play.route"
|
||||
val StockfishAnalyseRoute = config getString "stockfish.analyse.route"
|
||||
val StockfishLoadRoute = config getString "stockfish.load.route"
|
||||
|
@ -77,6 +78,7 @@ final class Env(
|
|||
lazy val stockfishServer = new stockfish.Server(
|
||||
queue = stockfishQueue,
|
||||
config = stockfishConfig,
|
||||
host = DNSLookup(StockfishLocal),
|
||||
uciMemo = uciMemo)
|
||||
|
||||
def nbStockfishRemotes = StockfishRemotes.size
|
||||
|
|
|
@ -15,9 +15,9 @@ final class Client(
|
|||
config: Config,
|
||||
val uciMemo: lila.game.UciMemo) extends lila.ai.Ai {
|
||||
|
||||
def move(uciMoves: List[String], initialFen: Option[String], level: Int): Fu[String] = {
|
||||
def move(uciMoves: List[String], initialFen: Option[String], level: Int): Fu[MoveResult] = {
|
||||
implicit val timeout = makeTimeout(config.playTimeout)
|
||||
dispatcher ? Play(uciMoves, ~initialFen, level) mapTo manifest[String]
|
||||
dispatcher ? Play(uciMoves, ~initialFen, level) mapTo manifest[MoveResult]
|
||||
} recoverWith {
|
||||
case e: Exception ⇒ {
|
||||
logwarn(s"[stockfish client] move ${e.getMessage}")
|
||||
|
|
|
@ -14,12 +14,15 @@ import lila.hub.actorApi.ai.GetLoad
|
|||
private[ai] final class Server(
|
||||
queue: ActorRef,
|
||||
config: Config,
|
||||
host: Fu[AiHost],
|
||||
val uciMemo: lila.game.UciMemo) extends lila.ai.Ai {
|
||||
|
||||
def move(uciMoves: List[String], initialFen: Option[String], level: Int): Fu[String] = {
|
||||
def move(uciMoves: List[String], initialFen: Option[String], level: Int): Fu[MoveResult] = {
|
||||
implicit val timeout = makeTimeout(config.playTimeout)
|
||||
queue ? PlayReq(uciMoves, initialFen map chess960Fen, level) mapTo
|
||||
manifest[Option[String]] flatten "[stockfish] play failed"
|
||||
manifest[Option[String]] flatten "[stockfish] play failed" flatMap { move ⇒
|
||||
host map { MoveResult(move, _) }
|
||||
}
|
||||
}
|
||||
|
||||
def analyse(uciMoves: List[String], initialFen: Option[String]): Fu[List[Info]] = {
|
||||
|
|
|
@ -40,7 +40,9 @@ private[ai] final class Connection(
|
|||
"uciMoves" -> uciMoves.mkString(" "),
|
||||
"initialFen" -> fen,
|
||||
"level" -> level.toString
|
||||
).get() map (_.body) pipeTo sender
|
||||
).get() flatMap { response ⇒
|
||||
DNSLookup(router.play) map { MoveResult(response.body, _) }
|
||||
} pipeTo sender
|
||||
|
||||
case Analyse(uciMoves, fen) ⇒ WS.url(router.analyse).withQueryString(
|
||||
"uciMoves" -> uciMoves.mkString(" "),
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit e3462cf9f8b330a0586070706a52c9dec6b02e99
|
||||
Subproject commit 8e938a749b6658f153a999b129b7caa0fb879402
|
|
@ -83,7 +83,7 @@ private final class Captcher extends Actor {
|
|||
case (_, moves) ⇒ moves filter { move ⇒
|
||||
(move.after situationOf !game.player).checkMate
|
||||
}
|
||||
} map (_.notation) toNel
|
||||
} map (_.spaceNotation) toNel
|
||||
|
||||
private def rewind(game: Game, pgnString: String): Option[ChessGame] =
|
||||
pgn.Reader.withSans(pgnString, safeInit) map (_.state) toOption
|
||||
|
|
|
@ -119,7 +119,12 @@ package monitor {
|
|||
}
|
||||
|
||||
package round {
|
||||
case class MoveEvent(gameId: String, fen: String, move: String, ip: String)
|
||||
case class MoveEvent(
|
||||
gameId: String,
|
||||
fen: String,
|
||||
move: String,
|
||||
ip: String,
|
||||
meta: String) // x, +, #, +x, #x
|
||||
case class FinishGame(gameId: String)
|
||||
}
|
||||
|
||||
|
|
|
@ -41,7 +41,6 @@ final class Env(
|
|||
val NetDomain = config getString "net.domain"
|
||||
val ActorMapName = config getString "actor.map.name"
|
||||
val ActorName = config getString "actor.name"
|
||||
val AiIpAddress = config getString "ai.ip_address"
|
||||
val HijackEnabled = config getBoolean "hijack.enabled"
|
||||
}
|
||||
import settings._
|
||||
|
@ -102,8 +101,10 @@ final class Env(
|
|||
finisher = finisher,
|
||||
cheatDetector = cheatDetector,
|
||||
roundMap = hub.actor.roundMap,
|
||||
uciMemo = uciMemo,
|
||||
aiIp = AiIpAddress)
|
||||
uciMemo = uciMemo)
|
||||
|
||||
// public access to AI play, for setup.Processor usage
|
||||
val aiPlay = player ai _
|
||||
|
||||
private lazy val drawer = new Drawer(
|
||||
messenger = messenger,
|
||||
|
|
|
@ -3,21 +3,28 @@ package lila.round
|
|||
import akka.actor._
|
||||
|
||||
import lila.hub.actorApi.round.MoveEvent
|
||||
import play.api.libs.iteratee._
|
||||
|
||||
private final class MoveBroadcast extends Actor {
|
||||
|
||||
private val (enumerator, channel) =
|
||||
play.api.libs.iteratee.Concurrent.broadcast[MoveEvent]
|
||||
|
||||
context.system.lilaBus.subscribe(self, 'moveEvent)
|
||||
|
||||
override def postStop() {
|
||||
context.system.lilaBus.unsubscribe(self)
|
||||
}
|
||||
|
||||
val format = Enumeratee.map[MoveEvent] { move ⇒
|
||||
s"${move.gameId} ${move.move}${move.meta} ${move.ip}"
|
||||
}
|
||||
|
||||
val (enumerator, channel) =
|
||||
play.api.libs.iteratee.Concurrent.broadcast[MoveEvent]
|
||||
|
||||
val formattedEnumerator = enumerator &> format
|
||||
|
||||
def receive = {
|
||||
|
||||
case MoveBroadcast.GetEnumerator ⇒ sender ! enumerator
|
||||
case MoveBroadcast.GetEnumerator ⇒ sender ! formattedEnumerator
|
||||
|
||||
case move: MoveEvent ⇒ channel push move
|
||||
}
|
||||
|
|
|
@ -16,8 +16,7 @@ private[round] final class Player(
|
|||
finisher: Finisher,
|
||||
cheatDetector: CheatDetector,
|
||||
roundMap: akka.actor.ActorSelection,
|
||||
uciMemo: UciMemo,
|
||||
aiIp: String) {
|
||||
uciMemo: UciMemo) {
|
||||
|
||||
def human(play: HumanPlay)(pov: Pov): Fu[Events] = play match {
|
||||
case HumanPlay(playerId, ip, origS, destS, promS, blur, lag, onFailure) ⇒ pov match {
|
||||
|
@ -34,7 +33,7 @@ private[round] final class Player(
|
|||
case ((progress, pgn), move) ⇒
|
||||
((GameRepo save progress) zip PgnRepo.save(pov.gameId, pgn)) >>-
|
||||
(pov.game.hasAi ! uciMemo.add(pov.game, move)) >>-
|
||||
notifyProgress(progress, ip) >>
|
||||
notifyProgress(move, progress, ip) >>
|
||||
progress.game.finished.fold(
|
||||
moveFinish(progress.game, color) map { progress.events ::: _ }, {
|
||||
cheatDetector(progress.game) addEffect {
|
||||
|
@ -55,23 +54,31 @@ private[round] final class Player(
|
|||
}
|
||||
}
|
||||
|
||||
def ai(game: Game): Fu[Events] =
|
||||
def ai(game: Game): Fu[Progress] =
|
||||
(game.playable && game.player.isAi).fold(
|
||||
engine.play(game, game.aiLevel | 1) flatMap { progress ⇒
|
||||
notifyProgress(progress, aiIp)
|
||||
moveFinish(progress.game, game.turnColor) map { progress.events ::: _ }
|
||||
engine.play(game, game.aiLevel | 1) flatMap {
|
||||
case lila.ai.PlayResult(progress, move, host) ⇒ {
|
||||
notifyProgress(move, progress, host.ip)
|
||||
moveFinish(progress.game, game.turnColor) map { progress.++ }
|
||||
}
|
||||
},
|
||||
fufail("not AI turn")
|
||||
) logFailureErr "[ai play] game %s turn %d".format(game.id, game.turns)
|
||||
fufail(s"[ai play] game ${game.id} turn ${game.turns} not AI turn")
|
||||
) logFailureErr s"[ai play] game ${game.id} turn ${game.turns}"
|
||||
|
||||
private def notifyProgress(progress: Progress, ip: String) {
|
||||
progress.game.lastMove foreach { move ⇒
|
||||
private def notifyProgress(move: chess.Move, progress: Progress, ip: String) {
|
||||
val game = progress.game
|
||||
val chess = game.toChess
|
||||
val meta = {
|
||||
if (move.captures) "x" else ""
|
||||
} + {
|
||||
if (game.finished) "#" else if (chess.situation.check) "+" else ""
|
||||
}
|
||||
bus.publish(MoveEvent(
|
||||
ip = ip,
|
||||
gameId = progress.game.id,
|
||||
fen = Forsyth exportBoard progress.game.toChess.board,
|
||||
move = move), 'moveEvent)
|
||||
}
|
||||
gameId = game.id,
|
||||
fen = Forsyth exportBoard chess.board,
|
||||
move = move.keyString,
|
||||
meta = meta), 'moveEvent)
|
||||
}
|
||||
|
||||
private def moveFinish(game: Game, color: Color): Fu[Events] = game.status match {
|
||||
|
|
|
@ -35,7 +35,9 @@ private[round] final class Round(
|
|||
pov.game.outoftimePlayer.fold(player.human(p)(pov))(outOfTime(pov.game))
|
||||
}
|
||||
|
||||
case AiPlay ⇒ publish(GameRepo game gameId)(player.ai)
|
||||
case AiPlay ⇒ publish(GameRepo game gameId) { game ⇒
|
||||
player ai game map (_.events)
|
||||
}
|
||||
|
||||
case Abort(playerId) ⇒ handle(playerId) { pov ⇒
|
||||
pov.game.abortable ?? finisher(pov.game, _.Aborted)
|
||||
|
|
|
@ -4,6 +4,7 @@ import akka.actor._
|
|||
import com.typesafe.config.{ Config ⇒ AppConfig }
|
||||
|
||||
import lila.common.PimpedConfig._
|
||||
import lila.game.{ Game, Progress }
|
||||
import lila.user.Context
|
||||
|
||||
final class Env(
|
||||
|
@ -11,7 +12,7 @@ final class Env(
|
|||
db: lila.db.Env,
|
||||
hub: lila.hub.Env,
|
||||
messenger: lila.round.Messenger,
|
||||
ai: lila.ai.Ai,
|
||||
aiPlay: Game ⇒ Fu[Progress],
|
||||
system: ActorSystem) {
|
||||
|
||||
private val FriendMemoTtl = config duration "friend.memo.ttl"
|
||||
|
@ -29,7 +30,7 @@ final class Env(
|
|||
friendConfigMemo = friendConfigMemo,
|
||||
timeline = hub.actor.gameTimeline,
|
||||
router = hub.actor.router,
|
||||
engine = ai)
|
||||
aiPlay = aiPlay)
|
||||
|
||||
lazy val friendJoiner = new FriendJoiner(
|
||||
messenger = messenger,
|
||||
|
@ -54,6 +55,6 @@ object Env {
|
|||
db = lila.db.Env.current,
|
||||
hub = lila.hub.Env.current,
|
||||
messenger = lila.round.Env.current.messenger,
|
||||
ai = lila.ai.Env.current.ai,
|
||||
aiPlay = lila.round.Env.current.aiPlay,
|
||||
system = lila.common.PlayApp.system)
|
||||
}
|
||||
|
|
|
@ -3,17 +3,17 @@ package lila.setup
|
|||
import akka.actor.ActorSelection
|
||||
import akka.pattern.ask
|
||||
import chess.{ Game ⇒ ChessGame, Board, Color ⇒ ChessColor }
|
||||
import makeTimeout.short
|
||||
import play.api.libs.json.{ Json, JsObject }
|
||||
|
||||
import lila.db.api._
|
||||
import lila.game.tube.gameTube
|
||||
import lila.game.{ Game, GameRepo, PgnRepo, Pov }
|
||||
import lila.game.{ Game, GameRepo, PgnRepo, Pov, Progress }
|
||||
import lila.hub.actorApi.router.Player
|
||||
import lila.i18n.I18nDomain
|
||||
import lila.lobby.actorApi.AddHook
|
||||
import lila.lobby.Hook
|
||||
import lila.user.{ User, Context }
|
||||
import makeTimeout.short
|
||||
import tube.{ userConfigTube, anonConfigTube }
|
||||
|
||||
private[setup] final class Processor(
|
||||
|
@ -21,7 +21,7 @@ private[setup] final class Processor(
|
|||
friendConfigMemo: FriendConfigMemo,
|
||||
timeline: ActorSelection,
|
||||
router: ActorSelection,
|
||||
engine: lila.ai.Ai) {
|
||||
aiPlay: Game ⇒ Fu[Progress]) {
|
||||
|
||||
def filter(config: FilterConfig)(implicit ctx: Context): Funit =
|
||||
saveConfig(_ withFilter config)
|
||||
|
@ -32,9 +32,10 @@ private[setup] final class Processor(
|
|||
saveConfig(_ withAi config) >>
|
||||
(GameRepo insertDenormalized game) >>-
|
||||
(timeline ! game) >>
|
||||
game.player.isHuman.fold(fuccess(pov), for {
|
||||
progress ← engine.play(game, game.aiLevel | 1)
|
||||
} yield pov withGame progress.game)
|
||||
game.player.isHuman.fold(
|
||||
fuccess(pov),
|
||||
aiPlay(game) map { progress ⇒ pov withGame progress.game }
|
||||
)
|
||||
}
|
||||
|
||||
def friend(config: FriendConfig)(implicit ctx: Context): Fu[Pov] = {
|
||||
|
|
|
@ -103,7 +103,7 @@ object ApplicationBuild extends Build {
|
|||
)
|
||||
|
||||
lazy val setup = project("setup", Seq(
|
||||
common, db, memo, hub, socket, chess, game, user, lobby)).settings(
|
||||
common, db, memo, hub, socket, chess, game, user, lobby, round)).settings(
|
||||
libraryDependencies ++= provided(play.api, reactivemongo, playReactivemongo)
|
||||
)
|
||||
|
||||
|
|
Loading…
Reference in a new issue