diff --git a/src/de/itsblue/ConnectFour/ButtonRow.java b/src/de/itsblue/ConnectFour/ButtonRow.java
index b1ed645..299c8f5 100644
--- a/src/de/itsblue/ConnectFour/ButtonRow.java
+++ b/src/de/itsblue/ConnectFour/ButtonRow.java
@@ -113,4 +113,13 @@ public class ButtonRow extends JPanel {
super.paint(g);
}
+
+ @Override
+ public void setEnabled(boolean enabled) {
+ super.setEnabled(enabled);
+
+ for (int i = 0; i < this.buttonCount; i++) {
+ this.inputButtons[i].setEnabled(enabled);
+ }
+ }
}
diff --git a/src/de/itsblue/ConnectFour/ConnectFour.java b/src/de/itsblue/ConnectFour/ConnectFour.java
index 5556ae7..10dc4d5 100644
--- a/src/de/itsblue/ConnectFour/ConnectFour.java
+++ b/src/de/itsblue/ConnectFour/ConnectFour.java
@@ -19,13 +19,15 @@
package de.itsblue.ConnectFour;
import java.awt.*;
+import java.io.Serializable;
+
import javax.swing.*;
import de.itsblue.ConnectFour.Plate.PlateType;
import de.itsblue.ConnectFour.player.Player;
-import de.itsblue.ConnectFour.player.LocalPlayer;
+import de.itsblue.ConnectFour.player.*;
-public class ConnectFour extends JFrame {
+public class ConnectFour extends JFrame implements PlayerMoveListener {
/**
*
*/
@@ -39,6 +41,8 @@ public class ConnectFour extends JFrame {
private Player players[] = new Player[2];
+ private GameType gameType;
+
enum GameType {
Local,
RemoteServer,
@@ -75,50 +79,48 @@ public class ConnectFour extends JFrame {
// finish up
this.pack();
this.setVisible(true);
-
- this.startNewGame(GameType.Local);
}
public void startNewGame(GameType type) {
+ this.gameType = type;
switch (type) {
case Local: {
- this.players[0] = new LocalPlayer(this, this.buttonRow, PlateType.O);
- this.players[1] = new LocalPlayer(this, this.buttonRow, PlateType.X);
+ 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);
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);
- default:
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);
+
+ this.player = 0;
+ this.players[player].setIsMyTurn(true);
+ this.players[1].setIsMyTurn(false);
+
+ break;
+ }
}
}
- /**
- * Function to handle the next plate insertion
- *
- * @param column The column to insert the plate into
- */
- public void insertNextPlate(int column) {
-
- String res;
-
- res = this.gameBoard.insertPlate(new Plate(this.players[player].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);
- }
-
- switchPlayer();
-
- }
-
-
/**
* Function to switch the player
*/
@@ -145,6 +147,29 @@ public class ConnectFour extends JFrame {
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
@@ -167,6 +192,19 @@ public class ConnectFour extends JFrame {
}
public static void main(final String[] args) {
- System.out.println(new ConnectFour());
+ 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"))
+ game.startNewGame(GameType.RemoteServer);
+ else if(args[0].equals("client"))
+ game.startNewGame(GameType.RemoteClient);
+ else
+ System.out.println("Usage: java ConnectFour.java [server|client]");
}
}
\ No newline at end of file
diff --git a/src/de/itsblue/ConnectFour/player/LocalPlayer.java b/src/de/itsblue/ConnectFour/player/LocalPlayer.java
index 67303c0..f42a505 100644
--- a/src/de/itsblue/ConnectFour/player/LocalPlayer.java
+++ b/src/de/itsblue/ConnectFour/player/LocalPlayer.java
@@ -34,14 +34,11 @@ public class LocalPlayer extends Player implements ActionListener {
/**
* Constructor
*
- * @param playingInGame The game the Player is plaing in The funtion
- * insertNextPlate()
of the game will
- * be called when a move is done.
* @param controlledByButtonRow The button row used to control the player.
* @param usingPlateType The type of plate the player is using.
*/
- public LocalPlayer(ConnectFour playingInGame, ButtonRow controlledByButtonRow, PlateType usingPlateType) {
- super(playingInGame, controlledByButtonRow, usingPlateType);
+ public LocalPlayer(ButtonRow controlledByButtonRow, PlateType usingPlateType) {
+ super(controlledByButtonRow, usingPlateType);
}
/**
diff --git a/src/de/itsblue/ConnectFour/player/Player.java b/src/de/itsblue/ConnectFour/player/Player.java
index 8f9d5ef..84ed464 100644
--- a/src/de/itsblue/ConnectFour/player/Player.java
+++ b/src/de/itsblue/ConnectFour/player/Player.java
@@ -19,6 +19,9 @@
package de.itsblue.ConnectFour.player;
import de.itsblue.ConnectFour.Plate.*;
+
+import java.util.ArrayList;
+
import de.itsblue.ConnectFour.*;
/**
@@ -29,12 +32,6 @@ import de.itsblue.ConnectFour.*;
*/
public abstract class Player {
- /**
- * The game the player is playing in. The funtion insertNextPlate()
- * of the game will be called when a move is done.
- */
- private ConnectFour playingInGame;
-
/**
* The button row used to control the game.
*/
@@ -45,6 +42,11 @@ public abstract class Player {
*/
public PlateType usingPlateType;
+ /**
+ * An array containing all move listeners
+ */
+ ArrayList playerMoveListeners = new ArrayList();
+
/**
* Whether it is this player's turn
*/
@@ -53,14 +55,10 @@ public abstract class Player {
/**
* Constructor
*
- * @param playingInGame The game the Player is plaing in The funtion
- * insertNextPlate()
of the game
- * will be called when a move is done.
* @param gameControllingButtonRow The button row used to control the game.
* @param usingPlateType The type of plate the player is using.
*/
- public Player(ConnectFour playingInGame, ButtonRow gameControllingButtonRow, PlateType usingPlateType) {
- this.playingInGame = playingInGame;
+ public Player(ButtonRow gameControllingButtonRow, PlateType usingPlateType) {
this.gameControllingButtonRow = gameControllingButtonRow;
this.usingPlateType = usingPlateType;
}
@@ -82,7 +80,30 @@ public abstract class Player {
* @param column the column to insert the plate into
*/
public void doMove(int column) {
- if (this.isMyTurn)
- this.playingInGame.insertNextPlate(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);
+ }
+ }
+ }
+
+ /**
+ * Function to add a move listener
+ *
+ * @param listener the listener to add
+ */
+ public void addMoveListener(PlayerMoveListener listener) {
+ this.playerMoveListeners.add(listener);
+ }
+
+ /**
+ * Function to remove a move listener
+ *
+ * @param listener the listener to remove
+ */
+ public void removeMoveListener(PlayerMoveListener listener) {
+ if(this.playerMoveListeners.contains(listener))
+ this.playerMoveListeners.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
new file mode 100644
index 0000000..fc30a2c
--- /dev/null
+++ b/src/de/itsblue/ConnectFour/player/PlayerMoveListener.java
@@ -0,0 +1,5 @@
+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/RemotePlayerClient.java b/src/de/itsblue/ConnectFour/player/RemotePlayerClient.java
new file mode 100644
index 0000000..0c96fde
--- /dev/null
+++ b/src/de/itsblue/ConnectFour/player/RemotePlayerClient.java
@@ -0,0 +1,148 @@
+/*
+ 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 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.Plate.*;
+import de.itsblue.ConnectFour.*;
+
+/**
+ * LocalPlayer is a class meant for usage with de.itsblue.ConnectFour. It is
+ * used for a player controlled by the local buttons in the button row.
+ *
+ * @author Dorian Zedler
+ */
+public class RemotePlayerClient extends Player implements PlayerMoveListener {
+
+ private Socket socket;
+ private Scanner in;
+ private PrintWriter out;
+
+ private Player opponent;
+
+ /**
+ * Constructor
+ *
+ * @param controlledByButtonRow The button row used to control the player.
+ */
+ public RemotePlayerClient(ButtonRow gameControllingButtonRow, String serverAddress, Player opponent) {
+ super(gameControllingButtonRow, null);
+
+ this.opponent = opponent;
+ opponent.addMoveListener(this);
+
+ 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();
+ }
+
+ }
+
+ public void handleResponse(String response) {
+ System.out.println("[CLIENT]GOT: " + response);
+
+ if(response.startsWith("setIsMyTurn")) {
+ this.setIsMyTurn(response.split(" ")[1].equals("true"));
+ opponent.setIsMyTurn(response.split(" ")[1].equals("false"));
+ } else if(response.startsWith("movePerformed")) {
+ 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
new file mode 100644
index 0000000..3498d02
--- /dev/null
+++ b/src/de/itsblue/ConnectFour/player/RemotePlayerServer.java
@@ -0,0 +1,140 @@
+/*
+ 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 java.io.IOException;
+import java.io.PrintWriter;
+import java.net.ServerSocket;
+import java.net.Socket;
+import java.util.Arrays;
+import java.util.Scanner;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+
+import de.itsblue.ConnectFour.Plate.*;
+import de.itsblue.ConnectFour.*;
+
+/**
+ * LocalPlayer is a class meant for usage with de.itsblue.ConnectFour. It is
+ * used for a player controlled by the local buttons in the button row.
+ *
+ * @author Dorian Zedler
+ */
+public class RemotePlayerServer extends Player implements PlayerMoveListener {
+
+ private ServerSocket listener;
+ private Socket clientSocket;
+ private Scanner in;
+ private PrintWriter out;
+
+ private Player opponent;
+
+ /**
+ * Constructor
+ *
+ * @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);
+
+ this.opponent = opponent;
+ opponent.addMoveListener(this);
+
+ try {
+ this.listener = new ServerSocket(4444);
+ System.out.println("Connect4 Server is Running...");
+
+ this.clientSocket = listener.accept();
+ this.in = new Scanner(this.clientSocket.getInputStream());
+ this.out = new PrintWriter(this.clientSocket.getOutputStream(), true);
+
+ System.out.println("Client connected");
+
+ 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();
+ }
+ }
+
+ public void handleResponse(String response) {
+ System.out.println("GOT: " + response);
+ if(response.startsWith("movePerformed")) {
+ 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);
+
+ 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();
+ }
+ }
+
+ 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