From 0c972d335c1a4d939633559050092a3a656eef7e Mon Sep 17 00:00:00 2001 From: dorian Date: Tue, 25 Feb 2020 15:34:07 +0100 Subject: [PATCH] Added some checks to the server to enshure that moves of the client are legal --- src/de/itsblue/ConnectFour/ConnectFour.java | 61 ++++++++++++++----- src/de/itsblue/ConnectFour/player/Player.java | 13 ++-- .../ConnectFour/player/RemotePlayer.java | 16 +---- .../player/RemotePlayerClient.java | 41 ++++++++++--- .../player/RemotePlayerServer.java | 48 +++++++++++---- 5 files changed, 124 insertions(+), 55 deletions(-) diff --git a/src/de/itsblue/ConnectFour/ConnectFour.java b/src/de/itsblue/ConnectFour/ConnectFour.java index 4ab6b89..a8df36d 100644 --- a/src/de/itsblue/ConnectFour/ConnectFour.java +++ b/src/de/itsblue/ConnectFour/ConnectFour.java @@ -40,7 +40,6 @@ public class ConnectFour extends JFrame implements ActionListener { private ControllRow controllRow; - private int player = 0; private JLabel statusLabel; private int currentPlayer = -1; @@ -60,6 +59,10 @@ public class ConnectFour extends JFrame implements ActionListener { Idle, Waiting, Running, Over } + enum GameOverReason { + Winner, Draw, OpponentDisconnected, Error + } + /** * Constructor */ @@ -135,7 +138,8 @@ public class ConnectFour extends JFrame implements ActionListener { e.printStackTrace(); } - this.players[0].addActionListener(this); + // do not add the listener of the local player here, as the client player will + // handle its moves in order to make shure they are legal this.players[1].addActionListener(this); break; @@ -164,20 +168,33 @@ public class ConnectFour extends JFrame implements ActionListener { this.setGameState(GameState.Running); } - private void gameOver(String gameOverType) { + private void gameOver(GameOverReason reason, String attributes) { if (!this.gameState.equals(GameState.Running)) return; - 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!"); + if (this.gameType.equals(GameType.RemoteServer)) + ((RemotePlayerServer) this.players[1]).notifyGameOver(reason.toString() + " " + attributes); + + switch (reason) { + case Draw: + this.winnerPlayer = -1; + this.statusLabel.setText("Game over. This was a draw!"); + break; + + case Winner: + PlateType winnerPlateType = PlateType.valueOf(attributes); + 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!"); + + case OpponentDisconnected: + break; + + case Error: + break; } this.setGameState(GameState.Over); @@ -187,6 +204,9 @@ public class ConnectFour extends JFrame implements ActionListener { if (!this.gameState.equals(GameState.Over)) return; + if(this.gameType.equals(GameType.RemoteServer)) + ((RemotePlayerServer) this.players[1]).notifyGameReset(); + this.players[0] = null; this.players[1] = null; this.currentPlayer = -1; @@ -217,6 +237,7 @@ public class ConnectFour extends JFrame implements ActionListener { if (e.getSource() instanceof Player) { Player src = (Player) e.getSource(); if (e.getActionCommand().startsWith("doMove") + // handle moves && (this.gameType == GameType.RemoteClient || this.players[this.currentPlayer].equals(src))) { boolean res = this.gameBoard.insertPlate(new Plate(src.getUsedPlateType()), @@ -229,20 +250,32 @@ public class ConnectFour extends JFrame implements ActionListener { if (this.gameType != GameType.RemoteClient && this.gameState.equals(GameState.Running)) switchPlayer(); + } else if (e.getActionCommand().startsWith("isMyTurnChanged")) { + // handle a turn change + 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!'"); } + + } else if (e.getActionCommand().startsWith("gameReset")) { + if(!this.gameState.equals(GameState.Over)) + this.gameOver(GameOverReason.OpponentDisconnected, ""); + else + this.resetGame(); } } // catch board events if (e.getSource() instanceof GameBoard) { if (e.getActionCommand().startsWith("gameOver")) { - this.gameOver(e.getActionCommand().split(" ")[1]); + if(e.getActionCommand().split(" ")[1].equals("draw")) + this.gameOver(GameOverReason.Draw, ""); + else + this.gameOver(GameOverReason.Winner, e.getActionCommand().split(" ")[1]); } } } diff --git a/src/de/itsblue/ConnectFour/player/Player.java b/src/de/itsblue/ConnectFour/player/Player.java index 567f222..84bf4e0 100644 --- a/src/de/itsblue/ConnectFour/player/Player.java +++ b/src/de/itsblue/ConnectFour/player/Player.java @@ -79,7 +79,7 @@ public abstract class Player { if (isMyTurn) this.gameControllingButtonRow.setColor(Plate.getColor(this.usingPlateType)); - this.fireActionListeners("isMyTurnChanged " + (isMyTurn ? "true" : "false")); + this.fireActionListeners(this,"isMyTurnChanged " + (isMyTurn ? "true" : "false")); } /** @@ -89,7 +89,7 @@ public abstract class Player { */ protected void doMove(int column) { if (this.isMyTurn) { - this.fireActionListeners("doMove " + column); + this.fireActionListeners(this, "doMove " + column); } } @@ -108,8 +108,8 @@ public abstract class Player { * @return player name */ public String getName() { - Color winnerColor = Plate.getColor(this.usingPlateType); - return winnerColor.equals(Color.BLACK) ? "Black":"Red"; + Color thisColor = Plate.getColor(this.usingPlateType); + return thisColor.equals(Color.BLACK) ? "Black":"Red"; } /** @@ -117,10 +117,9 @@ public abstract class Player { * * @param actionCommand The action command to fire the listeners with */ - protected void fireActionListeners(String actionCommand) { + protected void fireActionListeners(Object source, String command) { for (ActionListener playerActionListener : playerActionListeners) { - ActionEvent e = new ActionEvent(this, this.currentActionId, actionCommand); - playerActionListener.actionPerformed(e); + playerActionListener.actionPerformed(new ActionEvent(source, this.currentActionId, command)); this.currentActionId++; } } diff --git a/src/de/itsblue/ConnectFour/player/RemotePlayer.java b/src/de/itsblue/ConnectFour/player/RemotePlayer.java index 5e14b49..32ebda1 100644 --- a/src/de/itsblue/ConnectFour/player/RemotePlayer.java +++ b/src/de/itsblue/ConnectFour/player/RemotePlayer.java @@ -22,7 +22,6 @@ 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; @@ -73,20 +72,7 @@ public abstract class RemotePlayer extends Player implements ActionListener { } @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(); - } - } - } + public abstract void actionPerformed(ActionEvent e); private class SocketListener implements Runnable { RemotePlayer parent; diff --git a/src/de/itsblue/ConnectFour/player/RemotePlayerClient.java b/src/de/itsblue/ConnectFour/player/RemotePlayerClient.java index f48a58e..3ba165d 100644 --- a/src/de/itsblue/ConnectFour/player/RemotePlayerClient.java +++ b/src/de/itsblue/ConnectFour/player/RemotePlayerClient.java @@ -22,8 +22,7 @@ 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 java.awt.event.*; import de.itsblue.ConnectFour.Plate.*; import de.itsblue.ConnectFour.*; @@ -52,21 +51,47 @@ public class RemotePlayerClient extends RemotePlayer { System.out.println("Connected to Connect4 server"); this.startListening(); - } public void handleResponse(String response) { + System.out.println("[SOCKET] Got: " + response); + 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; + this.opponent.usingPlateType = PlateType.valueOf(response.split(" ")[1]); + this.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")); + PlateType targetPlateType = PlateType.valueOf(response.split(" ")[1]); + Player target = this.getUsedPlateType().equals(targetPlateType) ? this:this.opponent; + target.setIsMyTurn(response.split(" ")[2].equals("true")); + } else if (response.startsWith("movePerformed")) { // handle move performed - this.doMove(Integer.parseInt(response.split(" ")[1])); + PlateType targetPlateType = PlateType.valueOf(response.split(" ")[1]); + Player target = this.getUsedPlateType().equals(targetPlateType) ? this:this.opponent; + this.fireActionListeners(target, "doMove " + Integer.parseInt(response.split(" ")[2])); + + } else if(response.startsWith("gameOver") || response.startsWith("gameReset")) { + // handle game over + this.fireActionListeners(this, response); + } + } + + @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("doMove " + column); + System.out.println("[SOCKET] SENT: " + "doMove " + column); + } catch (Exception ex) { + ex.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 b69bf25..4410fa4 100644 --- a/src/de/itsblue/ConnectFour/player/RemotePlayerServer.java +++ b/src/de/itsblue/ConnectFour/player/RemotePlayerServer.java @@ -19,15 +19,10 @@ package de.itsblue.ConnectFour.player; import java.awt.event.*; - 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.*; @@ -52,6 +47,9 @@ public class RemotePlayerServer extends RemotePlayer { throws Exception { super(gameControllingButtonRow, usingPlateType, opponent); + // also catch own actions + this.addActionListener(this); + this.serverSocket = new ServerSocket(4444); System.out.println("Connect4 Server is Running..."); @@ -61,15 +59,31 @@ public class RemotePlayerServer extends RemotePlayer { System.out.println("Client connected"); - out.println("setUsingPlateType " + this.opponent.usingPlateType.name()); - out.println("setIsMyTurn " + (this.opponent.isMyTurn ? "true" : "false")); + out.println("setUsingPlateType " + this.usingPlateType.name()); this.startListening(); } public void handleResponse(String response) { - if (response.startsWith("movePerformed")) { - this.doMove(Integer.parseInt(response.split(" ")[1])); + if (response.startsWith("doMove")) { + if (this.isMyTurn) + this.doMove(Integer.parseInt(response.split(" ")[1])); + else + this.out.println("invalidMove " + response.split(" ")[1]); + } + } + + public void notifyGameOver(String reason) { + this.out.println("gameOver " + reason); + } + + public void notifyGameReset() { + this.out.println("gameReset"); + + try { + this.socket.close(); + } catch (IOException e) { + e.printStackTrace(); } } @@ -79,10 +93,22 @@ public class RemotePlayerServer extends RemotePlayer { @Override public void actionPerformed(ActionEvent e) { - super.actionPerformed(e); + if(!(e.getSource() instanceof Player)) + return; + + Player src = (Player)e.getSource(); + + if (e.getActionCommand().startsWith("doMove")) { + int column = Integer.parseInt(e.getActionCommand().split(" ")[1]); + try { + this.out.println("movePerformed " + src.getUsedPlateType().toString() + " " + column); + } catch (Exception ex) { + ex.printStackTrace(); + } + } if (e.getActionCommand().startsWith("isMyTurnChanged")) { - out.println("setIsMyTurn " + (e.getActionCommand().split(" ")[1])); + out.println("setIsMyTurn " + src.getUsedPlateType().toString() + " " + (e.getActionCommand().split(" ")[1])); } } } \ No newline at end of file