From 9d61201fbcaae73effb16989c5190bf03a65812d Mon Sep 17 00:00:00 2001 From: Aaron Alef Date: Thu, 8 Oct 2020 18:38:56 +0200 Subject: [PATCH 1/3] refactor(player): convert player from kotlin to java --- player/src/sc/player2021/SimpleClient.kt | 28 -------- player/src/sc/player2021/Starter.java | 80 +++++++++++++++++++++ player/src/sc/player2021/Starter.kt | 66 ------------------ player/src/sc/player2021/logic/Logic.java | 84 +++++++++++++++++++++++ player/src/sc/player2021/logic/Logic.kt | 60 ---------------- 5 files changed, 164 insertions(+), 154 deletions(-) delete mode 100644 player/src/sc/player2021/SimpleClient.kt create mode 100644 player/src/sc/player2021/Starter.java delete mode 100755 player/src/sc/player2021/Starter.kt create mode 100644 player/src/sc/player2021/logic/Logic.java delete mode 100644 player/src/sc/player2021/logic/Logic.kt diff --git a/player/src/sc/player2021/SimpleClient.kt b/player/src/sc/player2021/SimpleClient.kt deleted file mode 100644 index a72813df7..000000000 --- a/player/src/sc/player2021/SimpleClient.kt +++ /dev/null @@ -1,28 +0,0 @@ -package sc.player2021 - -import org.slf4j.LoggerFactory -import sc.player2021.logic.Logic -import sc.plugin2021.AbstractClient - -/** - * Eine konkrete Implementierung des [AbstractClient]. - * Dieser Client tritt einem Spiel bei und interagiert über die [Logic] mit dem Server. - */ -class SimpleClient(host: String, port: Int, reservation: String): AbstractClient(host, port) { - companion object { - val logger = LoggerFactory.getLogger(SimpleClient::class.java) - } - - /** Die eigentliche [Logic], die bestimmt, welche Züge gesendet werden. */ - val logic = Logic(this) - - init { - handler = logic - - if (reservation.isEmpty()) - joinAnyGame() - else - joinPreparedGame(reservation) - } - -} \ No newline at end of file diff --git a/player/src/sc/player2021/Starter.java b/player/src/sc/player2021/Starter.java new file mode 100644 index 000000000..51376ebac --- /dev/null +++ b/player/src/sc/player2021/Starter.java @@ -0,0 +1,80 @@ +package sc.player2021; + +import jargs.gnu.CmdLineParser; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import sc.player2021.logic.Logic; +import sc.plugin2021.AbstractClient; +import sc.plugin2021.IGameHandler; +import sc.shared.SharedConfiguration; + +import java.io.File; + +/** + * Hauptklasse des Clients, die über Konsolenargumente gesteuert werden kann. + * Sie veranlasst eine Verbindung zum Spielserver. + */ +public class Starter extends AbstractClient { + private static final Logger logger = LoggerFactory.getLogger(Starter.class); + + public Starter(String host, int port, String reservation) throws Exception { + // client starten + super(host, port); + + // Strategie zuweisen + IGameHandler logic = new Logic(this); + setHandler(logic); + + // einem Spiel beitreten + if (reservation == null || reservation.isEmpty()) { + joinAnyGame(); + } else { + joinPreparedGame(reservation); + } + } + + public static void main(String[] args) { + System.setProperty("file.encoding", "UTF-8"); + + // parameter definieren + CmdLineParser parser = new CmdLineParser(); + CmdLineParser.Option hostOption = parser.addStringOption('h', "host"); + CmdLineParser.Option portOption = parser.addIntegerOption('p', "port"); + CmdLineParser.Option reservationOption = parser.addStringOption('r', "reservation"); + + try { + // parameter auslesen + parser.parse(args); + } catch (CmdLineParser.OptionException e) { + // bei Fehler die Hilfe anzeigen + showHelp(e.getMessage()); + System.exit(2); + } + + // parameter laden + String host = (String) parser.getOptionValue(hostOption, "localhost"); + int port = (Integer) parser.getOptionValue(portOption, SharedConfiguration.DEFAULT_PORT); + String reservation = (String) parser.getOptionValue(reservationOption, ""); + + // einen neuen client erzeugen + try { + new Starter(host, port, reservation); + } catch (Exception e) { + logger.error("Beim Starten den Clients ist ein Fehler aufgetreten:", e); + e.printStackTrace(); + } + + } + + private static void showHelp(String errorMsg) { + String jarName = new File(Starter.class.getProtectionDomain().getCodeSource().getLocation().getFile()).getName(); + System.out.println("\n" + errorMsg); + System.out.println("\nBitte das Programm mit folgenden Parametern (optional) aufrufen: \n" + + "java -jar " + jarName + " [{-h,--host} hostname]\n" + + " [{-p,--port} port]\n" + + " [{-r,--reservation} reservierung]"); + System.out.println("\nBeispiel: \n" + + "java -jar " + jarName + " --host 127.0.0.1 --port 10500 --reservation 1234\n"); + } + +} diff --git a/player/src/sc/player2021/Starter.kt b/player/src/sc/player2021/Starter.kt deleted file mode 100755 index d128ca4ba..000000000 --- a/player/src/sc/player2021/Starter.kt +++ /dev/null @@ -1,66 +0,0 @@ -package sc.player2021 - -import jargs.gnu.CmdLineParser -import java.io.File -import kotlin.system.exitProcess - -/** - * Dies ist die Starter Datei, die benutzt wird, um Clients mit dem Server zu verbinden. - * Wichtig ist die `main` Funktion; diese wird bei Start als erstes ausgeführt. - * - * @args [args] Eine Liste aller Parameter, mit der das Programm aufgerufen wurde. - */ -fun main(args: Array) { - val parser = CmdLineParser() - - /** - * Dies sind die verschiedenen Optionen, die dem Programm von der Kommandozeile aus übergeben werden können. - * So kann man mit Start des Programms auswählen, - * auf welchem Server / zu welchem Spiel sich der Client verbinden soll - */ - val options = mapOf( - "host" to parser.addStringOption('h', "host"), - "port" to parser.addIntegerOption('p', "port"), - "reservation" to parser.addStringOption('r', "reservation") - ) - - /** - * Es wird geprüft, ob die vorhanden Argumente Sinn machen, also valide Optionen sind. - * Bei einem Fehler wird eine kleine Hilfe angezeigt. - */ - try { - parser.parse(args) - } catch (e: CmdLineParser.OptionException) { - showHelp(e.message.orEmpty()) - exitProcess(2) - } - - /** Die Optionen werden zu sinnvollen Datentypen umgewandelt. */ - val host = parser.getOptionValue(options["host"],"localhost") as String - val port = parser.getOptionValue(options["port"], "") as Int - val reservation = parser.getOptionValue(options["reservation"], "") as String - - /** Hier wird der eigentliche Client gestartet, der dann versucht, sich mit dem gegebenen Server zu verbinden. */ - try { - SimpleClient(host, port, reservation) - } catch (e: Exception) { - SimpleClient.logger.error("Beim starten des Clients ist ein Fehler aufgetreten", e) - e.printStackTrace() - } -} - -/** Eine Hilfsfunktion, die bei falschem Aufruf des Programms anzeigt, wie das Programm zu verwenden ist. */ -private fun showHelp(errorMsg: String) { - val jarName = File(SimpleClient::class.java.protectionDomain.codeSource.location.file).name - println("\n$errorMsg") - println(""" - Bitte das Programm mit folgenden Parametern (optional) aufrufen: - java -jar $jarName [{-h, --host} hostname] - [{-p, --port} port] - [{-r, --reservation} reservation] - - Beispiel: - java -jar $jarName --host 127.0.0.1 --port 10500 --reservation 1234 - """.trimIndent()) -} - diff --git a/player/src/sc/player2021/logic/Logic.java b/player/src/sc/player2021/logic/Logic.java new file mode 100644 index 000000000..8fbc605ba --- /dev/null +++ b/player/src/sc/player2021/logic/Logic.java @@ -0,0 +1,84 @@ +package sc.player2021.logic; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import sc.framework.plugins.Player; +import sc.player2021.Starter; +import sc.plugin2021.GameState; +import sc.plugin2021.IGameHandler; +import sc.plugin2021.Move; +import sc.plugin2021.Team; +import sc.plugin2021.util.GameRuleLogic; +import sc.shared.GameResult; +import sc.api.plugins.ITeam; + +import java.util.List; + +/** + * Das Herz des Clients: + * Eine sehr simple Logik, die ihre Zuege zufaellig waehlt, + * aber gueltige Zuege macht. + * Ausserdem werden zum Spielverlauf Konsolenausgaben gemacht. + */ +public class Logic implements IGameHandler { + private static final Logger log = LoggerFactory.getLogger(Logic.class); + + private Starter client; + private GameState gameState; + private Player currentPlayer; + + /** + * Erzeugt ein neues Strategieobjekt, das zufaellige Zuege taetigt. + * + * @param client Der zugrundeliegende Client, der mit dem Spielserver kommuniziert. + */ + public Logic(Starter client) { + this.client = client; + } + + /** + * {@inheritDoc} + */ + public void gameEnded(GameResult data, Team color, String errorMessage) { + log.info("Das Spiel ist beendet."); + } + + /** + * {@inheritDoc} + */ + @Override + public void onRequestAction() { + long startTime = System.currentTimeMillis(); + log.info("Es wurde ein Zug angefordert."); + List possibleMoves = GameRuleLogic.getPossibleMoves(gameState); + sendAction(possibleMoves.get((int) (Math.random() * possibleMoves.size()))); + } + + /** + * {@inheritDoc} + */ + @Override + public void onUpdate(Player player, Player otherPlayer) { + currentPlayer = player; + log.info("Spielerwechsel: " + player.getColor()); + } + + /** + * {@inheritDoc} + */ + @Override + public void onUpdate(GameState gameState) { + this.gameState = gameState; + currentPlayer = gameState.getCurrentPlayer(); + log.info("Zug: {} Spieler: {}", gameState.getTurn(), currentPlayer.getColor()); + } + + /** + * {@inheritDoc} + */ + @Override + public void sendAction(Move move) { + client.sendMove(move); + } + +} diff --git a/player/src/sc/player2021/logic/Logic.kt b/player/src/sc/player2021/logic/Logic.kt deleted file mode 100644 index a860a3160..000000000 --- a/player/src/sc/player2021/logic/Logic.kt +++ /dev/null @@ -1,60 +0,0 @@ -package sc.player2021.logic - -import org.slf4j.LoggerFactory -import sc.framework.plugins.Player -import sc.player2021.SimpleClient -import sc.plugin2021.* -import sc.plugin2021.util.GameRuleLogic -import sc.shared.GameResult - -/** - * Das Herz des Clients: - * Eine sehr simple Logik, die ihre Züge zufällig wählt, - * aber gültige Züge macht. - * Außerdem werden alle aktionen geloggt und in der Konsole ausgegeben. - */ -class Logic(private val client: SimpleClient): IGameHandler{ - companion object { - val logger = LoggerFactory.getLogger(Logic::class.java) - } - - /** Der aktuelle Spielstand, aus dem der nächste Zug berechnet werden kann. */ - private lateinit var gameState: GameState - /** Der Spieler, der momentan am Zug ist. */ - private lateinit var currentPlayer: Player - - /** Der aktuelle Spieler wird geupdatet. */ - override fun onUpdate(player: Player, otherPlayer: Player) { - currentPlayer = player - logger.info("Spielerwechsel - neuer Spieler: ${player.color}") - } - - /** Der aktuelle Spielstand wird aktualisiert. */ - override fun onUpdate(gamestate: GameState) { - this.gameState = gamestate - currentPlayer = gamestate.currentPlayer - logger.info("$gamestate") - } - - /** Ein Zug wurde vom Server angefordert. */ - override fun onRequestAction() { - val startTime = System.currentTimeMillis() - logger.info("Es wurde ein Zug angefordert.") - val possibleMoves = GameRuleLogic.getPossibleMoves(gameState) - - /** Ein zufälliger, valider Move wird an den Server zurückgesendet. */ - sendAction( - if (possibleMoves.isEmpty()) SkipMove(gameState.currentColor) - else possibleMoves.random()) - } - - /** Der Zug wird an den Client geschickt, der diesen dann an den Server sendet. */ - override fun sendAction(move: Move) { - client.sendMove(move) - } - - /** Das Spiel ist beendet. */ - override fun gameEnded(data: GameResult, team: Team?, errorMessage: String?) { - logger.info("Das Spiel ist beendet.") - } -} \ No newline at end of file From bb5a336dd4d0e00c1bb5705acbf033c53114e73a Mon Sep 17 00:00:00 2001 From: Aaron Alef Date: Thu, 8 Oct 2020 19:00:24 +0200 Subject: [PATCH 2/3] refactor(player): adjust AbstractClient and Logic to kotlin --- player/src/sc/player2021/logic/Logic.java | 4 ++-- plugin/src/client/sc/plugin2021/AbstractClient.kt | 4 +++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/player/src/sc/player2021/logic/Logic.java b/player/src/sc/player2021/logic/Logic.java index 8fbc605ba..eabd0f7a5 100644 --- a/player/src/sc/player2021/logic/Logic.java +++ b/player/src/sc/player2021/logic/Logic.java @@ -50,8 +50,8 @@ public void gameEnded(GameResult data, Team color, String errorMessage) { public void onRequestAction() { long startTime = System.currentTimeMillis(); log.info("Es wurde ein Zug angefordert."); - List possibleMoves = GameRuleLogic.getPossibleMoves(gameState); - sendAction(possibleMoves.get((int) (Math.random() * possibleMoves.size()))); + List possibleMoves = List.copyOf(GameRuleLogic.getPossibleMoves(gameState)); + sendAction((Move) possibleMoves.get((int) (Math.random() * possibleMoves.size()))); } /** diff --git a/plugin/src/client/sc/plugin2021/AbstractClient.kt b/plugin/src/client/sc/plugin2021/AbstractClient.kt index be0634029..51ba23351 100644 --- a/plugin/src/client/sc/plugin2021/AbstractClient.kt +++ b/plugin/src/client/sc/plugin2021/AbstractClient.kt @@ -23,9 +23,11 @@ import kotlin.system.exitProcess abstract class AbstractClient @Throws(IOException::class) constructor( host: String, port: Int, - private val type: PlayerType = PlayerType.PLAYER_ONE + private val type: PlayerType ): ILobbyClientListener { + constructor(host: String, port: Int): this(host, port, PlayerType.PLAYER_ONE) {} + companion object { private val logger = LoggerFactory.getLogger(AbstractClient::class.java); private val gameType = GamePlugin.PLUGIN_UUID From ed0a751aac7d58ab797e081e2c7571ac7b40012f Mon Sep 17 00:00:00 2001 From: Aaron Alef Date: Thu, 8 Oct 2020 19:22:34 +0200 Subject: [PATCH 3/3] fix(player): change implementation to run on java 8 --- player/src/sc/player2021/logic/Logic.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/player/src/sc/player2021/logic/Logic.java b/player/src/sc/player2021/logic/Logic.java index eabd0f7a5..25a6c5b95 100644 --- a/player/src/sc/player2021/logic/Logic.java +++ b/player/src/sc/player2021/logic/Logic.java @@ -13,6 +13,7 @@ import sc.api.plugins.ITeam; import java.util.List; +import java.util.ArrayList; /** * Das Herz des Clients: @@ -50,7 +51,7 @@ public void gameEnded(GameResult data, Team color, String errorMessage) { public void onRequestAction() { long startTime = System.currentTimeMillis(); log.info("Es wurde ein Zug angefordert."); - List possibleMoves = List.copyOf(GameRuleLogic.getPossibleMoves(gameState)); + List possibleMoves = new ArrayList<>(GameRuleLogic.getPossibleMoves(gameState)); sendAction((Move) possibleMoves.get((int) (Math.random() * possibleMoves.size()))); }