- cleaned up networking stuff

- added a state machine to the game
- added a status label
This commit is contained in:
Dorian Zedler 2020-02-25 11:17:17 +01:00
parent 8ae82e9f9a
commit 16a6d49c77
7 changed files with 420 additions and 248 deletions

View file

@ -19,7 +19,9 @@
package de.itsblue.ConnectFour; package de.itsblue.ConnectFour;
import java.awt.*; import java.awt.*;
import java.io.Serializable; import java.awt.event.*;
import java.io.IOException;
import java.io.StringReader;
import javax.swing.*; import javax.swing.*;
@ -27,7 +29,7 @@ import de.itsblue.ConnectFour.Plate.PlateType;
import de.itsblue.ConnectFour.player.Player; import de.itsblue.ConnectFour.player.Player;
import de.itsblue.ConnectFour.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 ControllRow controllRow;
private int player = 0; private int player = 0;
private JLabel statusLabel;
private int currentPlayer = -1;
private int winnerPlayer = -1;
private Player players[] = new Player[2]; private Player players[] = new Player[2];
@ -49,6 +55,12 @@ public class ConnectFour extends JFrame implements PlayerMoveListener {
Local, RemoteServer, RemoteClient Local, RemoteServer, RemoteClient
} }
private GameState gameState = GameState.Idle;
enum GameState {
Idle, Waiting, Running, Over
}
/** /**
* Constructor * Constructor
*/ */
@ -65,12 +77,14 @@ public class ConnectFour extends JFrame implements PlayerMoveListener {
// initialize GameBoard // initialize GameBoard
this.gameBoard = new GameBoard(); this.gameBoard = new GameBoard();
this.gameBoard.addActionListener(this);
// initialize ButtonRow // initialize ButtonRow
this.buttonRow = new ButtonRow(this.gameBoard.getColumns()); this.buttonRow = new ButtonRow(this.gameBoard.getColumns());
// initialize ContollRow // initialize ContollRow
this.controllRow = new ControllRow(this.gameBoard.getColumns()); this.controllRow = new ControllRow(this.gameBoard.getColumns());
this.statusLabel = new JLabel();
// add components to window // add components to window
c.gridx = 0; c.gridx = 0;
@ -85,64 +99,165 @@ public class ConnectFour extends JFrame implements PlayerMoveListener {
c.gridy = 1; c.gridy = 1;
this.add(gameBoard, c); this.add(gameBoard, c);
c.gridy = 2;
this.add(this.statusLabel, c);
// finish up // finish up
this.pack(); this.pack();
this.setVisible(true); this.setVisible(true);
} }
public void startNewGame(GameType type) { public void startNewGame(GameType type) {
if (this.gameState != GameState.Idle)
return;
this.gameType = type; this.gameType = type;
this.setGameState(GameState.Waiting);
switch (type) { switch (type) {
case Local: { case Local: {
this.players[0] = new LocalPlayer(this.buttonRow, PlateType.O); 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] = new LocalPlayer(this.buttonRow, PlateType.X);
this.players[1].addMoveListener(this);
this.player = 0; this.players[0].addActionListener(this);
this.players[player].setIsMyTurn(true); this.players[1].addActionListener(this);
this.currentPlayer = 0;
this.players[this.currentPlayer].setIsMyTurn(true);
break; break;
} }
case RemoteClient: { case RemoteClient: {
this.players[0] = new LocalPlayer(this.buttonRow, null); this.players[0] = new LocalPlayer(this.buttonRow, null);
this.players[1] = new RemotePlayerClient(this.buttonRow, "localhost", this.players[0]);
this.players[0].addMoveListener(this); try {
this.players[1].addMoveListener(this); 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; break;
} }
case RemoteServer: { case RemoteServer: {
this.players[0] = new LocalPlayer(this.buttonRow, PlateType.O); this.players[0] = new LocalPlayer(this.buttonRow, PlateType.O);
try {
this.players[1] = new RemotePlayerServer(this.buttonRow, PlateType.X, this.players[0]); this.players[1] = new RemotePlayerServer(this.buttonRow, PlateType.X, this.players[0]);
} catch (Exception e) {
e.printStackTrace();
}
this.players[0].addMoveListener(this); this.players[0].addActionListener(this);
this.players[1].addMoveListener(this); this.players[1].addActionListener(this);
this.player = 0; this.currentPlayer = 0;
this.players[player].setIsMyTurn(true); this.players[0].setIsMyTurn(true);
this.players[1].setIsMyTurn(false); this.players[1].setIsMyTurn(false);
break; 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() { private void switchPlayer() {
this.players[player].setIsMyTurn(false); this.players[this.currentPlayer].setIsMyTurn(false);
if (player == 0) { if (this.currentPlayer == 0) {
player = 1; this.currentPlayer = 1;
} else { } 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; 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 * Override validate in order to resacle the components when the window is
* rescaled * rescaled
@ -206,9 +298,6 @@ public class ConnectFour extends JFrame implements PlayerMoveListener {
ConnectFour game; ConnectFour game;
System.out.println(game = new ConnectFour()); System.out.println(game = new ConnectFour());
System.out.println("argc: " + args.length);
System.out.println("args[0]: " + args[0]);
if (args.length <= 0) if (args.length <= 0)
game.startNewGame(GameType.Local); game.startNewGame(GameType.Local);
else if (args[0].equals("server")) else if (args[0].equals("server"))

View file

@ -20,6 +20,8 @@ package de.itsblue.ConnectFour;
import javax.swing.*; import javax.swing.*;
import java.awt.*; import java.awt.*;
import java.awt.event.*;
import java.util.ArrayList;
import de.itsblue.ConnectFour.Plate.PlateType; import de.itsblue.ConnectFour.Plate.PlateType;
@ -58,6 +60,16 @@ public class GameBoard extends JPanel {
*/ */
private boolean boardLocked = false; private boolean boardLocked = false;
/**
* An array containing all action listeners
*/
private ArrayList<ActionListener> playerActionListeners = new ArrayList<ActionListener>();
/**
* The current action id
*/
private int currentActionId = 0;
/** /**
* Constructor * Constructor
*/ */
@ -85,11 +97,11 @@ public class GameBoard extends JPanel {
* @return "ok" if the inserton was successfull, "err" if the column is full, * @return "ok" if the inserton was successfull, "err" if the column is full,
* PlateType as string if a plate type has won * 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 // check if the column is out of range
if (column > boardColumns - 1 || this.boardLocked) if (column > boardColumns - 1 || this.boardLocked)
return "err"; return false;
// search for an empty row // search for an empty row
for (int i = boardRows - 1; i >= 0; i--) { 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 // if the container is empty -> add the plate
this.BoardContainers[column][i].insertPlate(plate); this.BoardContainers[column][i].insertPlate(plate);
PlateType winCheckResult = this.checkForWin(); this.checkForResult();
if (winCheckResult == null) return true;
return "ok";
return winCheckResult.toString();
} }
} }
return "err"; return false;
} }
/** /**
@ -169,18 +178,40 @@ public class GameBoard extends JPanel {
* @return <code>null</code> if there was no matching chain; otherwise the * @return <code>null</code> if there was no matching chain; otherwise the
* PlateType of the chain that was found * PlateType of the chain that was found
*/ */
public PlateType checkForWin() { public PlateType checkForResult() {
for (int c = 0; c < this.boardColumns; c++) { for (int c = 0; c < this.boardColumns; c++) {
for (int r = 0; r < this.boardRows; r++) { for (int r = 0; r < this.boardRows; r++) {
PlateType res = this.checkContainerForWin(c, r); PlateType res = this.checkContainerForWin(c, r);
if (res != null) if (res != null) {
this.fireActionListeners("gameOver " + res.toString());
return res; return res;
} }
} }
}
if(this.isFull()) {
this.boardLocked = true;
this.fireActionListeners("gameOver draw");
}
return null; 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 * 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 * 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; 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 * Override paint function to rescale all containers on every repaint
*/ */

View file

@ -21,6 +21,8 @@ package de.itsblue.ConnectFour.player;
import de.itsblue.ConnectFour.Plate.*; import de.itsblue.ConnectFour.Plate.*;
import java.util.ArrayList; import java.util.ArrayList;
import java.awt.event.*;
import java.awt.*;
import de.itsblue.ConnectFour.*; import de.itsblue.ConnectFour.*;
@ -35,22 +37,27 @@ public abstract class Player {
/** /**
* The button row used to control the game. * The button row used to control the game.
*/ */
public ButtonRow gameControllingButtonRow; protected ButtonRow gameControllingButtonRow;
/** /**
* The type of plate the player is using. * 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<PlayerMoveListener> playerMoveListeners = new ArrayList<PlayerMoveListener>(); private ArrayList<ActionListener> playerActionListeners = new ArrayList<ActionListener>();
/**
* The current action id
*/
private int currentActionId = 0;
/** /**
* Whether it is this player's turn * Whether it is this player's turn
*/ */
public boolean isMyTurn = false; protected boolean isMyTurn = false;
/** /**
* Constructor * Constructor
@ -72,6 +79,7 @@ public abstract class Player {
if (isMyTurn) if (isMyTurn)
this.gameControllingButtonRow.setColor(Plate.getColor(this.usingPlateType)); 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 * @param column the column to insert the plate into
*/ */
public void doMove(int column) { protected void doMove(int column) {
if (this.isMyTurn) { if (this.isMyTurn) {
System.out.println("[LOG] " + Plate.getColor(this.usingPlateType) + " is doing a move in col: " + column); this.fireActionListeners("doMove " + column);
for (PlayerMoveListener playerMoveListener : playerMoveListeners) {
playerMoveListener.movePerformed(column, this);
}
} }
} }
/** /**
* 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 * @param listener the listener to add
*/ */
public void addMoveListener(PlayerMoveListener listener) { public void addActionListener(ActionListener listener) {
this.playerMoveListeners.add(listener); this.playerActionListeners.add(listener);
} }
/** /**
* Function to remove a move listener * Function to remove an ActionListener
* *
* @param listener the listener to remove * @param listener the listener to remove
*/ */
public void removeMoveListener(PlayerMoveListener listener) { public void removeMoveListener(ActionListener listener) {
if(this.playerMoveListeners.contains(listener)) if (this.playerActionListeners.contains(listener))
this.playerMoveListeners.remove(listener); this.playerActionListeners.remove(listener);
} }
} }

View file

@ -1,5 +0,0 @@
package de.itsblue.ConnectFour.player;
public abstract interface PlayerMoveListener {
public abstract void movePerformed(int column, Player src);
}

View file

@ -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 <http://www.gnu.org/licenses/>.
*/
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();
}
}
}
}

View file

@ -18,7 +18,6 @@
package de.itsblue.ConnectFour.player; package de.itsblue.ConnectFour.player;
import java.awt.event.*;
import java.util.Scanner; import java.util.Scanner;
import java.io.IOException; import java.io.IOException;
import java.io.PrintWriter; import java.io.PrintWriter;
@ -35,114 +34,39 @@ import de.itsblue.ConnectFour.*;
* *
* @author Dorian Zedler * @author Dorian Zedler
*/ */
public class RemotePlayerClient extends Player implements PlayerMoveListener { public class RemotePlayerClient extends RemotePlayer {
private Socket socket;
private Scanner in;
private PrintWriter out;
private Player opponent;
/** /**
* Constructor * Constructor
* *
* @param controlledByButtonRow The button row used to control the player. * @param controlledByButtonRow The button row used to control the player.
*/ */
public RemotePlayerClient(ButtonRow gameControllingButtonRow, String serverAddress, Player opponent) { public RemotePlayerClient(ButtonRow gameControllingButtonRow, String serverAddress, Player opponent)
super(gameControllingButtonRow, null); throws IOException {
super(gameControllingButtonRow, null, opponent);
this.opponent = opponent; // initialize the socket
opponent.addMoveListener(this);
try {
socket = new Socket(serverAddress, 4444); socket = new Socket(serverAddress, 4444);
in = new Scanner(socket.getInputStream()); in = new Scanner(socket.getInputStream());
out = new PrintWriter(socket.getOutputStream(), true); out = new PrintWriter(socket.getOutputStream(), true);
System.out.println("Connected to Connect4 server"); System.out.println("Connected to Connect4 server");
// get our plate type this.startListening();
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) { public void handleResponse(String response) {
System.out.println("[CLIENT]GOT: " + response); if (response.startsWith("setUsingPlateType")) {
// handle PlateType change
if(response.startsWith("setIsMyTurn")) { 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")); this.setIsMyTurn(response.split(" ")[1].equals("true"));
opponent.setIsMyTurn(response.split(" ")[1].equals("false")); 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])); 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();
}
}
}
} }

View file

@ -18,6 +18,8 @@
package de.itsblue.ConnectFour.player; package de.itsblue.ConnectFour.player;
import java.awt.event.*;
import java.io.IOException; import java.io.IOException;
import java.io.PrintWriter; import java.io.PrintWriter;
import java.net.ServerSocket; import java.net.ServerSocket;
@ -36,14 +38,9 @@ import de.itsblue.ConnectFour.*;
* *
* @author Dorian Zedler * @author Dorian Zedler
*/ */
public class RemotePlayerServer extends Player implements PlayerMoveListener { public class RemotePlayerServer extends RemotePlayer {
private ServerSocket listener; private ServerSocket serverSocket;
private Socket clientSocket;
private Scanner in;
private PrintWriter out;
private Player opponent;
/** /**
* Constructor * Constructor
@ -51,90 +48,41 @@ public class RemotePlayerServer extends Player implements PlayerMoveListener {
* @param controlledByButtonRow The button row used to control the player. * @param controlledByButtonRow The button row used to control the player.
* @param usingPlateType The type of plate the player is using. * @param usingPlateType The type of plate the player is using.
*/ */
public RemotePlayerServer(ButtonRow gameControllingButtonRow, PlateType usingPlateType, Player opponent) { public RemotePlayerServer(ButtonRow gameControllingButtonRow, PlateType usingPlateType, Player opponent)
super(gameControllingButtonRow, usingPlateType); throws Exception {
super(gameControllingButtonRow, usingPlateType, opponent);
this.opponent = opponent; this.serverSocket = new ServerSocket(4444);
opponent.addMoveListener(this);
try {
this.listener = new ServerSocket(4444);
System.out.println("Connect4 Server is Running..."); System.out.println("Connect4 Server is Running...");
this.clientSocket = listener.accept(); this.socket = serverSocket.accept(); // gets stuck here until someone connects
this.in = new Scanner(this.clientSocket.getInputStream()); this.in = new Scanner(this.socket.getInputStream());
this.out = new PrintWriter(this.clientSocket.getOutputStream(), true); this.out = new PrintWriter(this.socket.getOutputStream(), true);
System.out.println("Client connected"); System.out.println("Client connected");
out.println("setUsingPlateType " + this.opponent.usingPlateType.name()); out.println("setUsingPlateType " + this.opponent.usingPlateType.name());
out.println("setIsMyTurn " + (this.opponent.isMyTurn ? "true" : "false")); out.println("setIsMyTurn " + (this.opponent.isMyTurn ? "true" : "false"));
ExecutorService pool = Executors.newFixedThreadPool(200); this.startListening();
pool.execute(this.new ServerListener(in, this));
} catch (Exception e) {
e.printStackTrace();
}
} }
public void handleResponse(String response) { 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])); 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 @Override
public void setIsMyTurn(boolean isMyTurn) { public void actionPerformed(ActionEvent e) {
super.setIsMyTurn(isMyTurn);
if(isMyTurn) super.actionPerformed(e);
this.gameControllingButtonRow.setEnabled(false);
else
this.gameControllingButtonRow.setEnabled(true);
out.println("setIsMyTurn " + (this.isMyTurn ? "false":"true")); if (e.getActionCommand().startsWith("isMyTurnChanged")) {
} out.println("setIsMyTurn " + (e.getActionCommand().split(" ")[1]));
@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();
}
}
}
} }