From 16a6d49c77a6fc27113a7574ad3c2d09d8ce8bd6 Mon Sep 17 00:00:00 2001 From: dorian Date: Tue, 25 Feb 2020 11:17:17 +0100 Subject: [PATCH] - cleaned up networking stuff - added a state machine to the game - added a status label --- src/de/itsblue/ConnectFour/ConnectFour.java | 181 +++++++++++++----- src/de/itsblue/ConnectFour/GameBoard.java | 83 +++++++- src/de/itsblue/ConnectFour/player/Player.java | 75 ++++++-- .../player/PlayerMoveListener.java | 5 - .../ConnectFour/player/RemotePlayer.java | 116 +++++++++++ .../player/RemotePlayerClient.java | 112 ++--------- .../player/RemotePlayerServer.java | 96 +++------- 7 files changed, 420 insertions(+), 248 deletions(-) delete mode 100644 src/de/itsblue/ConnectFour/player/PlayerMoveListener.java create mode 100644 src/de/itsblue/ConnectFour/player/RemotePlayer.java diff --git a/src/de/itsblue/ConnectFour/ConnectFour.java b/src/de/itsblue/ConnectFour/ConnectFour.java index 706fdc8..88bea31 100644 --- a/src/de/itsblue/ConnectFour/ConnectFour.java +++ b/src/de/itsblue/ConnectFour/ConnectFour.java @@ -19,7 +19,9 @@ package de.itsblue.ConnectFour; import java.awt.*; -import java.io.Serializable; +import java.awt.event.*; +import java.io.IOException; +import java.io.StringReader; import javax.swing.*; @@ -27,7 +29,7 @@ import de.itsblue.ConnectFour.Plate.PlateType; import de.itsblue.ConnectFour.player.Player; import de.itsblue.ConnectFour.player.*; -public class ConnectFour extends JFrame implements PlayerMoveListener { +public class ConnectFour extends JFrame implements ActionListener { /** * */ @@ -40,6 +42,10 @@ public class ConnectFour extends JFrame implements PlayerMoveListener { private ControllRow controllRow; private int player = 0; + private JLabel statusLabel; + + private int currentPlayer = -1; + private int winnerPlayer = -1; private Player players[] = new Player[2]; @@ -49,6 +55,12 @@ public class ConnectFour extends JFrame implements PlayerMoveListener { Local, RemoteServer, RemoteClient } + private GameState gameState = GameState.Idle; + + enum GameState { + Idle, Waiting, Running, Over + } + /** * Constructor */ @@ -65,12 +77,14 @@ public class ConnectFour extends JFrame implements PlayerMoveListener { // initialize GameBoard this.gameBoard = new GameBoard(); + this.gameBoard.addActionListener(this); // initialize ButtonRow this.buttonRow = new ButtonRow(this.gameBoard.getColumns()); // initialize ContollRow this.controllRow = new ControllRow(this.gameBoard.getColumns()); + this.statusLabel = new JLabel(); // add components to window c.gridx = 0; @@ -85,64 +99,165 @@ public class ConnectFour extends JFrame implements PlayerMoveListener { c.gridy = 1; this.add(gameBoard, c); + c.gridy = 2; + this.add(this.statusLabel, c); + // finish up this.pack(); this.setVisible(true); } public void startNewGame(GameType type) { + if (this.gameState != GameState.Idle) + return; + this.gameType = type; + + this.setGameState(GameState.Waiting); switch (type) { case Local: { this.players[0] = new LocalPlayer(this.buttonRow, PlateType.O); - this.players[0].addMoveListener(this); this.players[1] = new LocalPlayer(this.buttonRow, PlateType.X); - this.players[1].addMoveListener(this); - this.player = 0; - this.players[player].setIsMyTurn(true); + this.players[0].addActionListener(this); + this.players[1].addActionListener(this); + + this.currentPlayer = 0; + this.players[this.currentPlayer].setIsMyTurn(true); break; } case RemoteClient: { this.players[0] = new LocalPlayer(this.buttonRow, null); - this.players[1] = new RemotePlayerClient(this.buttonRow, "localhost", this.players[0]); - this.players[0].addMoveListener(this); - this.players[1].addMoveListener(this); + try { + this.players[1] = new RemotePlayerClient(this.buttonRow, "localhost", this.players[0]); + } catch (IOException e) { + e.printStackTrace(); + } + + this.players[0].addActionListener(this); + this.players[1].addActionListener(this); break; } case RemoteServer: { this.players[0] = new LocalPlayer(this.buttonRow, PlateType.O); - this.players[1] = new RemotePlayerServer(this.buttonRow, PlateType.X, this.players[0]); - this.players[0].addMoveListener(this); - this.players[1].addMoveListener(this); + try { + this.players[1] = new RemotePlayerServer(this.buttonRow, PlateType.X, this.players[0]); + } catch (Exception e) { + e.printStackTrace(); + } - this.player = 0; - this.players[player].setIsMyTurn(true); + this.players[0].addActionListener(this); + this.players[1].addActionListener(this); + + this.currentPlayer = 0; + this.players[0].setIsMyTurn(true); this.players[1].setIsMyTurn(false); break; } } + + this.setGameState(GameState.Running); + } + + private void gameOver(String gameOverType) { + if (gameOverType.equals("draw")) { + this.winnerPlayer = -1; + this.statusLabel.setText("Game over. This was a draw!"); + } else { + PlateType winnerPlateType = PlateType.valueOf(gameOverType); + this.winnerPlayer = this.players[0].getUsedPlateType().equals(winnerPlateType) ? 0 : 1; + if(!this.gameType.equals(GameType.Local) && this.players[this.winnerPlayer] instanceof LocalPlayer) + this.statusLabel.setText("Game over. You won the game!"); + else + this.statusLabel.setText("Game over. " + this.players[this.winnerPlayer].getName() + " won the game!"); + } + + this.setGameState(GameState.Over); } /** - * Function to switch the player + * Function to switch the current player */ private void switchPlayer() { - this.players[player].setIsMyTurn(false); + this.players[this.currentPlayer].setIsMyTurn(false); - if (player == 0) { - player = 1; + if (this.currentPlayer == 0) { + this.currentPlayer = 1; } else { - player = 0; + this.currentPlayer = 0; } - this.players[player].setIsMyTurn(true); + this.players[this.currentPlayer].setIsMyTurn(true); + } + + @Override + public void actionPerformed(ActionEvent e) { + + // catch player moves + if (e.getSource() instanceof Player) { + Player src = (Player) e.getSource(); + if (e.getActionCommand().startsWith("doMove") + && (this.gameType == GameType.RemoteClient || this.players[this.currentPlayer].equals(src))) { + + boolean res = this.gameBoard.insertPlate(new Plate(src.getUsedPlateType()), + Integer.parseInt(e.getActionCommand().split(" ")[1])); + + if (!res) { + // beep in case of error + Toolkit.getDefaultToolkit().beep(); + } + + if (this.gameType != GameType.RemoteClient && this.gameState.equals(GameState.Running)) + switchPlayer(); + } else if (e.getActionCommand().startsWith("isMyTurnChanged")) { + if(e.getActionCommand().split(" ")[1].equals("true")) { + if(!this.gameType.equals(GameType.Local) && src instanceof LocalPlayer) + this.statusLabel.setText("Running, it's your turn!'"); + else + this.statusLabel.setText("Running, it's " + src.getName() + "'s turn!'"); + } + } + } + + // catch board events + if (e.getSource() instanceof GameBoard) { + if (e.getActionCommand().startsWith("gameOver")) { + this.gameOver(e.getActionCommand().split(" ")[1]); + } + } + } + + public void setGameState(GameState newState) { + this.gameState = newState; + + switch (this.gameState) { + case Idle: + this.statusLabel.setText("IDLE"); + this.buttonRow.setEnabled(false); + break; + + case Waiting: + this.statusLabel.setText("Waiting for opponent to connect"); + this.buttonRow.setEnabled(false); + break; + + case Running: + this.buttonRow.setEnabled(true); + break; + + case Over: + this.buttonRow.setEnabled(false); + break; + + default: + break; + } } /** @@ -155,29 +270,6 @@ public class ConnectFour extends JFrame implements PlayerMoveListener { return this.getSize().height < this.getSize().width; } - /** - * Catch player moves - */ - @Override - public void movePerformed(int column, Player src) { - if (this.players[this.player].equals(src) || this.gameType == GameType.RemoteClient) { - String res; - - res = this.gameBoard.insertPlate(new Plate(src.usingPlateType), column); - - if (res == "err") { - // beep in case of error - Toolkit.getDefaultToolkit().beep(); - } else if (res != "ok" && res != "err") { - PlateType winnerType = PlateType.valueOf(res); - System.out.println("A player won: " + winnerType); - } - - if (this.gameType != GameType.RemoteClient) - switchPlayer(); - } - } - /** * Override validate in order to resacle the components when the window is * rescaled @@ -206,9 +298,6 @@ public class ConnectFour extends JFrame implements PlayerMoveListener { ConnectFour game; System.out.println(game = new ConnectFour()); - System.out.println("argc: " + args.length); - System.out.println("args[0]: " + args[0]); - if (args.length <= 0) game.startNewGame(GameType.Local); else if (args[0].equals("server")) diff --git a/src/de/itsblue/ConnectFour/GameBoard.java b/src/de/itsblue/ConnectFour/GameBoard.java index 54490b9..c42d70b 100644 --- a/src/de/itsblue/ConnectFour/GameBoard.java +++ b/src/de/itsblue/ConnectFour/GameBoard.java @@ -20,6 +20,8 @@ package de.itsblue.ConnectFour; import javax.swing.*; import java.awt.*; +import java.awt.event.*; +import java.util.ArrayList; import de.itsblue.ConnectFour.Plate.PlateType; @@ -58,6 +60,16 @@ public class GameBoard extends JPanel { */ private boolean boardLocked = false; + /** + * An array containing all action listeners + */ + private ArrayList playerActionListeners = new ArrayList(); + + /** + * The current action id + */ + private int currentActionId = 0; + /** * Constructor */ @@ -85,11 +97,11 @@ public class GameBoard extends JPanel { * @return "ok" if the inserton was successfull, "err" if the column is full, * PlateType as string if a plate type has won */ - public String insertPlate(Plate plate, int column) { + public boolean insertPlate(Plate plate, int column) { // check if the column is out of range if (column > boardColumns - 1 || this.boardLocked) - return "err"; + return false; // search for an empty row for (int i = boardRows - 1; i >= 0; i--) { @@ -97,16 +109,13 @@ public class GameBoard extends JPanel { // if the container is empty -> add the plate this.BoardContainers[column][i].insertPlate(plate); - PlateType winCheckResult = this.checkForWin(); + this.checkForResult(); - if (winCheckResult == null) - return "ok"; - - return winCheckResult.toString(); + return true; } } - return "err"; + return false; } /** @@ -169,18 +178,40 @@ public class GameBoard extends JPanel { * @return null if there was no matching chain; otherwise the * PlateType of the chain that was found */ - public PlateType checkForWin() { + public PlateType checkForResult() { for (int c = 0; c < this.boardColumns; c++) { for (int r = 0; r < this.boardRows; r++) { PlateType res = this.checkContainerForWin(c, r); - if (res != null) + if (res != null) { + this.fireActionListeners("gameOver " + res.toString()); return res; + } } } + if(this.isFull()) { + this.boardLocked = true; + this.fireActionListeners("gameOver draw"); + } + return null; } + public boolean isFull() { + boolean allContainersOccupied = true; + + for (int c = 0; c < this.boardColumns; c++) { + for (int r = 0; r < this.boardRows; r++) { + if(!this.getPlateContainer(c, r).containsPlate()) { + allContainersOccupied = false; + break; + } + } + } + + return allContainersOccupied; + } + /** * Function to check if a certain container is the beginning of a four plate log * chain of plates of the same type what would indicate the end of the game. If @@ -325,6 +356,38 @@ public class GameBoard extends JPanel { return this.boardRows; } + /** + * Function to fire all actionListeners with a given action command + * + * @param actionCommand The action command to fire the listeners with + */ + protected void fireActionListeners(String actionCommand) { + for (ActionListener playerActionListener : playerActionListeners) { + ActionEvent e = new ActionEvent(this, this.currentActionId, actionCommand); + playerActionListener.actionPerformed(e); + this.currentActionId++; + } + } + + /** + * Function to add an ActionListener + * + * @param listener the listener to add + */ + public void addActionListener(ActionListener listener) { + this.playerActionListeners.add(listener); + } + + /** + * Function to remove an ActionListener + * + * @param listener the listener to remove + */ + public void removeMoveListener(ActionListener listener) { + if (this.playerActionListeners.contains(listener)) + this.playerActionListeners.remove(listener); + } + /** * Override paint function to rescale all containers on every repaint */ diff --git a/src/de/itsblue/ConnectFour/player/Player.java b/src/de/itsblue/ConnectFour/player/Player.java index 84ed464..567f222 100644 --- a/src/de/itsblue/ConnectFour/player/Player.java +++ b/src/de/itsblue/ConnectFour/player/Player.java @@ -21,6 +21,8 @@ package de.itsblue.ConnectFour.player; import de.itsblue.ConnectFour.Plate.*; import java.util.ArrayList; +import java.awt.event.*; +import java.awt.*; import de.itsblue.ConnectFour.*; @@ -35,22 +37,27 @@ public abstract class Player { /** * The button row used to control the game. */ - public ButtonRow gameControllingButtonRow; + protected ButtonRow gameControllingButtonRow; /** * The type of plate the player is using. */ - public PlateType usingPlateType; + protected PlateType usingPlateType; /** - * An array containing all move listeners + * An array containing all action listeners */ - ArrayList playerMoveListeners = new ArrayList(); + private ArrayList playerActionListeners = new ArrayList(); + + /** + * The current action id + */ + private int currentActionId = 0; /** * Whether it is this player's turn */ - public boolean isMyTurn = false; + protected boolean isMyTurn = false; /** * Constructor @@ -72,6 +79,7 @@ public abstract class Player { if (isMyTurn) this.gameControllingButtonRow.setColor(Plate.getColor(this.usingPlateType)); + this.fireActionListeners("isMyTurnChanged " + (isMyTurn ? "true" : "false")); } /** @@ -79,31 +87,60 @@ public abstract class Player { * * @param column the column to insert the plate into */ - public void doMove(int column) { - if (this.isMyTurn){ - System.out.println("[LOG] " + Plate.getColor(this.usingPlateType) + " is doing a move in col: " + column); - for (PlayerMoveListener playerMoveListener : playerMoveListeners) { - playerMoveListener.movePerformed(column, this); - } + protected void doMove(int column) { + if (this.isMyTurn) { + this.fireActionListeners("doMove " + column); } } /** - * Function to add a move listener + * Function to get the plate type used by the player + * + * @return used plate type + */ + public PlateType getUsedPlateType() { + return this.usingPlateType; + } + + /** + * Function to get the name of the player + * + * @return player name + */ + public String getName() { + Color winnerColor = Plate.getColor(this.usingPlateType); + return winnerColor.equals(Color.BLACK) ? "Black":"Red"; + } + + /** + * Function to fire all actionListeners with a given action command + * + * @param actionCommand The action command to fire the listeners with + */ + protected void fireActionListeners(String actionCommand) { + for (ActionListener playerActionListener : playerActionListeners) { + ActionEvent e = new ActionEvent(this, this.currentActionId, actionCommand); + playerActionListener.actionPerformed(e); + this.currentActionId++; + } + } + + /** + * Function to add an ActionListener * * @param listener the listener to add */ - public void addMoveListener(PlayerMoveListener listener) { - this.playerMoveListeners.add(listener); + public void addActionListener(ActionListener listener) { + this.playerActionListeners.add(listener); } - /** - * Function to remove a move listener + /** + * Function to remove an ActionListener * * @param listener the listener to remove */ - public void removeMoveListener(PlayerMoveListener listener) { - if(this.playerMoveListeners.contains(listener)) - this.playerMoveListeners.remove(listener); + public void removeMoveListener(ActionListener listener) { + if (this.playerActionListeners.contains(listener)) + this.playerActionListeners.remove(listener); } } \ No newline at end of file diff --git a/src/de/itsblue/ConnectFour/player/PlayerMoveListener.java b/src/de/itsblue/ConnectFour/player/PlayerMoveListener.java deleted file mode 100644 index fc30a2c..0000000 --- a/src/de/itsblue/ConnectFour/player/PlayerMoveListener.java +++ /dev/null @@ -1,5 +0,0 @@ -package de.itsblue.ConnectFour.player; - -public abstract interface PlayerMoveListener { - public abstract void movePerformed(int column, Player src); -} \ No newline at end of file diff --git a/src/de/itsblue/ConnectFour/player/RemotePlayer.java b/src/de/itsblue/ConnectFour/player/RemotePlayer.java new file mode 100644 index 0000000..5e14b49 --- /dev/null +++ b/src/de/itsblue/ConnectFour/player/RemotePlayer.java @@ -0,0 +1,116 @@ +/* + Connect four - written in java + Copyright (C) 2020 Oliver Schappacher and Dorian Zedler + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +package de.itsblue.ConnectFour.player; + +import de.itsblue.ConnectFour.Plate.*; + +import java.awt.event.*; +import java.util.Scanner; +import java.io.IOException; +import java.io.PrintWriter; +import java.net.Socket; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + +import de.itsblue.ConnectFour.*; + +/** + * Player is an abstract class meant for usage with de.itsblue.ConnectFour. It + * is a template for a connect four player. + * + * @author Dorian Zedler + */ +public abstract class RemotePlayer extends Player implements ActionListener { + + protected Socket socket; + protected Scanner in; + protected PrintWriter out; + + protected Player opponent; + + public RemotePlayer(ButtonRow gameControllingButtonRow, PlateType usingPlateType, Player opponent) { + super(gameControllingButtonRow, usingPlateType); + this.opponent = opponent; + opponent.addActionListener(this); + } + + protected void startListening() { + // listen to the socket + ExecutorService pool = Executors.newFixedThreadPool(200); + pool.execute(this.new SocketListener(this.in, this)); + } + + protected abstract void handleResponse(String response); + + /** + * Function to set wether it is this player's turn + */ + @Override + public void setIsMyTurn(boolean isMyTurn) { + super.setIsMyTurn(isMyTurn); + + if (isMyTurn) + this.gameControllingButtonRow.setEnabled(false); + else + this.gameControllingButtonRow.setEnabled(true); + + } + + @Override + public void actionPerformed(ActionEvent e) { + + if(!(e.getSource() instanceof Player)) + return; + + if (e.getActionCommand().startsWith("doMove")) { + int column = Integer.parseInt(e.getActionCommand().split(" ")[1]); + try { + this.out.println("movePerformed " + column); + } catch (Exception ex) { + ex.printStackTrace(); + } + } + } + + private class SocketListener implements Runnable { + RemotePlayer parent; + Scanner in; + + public SocketListener(Scanner in, RemotePlayer parent) { + this.parent = parent; + this.in = in; + } + + @Override + public void run() { + // listen to the socket + try { + while (in.hasNextLine()) { + String response = in.nextLine(); + + this.parent.handleResponse(response); + + } + out.println("QUIT"); + } catch (Exception e) { + e.printStackTrace(); + } + } + } +} \ No newline at end of file diff --git a/src/de/itsblue/ConnectFour/player/RemotePlayerClient.java b/src/de/itsblue/ConnectFour/player/RemotePlayerClient.java index 0c96fde..f48a58e 100644 --- a/src/de/itsblue/ConnectFour/player/RemotePlayerClient.java +++ b/src/de/itsblue/ConnectFour/player/RemotePlayerClient.java @@ -18,7 +18,6 @@ package de.itsblue.ConnectFour.player; -import java.awt.event.*; import java.util.Scanner; import java.io.IOException; import java.io.PrintWriter; @@ -35,114 +34,39 @@ import de.itsblue.ConnectFour.*; * * @author Dorian Zedler */ -public class RemotePlayerClient extends Player implements PlayerMoveListener { - - private Socket socket; - private Scanner in; - private PrintWriter out; - - private Player opponent; +public class RemotePlayerClient extends RemotePlayer { /** * Constructor * * @param controlledByButtonRow The button row used to control the player. */ - public RemotePlayerClient(ButtonRow gameControllingButtonRow, String serverAddress, Player opponent) { - super(gameControllingButtonRow, null); + public RemotePlayerClient(ButtonRow gameControllingButtonRow, String serverAddress, Player opponent) + throws IOException { + super(gameControllingButtonRow, null, opponent); - this.opponent = opponent; - opponent.addMoveListener(this); + // initialize the socket + socket = new Socket(serverAddress, 4444); + in = new Scanner(socket.getInputStream()); + out = new PrintWriter(socket.getOutputStream(), true); + System.out.println("Connected to Connect4 server"); - try { - socket = new Socket(serverAddress, 4444); - in = new Scanner(socket.getInputStream()); - out = new PrintWriter(socket.getOutputStream(), true); - System.out.println("Connected to Connect4 server"); - - // get our plate type - String response = in.nextLine(); - if (response.split(" ")[0].equals("setUsingPlateType")) { - this.usingPlateType = PlateType.valueOf(response.split(" ")[1]); - this.opponent.usingPlateType = this.usingPlateType.equals(PlateType.O) ? PlateType.X : PlateType.O; - } - - // check if it is out turn - response = in.nextLine(); - if (response.split(" ")[0].equals("setIsMyTurn")) { - this.setIsMyTurn(response.split(" ")[1].equals("true")); - opponent.setIsMyTurn(response.split(" ")[1].equals("false")); - } - - // listen to the socket - ExecutorService pool = Executors.newFixedThreadPool(200); - pool.execute(this.new ClientListener(in, this)); - - } catch (IOException e) { - e.printStackTrace(); - } + this.startListening(); } public void handleResponse(String response) { - System.out.println("[CLIENT]GOT: " + response); - - if(response.startsWith("setIsMyTurn")) { + if (response.startsWith("setUsingPlateType")) { + // handle PlateType change + this.usingPlateType = PlateType.valueOf(response.split(" ")[1]); + this.opponent.usingPlateType = this.usingPlateType == PlateType.O ? PlateType.X : PlateType.O; + } else if (response.startsWith("setIsMyTurn")) { + // handle turn change this.setIsMyTurn(response.split(" ")[1].equals("true")); opponent.setIsMyTurn(response.split(" ")[1].equals("false")); - } else if(response.startsWith("movePerformed")) { + } else if (response.startsWith("movePerformed")) { + // handle move performed this.doMove(Integer.parseInt(response.split(" ")[1])); } } - - /** - * Function to set wether it is this player's turn - */ - @Override - public void setIsMyTurn(boolean isMyTurn) { - super.setIsMyTurn(isMyTurn); - - if (isMyTurn) - this.gameControllingButtonRow.setEnabled(false); - else - this.gameControllingButtonRow.setEnabled(true); - - } - - @Override - public void movePerformed(int column, Player src) { - try { - this.out.println("movePerformed " + column); - } catch (Exception e) { - e.printStackTrace(); - } - } - - class ClientListener implements Runnable { - - RemotePlayerClient parent; - Scanner in; - - public ClientListener(Scanner in, RemotePlayerClient parent) { - this.parent = parent; - this.in = in; - } - - @Override - public void run() { - // listen to the socket - try { - while (in.hasNextLine()) { - String response = in.nextLine(); - - this.parent.handleResponse(response); - - } - out.println("QUIT"); - } catch (Exception e) { - e.printStackTrace(); - } - } - - } } \ No newline at end of file diff --git a/src/de/itsblue/ConnectFour/player/RemotePlayerServer.java b/src/de/itsblue/ConnectFour/player/RemotePlayerServer.java index 3498d02..b69bf25 100644 --- a/src/de/itsblue/ConnectFour/player/RemotePlayerServer.java +++ b/src/de/itsblue/ConnectFour/player/RemotePlayerServer.java @@ -18,6 +18,8 @@ package de.itsblue.ConnectFour.player; +import java.awt.event.*; + import java.io.IOException; import java.io.PrintWriter; import java.net.ServerSocket; @@ -36,14 +38,9 @@ import de.itsblue.ConnectFour.*; * * @author Dorian Zedler */ -public class RemotePlayerServer extends Player implements PlayerMoveListener { +public class RemotePlayerServer extends RemotePlayer { - private ServerSocket listener; - private Socket clientSocket; - private Scanner in; - private PrintWriter out; - - private Player opponent; + private ServerSocket serverSocket; /** * Constructor @@ -51,90 +48,41 @@ public class RemotePlayerServer extends Player implements PlayerMoveListener { * @param controlledByButtonRow The button row used to control the player. * @param usingPlateType The type of plate the player is using. */ - public RemotePlayerServer(ButtonRow gameControllingButtonRow, PlateType usingPlateType, Player opponent) { - super(gameControllingButtonRow, usingPlateType); + public RemotePlayerServer(ButtonRow gameControllingButtonRow, PlateType usingPlateType, Player opponent) + throws Exception { + super(gameControllingButtonRow, usingPlateType, opponent); - this.opponent = opponent; - opponent.addMoveListener(this); + this.serverSocket = new ServerSocket(4444); + System.out.println("Connect4 Server is Running..."); - try { - this.listener = new ServerSocket(4444); - System.out.println("Connect4 Server is Running..."); + this.socket = serverSocket.accept(); // gets stuck here until someone connects + this.in = new Scanner(this.socket.getInputStream()); + this.out = new PrintWriter(this.socket.getOutputStream(), true); - this.clientSocket = listener.accept(); - this.in = new Scanner(this.clientSocket.getInputStream()); - this.out = new PrintWriter(this.clientSocket.getOutputStream(), true); + System.out.println("Client connected"); - System.out.println("Client connected"); + out.println("setUsingPlateType " + this.opponent.usingPlateType.name()); + out.println("setIsMyTurn " + (this.opponent.isMyTurn ? "true" : "false")); - out.println("setUsingPlateType " + this.opponent.usingPlateType.name()); - out.println("setIsMyTurn " + (this.opponent.isMyTurn ? "true":"false")); - - ExecutorService pool = Executors.newFixedThreadPool(200); - pool.execute(this.new ServerListener(in, this)); - - } catch (Exception e) { - e.printStackTrace(); - } + this.startListening(); } public void handleResponse(String response) { - System.out.println("GOT: " + response); - if(response.startsWith("movePerformed")) { + if (response.startsWith("movePerformed")) { this.doMove(Integer.parseInt(response.split(" ")[1])); } } /** - * Function to set wether it is this player's turn + * Catch actions of opponent and forward them to client */ @Override - public void setIsMyTurn(boolean isMyTurn) { - super.setIsMyTurn(isMyTurn); + public void actionPerformed(ActionEvent e) { - if(isMyTurn) - this.gameControllingButtonRow.setEnabled(false); - else - this.gameControllingButtonRow.setEnabled(true); + super.actionPerformed(e); - out.println("setIsMyTurn " + (this.isMyTurn ? "false":"true")); - } - - @Override - public void movePerformed(int column, Player src) { - System.out.println("movePerformed"); - try { - this.out.println("movePerformed " + column); - } catch (Exception e) { - e.printStackTrace(); + if (e.getActionCommand().startsWith("isMyTurnChanged")) { + out.println("setIsMyTurn " + (e.getActionCommand().split(" ")[1])); } } - - class ServerListener implements Runnable { - - RemotePlayerServer parent; - Scanner in; - - public ServerListener(Scanner in, RemotePlayerServer parent) { - this.parent = parent; - this.in = in; - } - - @Override - public void run() { - // listen to the socket - try { - while (in.hasNextLine()) { - String response = in.nextLine(); - - this.parent.handleResponse(response); - - } - out.println("QUIT"); - } catch (Exception e) { - e.printStackTrace(); - } - } - - } } \ No newline at end of file