diff --git a/modules/official-bots/src/main/scala/de/nowchess/bot/service/TournamentBotGamePlayer.scala b/modules/official-bots/src/main/scala/de/nowchess/bot/service/TournamentBotGamePlayer.scala index d67a240..6455380 100644 --- a/modules/official-bots/src/main/scala/de/nowchess/bot/service/TournamentBotGamePlayer.scala +++ b/modules/official-bots/src/main/scala/de/nowchess/bot/service/TournamentBotGamePlayer.scala @@ -103,7 +103,7 @@ class TournamentBotGamePlayer: log.infof("Playing game %s as %s", gameId, color) val stream = openGameStream(cfg, gameId) maybeMoveFromCurrentState(cfg, gameId, color) - if stream != null then consumeGameStream(cfg, gameId, color, stream) + stream.foreach(consumeGameStream(cfg, gameId, color, _)) activeGames.remove(gameId) } match case Failure(ex) => log.errorf(ex, "Game %s crashed", gameId); activeGames.remove(gameId) @@ -125,15 +125,19 @@ class TournamentBotGamePlayer: val reader = new BufferedReader(new InputStreamReader(stream)) // scalafix:off DisableSyntax.var var done = false - var line = reader.readLine() // scalafix:on DisableSyntax.var - while line != null && running && !done do - parse(line).foreach: node => - node.path("type").asText() match - case "move" => maybeMove(cfg, gameId, color, node.path("turn").asText(), "ongoing", node.path("fen").asText()) - case "gameEnd" => log.infof("Game %s ended — status=%s", gameId, node.path("status").asText()); done = true - case _ => () - line = reader.readLine() + Iterator + .continually(reader.readLine()) + .map(Option(_)) + .takeWhile(opt => opt.isDefined && running && !done) + .flatten + .foreach { line => + parse(line).foreach: node => + node.path("type").asText() match + case "move" => maybeMove(cfg, gameId, color, node.path("turn").asText(), "ongoing", node.path("fen").asText()) + case "gameEnd" => log.infof("Game %s ended — status=%s", gameId, node.path("status").asText()); done = true + case _ => () + } private def maybeMove( cfg: TournamentBotConfig, @@ -172,14 +176,14 @@ class TournamentBotGamePlayer: node }.getOrElse(None) - private def openGameStream(cfg: TournamentBotConfig, gameId: String): InputStream = + private def openGameStream(cfg: TournamentBotConfig, gameId: String): Option[InputStream] = Try { val response = authed(cfg, target(cfg).path("game").path(gameId).path("stream")) .header("Accept", "application/x-ndjson") .get() - if response.getStatus == 200 then response.readEntity(classOf[InputStream]) - else { log.warnf("Game stream %s returned status %d", gameId, response.getStatus); response.close(); null } - }.getOrElse(null) + if response.getStatus == 200 then Some(response.readEntity(classOf[InputStream])) + else { log.warnf("Game stream %s returned status %d", gameId, response.getStatus); response.close(); None } + }.getOrElse(None) private def engine(cfg: TournamentBotConfig): Bot = botController.getBot(cfg.difficulty).orElse(botController.getBot("medium")).get @@ -196,12 +200,14 @@ class TournamentBotGamePlayer: private def forEachLine(stream: InputStream)(handle: String => Unit): Unit = val reader = new BufferedReader(new InputStreamReader(stream)) - // scalafix:off DisableSyntax.var - var line: String = reader.readLine() - // scalafix:on DisableSyntax.var - while line != null && running do - Try(handle(line)).failed.foreach(ex => log.warnf(ex, "Error handling stream line")) - line = reader.readLine() + Iterator + .continually(reader.readLine()) + .map(Option(_)) + .takeWhile(opt => opt.isDefined && running) + .flatten + .foreach { line => + Try(handle(line)).failed.foreach(ex => log.warnf(ex, "Error handling stream line")) + } private def toUci(move: Move): String = val base = s"${move.from}${move.to}"