- cleaned up networking stuff
- added a state machine to the game - added a status label
This commit is contained in:
parent
8ae82e9f9a
commit
16a6d49c77
7 changed files with 420 additions and 248 deletions
|
@ -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"))
|
||||||
|
|
|
@ -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
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,5 +0,0 @@
|
||||||
package de.itsblue.ConnectFour.player;
|
|
||||||
|
|
||||||
public abstract interface PlayerMoveListener {
|
|
||||||
public abstract void movePerformed(int column, Player src);
|
|
||||||
}
|
|
116
src/de/itsblue/ConnectFour/player/RemotePlayer.java
Normal file
116
src/de/itsblue/ConnectFour/player/RemotePlayer.java
Normal 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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
|
@ -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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
Reference in a new issue