From 3581904abc35826cc52c78814f9e5187f99a20af Mon Sep 17 00:00:00 2001 From: kske Date: Sun, 21 Jul 2019 14:35:14 +0200 Subject: [PATCH] Implemented UCI handshake with engine + UCI game start in MenuBar + UCI game creation method in Game - Fixed double game instance bug after starting a new game + Name and author parsing in UCIReceiver --- src/dev/kske/chess/game/Game.java | 8 ++++++++ src/dev/kske/chess/game/UCIPlayer.java | 1 + src/dev/kske/chess/game/UCIPlayerListener.java | 5 ----- src/dev/kske/chess/uci/UCIHandle.java | 4 ++-- src/dev/kske/chess/uci/UCIReceiver.java | 9 +++++---- src/dev/kske/chess/ui/MainWindow.java | 5 ++++- src/dev/kske/chess/ui/MenuBar.java | 11 +++++++++++ 7 files changed, 31 insertions(+), 12 deletions(-) diff --git a/src/dev/kske/chess/game/Game.java b/src/dev/kske/chess/game/Game.java index e3a83f6..40cd720 100644 --- a/src/dev/kske/chess/game/Game.java +++ b/src/dev/kske/chess/game/Game.java @@ -62,6 +62,14 @@ public class Game { return new Game(players, boardPane); } + public static Game createUCI(BoardPane boardPane, String enginePath) { + Map players = new HashMap<>(); + + players.put(Color.WHITE, new NaturalPlayer(Color.WHITE, boardPane.getOverlayComponent())); + players.put(Color.BLACK, new UCIPlayer(Color.BLACK, enginePath)); + return new Game(players, boardPane); + } + public void onMove(Player player, Move move) { if (board.getPos(move).getColor() == player.color && board.attemptMove(move)) { System.out.printf("%s: %s%n", player.color, move); diff --git a/src/dev/kske/chess/game/UCIPlayer.java b/src/dev/kske/chess/game/UCIPlayer.java index 376dc55..a34188d 100644 --- a/src/dev/kske/chess/game/UCIPlayer.java +++ b/src/dev/kske/chess/game/UCIPlayer.java @@ -22,6 +22,7 @@ public class UCIPlayer extends Player { handle = new UCIHandle(enginePath); listener = new UCIPlayerListener(); handle.setListener(listener); + handle.start(); } catch (IOException ex) { ex.printStackTrace(); } diff --git a/src/dev/kske/chess/game/UCIPlayerListener.java b/src/dev/kske/chess/game/UCIPlayerListener.java index 7d17457..b647e89 100644 --- a/src/dev/kske/chess/game/UCIPlayerListener.java +++ b/src/dev/kske/chess/game/UCIPlayerListener.java @@ -28,25 +28,21 @@ class UCIPlayerListener implements UCIListener { @Override public void onUCIOk() { // TODO Auto-generated method stub - } @Override public void onReadyOk() { // TODO Auto-generated method stub - } @Override public void onBestMove(String move) { // TODO Auto-generated method stub - } @Override public void onBestMove(String move, String ponderMove) { // TODO Auto-generated method stub - } @Override @@ -72,7 +68,6 @@ class UCIPlayerListener implements UCIListener { @Override public void onRegistrationOk() { System.out.println("Registration ok"); - } @Override diff --git a/src/dev/kske/chess/uci/UCIHandle.java b/src/dev/kske/chess/uci/UCIHandle.java index 3988a16..bf02f4c 100644 --- a/src/dev/kske/chess/uci/UCIHandle.java +++ b/src/dev/kske/chess/uci/UCIHandle.java @@ -17,13 +17,13 @@ public class UCIHandle { public UCIHandle(String enginePath) throws IOException { process = new ProcessBuilder(enginePath).start(); - out = new PrintWriter(process.getOutputStream()); + out = new PrintWriter(process.getOutputStream(), true); receiver = new UCIReceiver(process.getInputStream()); } public void start() { - uci(); new Thread(receiver).start(); + uci(); } /** diff --git a/src/dev/kske/chess/uci/UCIReceiver.java b/src/dev/kske/chess/uci/UCIReceiver.java index 138d329..5af8d61 100644 --- a/src/dev/kske/chess/uci/UCIReceiver.java +++ b/src/dev/kske/chess/uci/UCIReceiver.java @@ -31,8 +31,9 @@ public class UCIReceiver implements Runnable { @Override public void run() { try { - while (in.ready()) - parse(in.readLine()); + String line; + while (!Thread.currentThread().isInterrupted()) + if ((line = in.readLine()) != null) parse(line); } catch (IndexOutOfBoundsException ex) { System.err.println("Too few arguments were provided!"); ex.printStackTrace(); @@ -72,9 +73,9 @@ public class UCIReceiver implements Runnable { } private void parseId(String line) { - String param = line.substring(line.indexOf(' ')); + String param = line.substring(0, line.indexOf(' ')); String arg = line.substring(param.length() + 1); - switch (line) { + switch (param) { case "name": listener.onIdName(arg); break; diff --git a/src/dev/kske/chess/ui/MainWindow.java b/src/dev/kske/chess/ui/MainWindow.java index c33a162..b776425 100644 --- a/src/dev/kske/chess/ui/MainWindow.java +++ b/src/dev/kske/chess/ui/MainWindow.java @@ -76,5 +76,8 @@ public class MainWindow { public Game getGame() { return game; } - public void setGame(Game game) { this.game = game; } + public void setGame(Game game) { + if (this.game != null) this.game.disconnect(); + this.game = game; + } } diff --git a/src/dev/kske/chess/ui/MenuBar.java b/src/dev/kske/chess/ui/MenuBar.java index 362e684..a502474 100644 --- a/src/dev/kske/chess/ui/MenuBar.java +++ b/src/dev/kske/chess/ui/MenuBar.java @@ -3,6 +3,7 @@ package dev.kske.chess.ui; import javax.swing.JMenu; import javax.swing.JMenuBar; import javax.swing.JMenuItem; +import javax.swing.JOptionPane; import dev.kske.chess.game.Game; @@ -32,6 +33,7 @@ public class MenuBar extends JMenuBar { JMenuItem naturalMenuItem = new JMenuItem("Game against natural opponent"); JMenuItem aiMenuItem = new JMenuItem("Game against artificial opponent"); JMenuItem aiVsAiMenuItem = new JMenuItem("Watch AI vs. AI"); + JMenuItem uciMenuItem = new JMenuItem("UCI"); naturalMenuItem.addActionListener((evt) -> startGame(Game.createNatural(boardPane))); @@ -44,9 +46,18 @@ public class MenuBar extends JMenuBar { aiVsAiMenuItem.addActionListener((evt) -> startGame(Game.createAIVsAI(boardPane, 4, 3, -10, -10))); + uciMenuItem.addActionListener((evt) -> { + String enginePath = JOptionPane.showInputDialog(getParent(), + "Enter the path to a UCI-compatible chess engine:", + "Engine selection", + JOptionPane.QUESTION_MESSAGE); + if (enginePath != null) startGame(Game.createUCI(boardPane, enginePath)); + }); + gameMenu.add(naturalMenuItem); gameMenu.add(aiMenuItem); gameMenu.add(aiVsAiMenuItem); + gameMenu.add(uciMenuItem); add(gameMenu);