From 20732e730cdc9b0860a63b783dc117fefdfd2b8c Mon Sep 17 00:00:00 2001 From: Luca Conte Date: Fri, 20 Dec 2024 17:31:16 +0100 Subject: [PATCH 01/13] some cleanup --- src/HumanPlayer.java | 6 +++++- src/LocalPlayer.java | 9 +++++++-- src/OnlinePlayer.java | 6 ++++++ src/OnlinePlayer_1_1_0.java | 6 ++++-- src/Player.java | 7 +++++++ 5 files changed, 29 insertions(+), 5 deletions(-) diff --git a/src/HumanPlayer.java b/src/HumanPlayer.java index ae0e298..4dfdbe1 100644 --- a/src/HumanPlayer.java +++ b/src/HumanPlayer.java @@ -1,4 +1,8 @@ public class HumanPlayer extends LocalPlayer { - + @Override + public void shoot(Point point) { + this.myTurn = false; + enemy.receiveShoot(point); + } } diff --git a/src/LocalPlayer.java b/src/LocalPlayer.java index f3e434b..ab19f20 100644 --- a/src/LocalPlayer.java +++ b/src/LocalPlayer.java @@ -10,6 +10,8 @@ public class LocalPlayer extends Player { @Override public synchronized void receiveShoot(Point point) { + if (!this.enemy.myTurn) return; + HitResponse hitResponse = board.getHitResponseOnPoint(point); if (!(hitResponse == null)){ enemy.receiveHit(hitResponse); @@ -46,10 +48,13 @@ public class LocalPlayer extends Player { } } + /** + * sends shot to enemy player. + * should ONLY be called on HumanPlayer + */ @Override public void shoot(Point point){ - this.myTurn = false; - enemy.receiveShoot(point); + return; } @Override diff --git a/src/OnlinePlayer.java b/src/OnlinePlayer.java index 14f3edb..4f0d56b 100644 --- a/src/OnlinePlayer.java +++ b/src/OnlinePlayer.java @@ -25,4 +25,10 @@ public abstract class OnlinePlayer extends Player implements AsyncSocketListener @Override public abstract void receiveCoin(boolean coin); + @Override + public void destroy() { + super.destroy(); + this.socket.close(); + } + } diff --git a/src/OnlinePlayer_1_1_0.java b/src/OnlinePlayer_1_1_0.java index a9b513d..eab7f1e 100644 --- a/src/OnlinePlayer_1_1_0.java +++ b/src/OnlinePlayer_1_1_0.java @@ -34,8 +34,8 @@ public class OnlinePlayer_1_1_0 extends OnlinePlayer { case "COIN": if(!this.hasReceivedCoinPackage && (p.getData().equals("1") || p.getData().equals("0"))){ this.myCoin = p.getData().equals("1"); - this.ready(); this.hasReceivedCoinPackage = true; + this.ready(); } break; @@ -75,6 +75,7 @@ public class OnlinePlayer_1_1_0 extends OnlinePlayer { @Override public synchronized void receiveShoot(Point point){ + if (!this.enemy.myTurn) return; super.socket.send(new SocketPackage("SHOOT",point.toString())); } @@ -94,6 +95,7 @@ public class OnlinePlayer_1_1_0 extends OnlinePlayer { @Override public synchronized void shoot(Point point) { - super.socket.send(new SocketPackage("SHOOT", point.toString())); + // SHOULD NEVER BE CALLED ON ONLINE PLAYER. ONLY ON HUMAN PLAYER + return; } } \ No newline at end of file diff --git a/src/Player.java b/src/Player.java index f36702d..5ea7ba7 100644 --- a/src/Player.java +++ b/src/Player.java @@ -77,4 +77,11 @@ public abstract class Player { public boolean isReady() { return this.sentCoin; } + + public void destroy() { + this.myTurn = false; + this.gameRunning = false; + this.board = null; + this.enemy = null; + } } From 65451d6912b9a11eac523b39483472ca307335e3 Mon Sep 17 00:00:00 2001 From: Luca Conte Date: Fri, 20 Dec 2024 17:55:38 +0100 Subject: [PATCH 02/13] destroy for AI Player --- src/AiPlayer.java | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/AiPlayer.java b/src/AiPlayer.java index 724233c..d51e41e 100644 --- a/src/AiPlayer.java +++ b/src/AiPlayer.java @@ -35,6 +35,7 @@ public abstract class AiPlayer extends LocalPlayer implements Runnable { } public void aiShoot() { + if (!this.myTurn) return; this.enemy.receiveShoot(RandomPoint()); return; } @@ -93,4 +94,20 @@ public abstract class AiPlayer extends LocalPlayer implements Runnable { this.aiShoot(); } + + @Override + public void destroy() { + super.destroy(); + Iterator i = this.shootThreads.iterator(); + while(i.hasNext()) { + Thread thread = i.next(); + try { + thread.join(); + i.remove(); + } catch (InterruptedException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + } } \ No newline at end of file From b7215db6d98a3d703898c0d67eb1552736af4f66 Mon Sep 17 00:00:00 2001 From: Luca Conte Date: Fri, 20 Dec 2024 17:57:50 +0100 Subject: [PATCH 03/13] destroy players on game end --- src/GameBoard.java | 3 +++ src/MainFrame.java | 2 ++ 2 files changed, 5 insertions(+) diff --git a/src/GameBoard.java b/src/GameBoard.java index b6aa09c..0eaa8d3 100644 --- a/src/GameBoard.java +++ b/src/GameBoard.java @@ -221,5 +221,8 @@ public class GameBoard extends JPanel { public Player getP1() { return p1; } + public Player getP2() { + return p2; + } } diff --git a/src/MainFrame.java b/src/MainFrame.java index 6d0b533..e384f92 100644 --- a/src/MainFrame.java +++ b/src/MainFrame.java @@ -151,6 +151,8 @@ public class MainFrame extends JFrame { if(player != gameBoard.getP1()){ return; } + this.gameBoard.getP1().destroy(); + this.gameBoard.getP2().destroy(); LooseScreen looseScreen = new LooseScreen(this); mainPanel.add(looseScreen,panelName); mainPanel.revalidate(); From a3827d6bd011a08c061aa849772f49303597a426 Mon Sep 17 00:00:00 2001 From: Luca Conte Date: Fri, 20 Dec 2024 18:29:49 +0100 Subject: [PATCH 04/13] add metric shit ton of javadoc comments --- src/AiPlayer.java | 8 +++++ src/AsyncSocket.java | 63 +++++++++++++++++++++++++++++++++++- src/AsyncSocketListener.java | 3 ++ src/Board.java | 6 ++++ src/GameController.java | 56 ++++++++++++++++++++++++++++++++ 5 files changed, 135 insertions(+), 1 deletion(-) diff --git a/src/AiPlayer.java b/src/AiPlayer.java index d51e41e..f3ed2aa 100644 --- a/src/AiPlayer.java +++ b/src/AiPlayer.java @@ -69,6 +69,10 @@ public abstract class AiPlayer extends LocalPlayer implements Runnable { this.shootThreads.add(t); } + /** + * Closes past threads and tries firing a shot. + * @author Luca Conte + */ public void run() { Iterator i = this.shootThreads.iterator(); while(i.hasNext()) { @@ -95,6 +99,10 @@ public abstract class AiPlayer extends LocalPlayer implements Runnable { this.aiShoot(); } + /** + * Closes all running threads and does some cleanup work so the garbage collector will delete the player + * @author Luca Conte + */ @Override public void destroy() { super.destroy(); diff --git a/src/AsyncSocket.java b/src/AsyncSocket.java index a5aa22e..506309f 100644 --- a/src/AsyncSocket.java +++ b/src/AsyncSocket.java @@ -7,6 +7,10 @@ import java.net.InetSocketAddress; import java.net.ServerSocket; import java.net.Socket; +/** + * Provides an Interface to communicate using a socket asynchronously + * @author Luca Conte + */ public class AsyncSocket { private Socket socket; private Thread checkerThread; @@ -19,6 +23,12 @@ public class AsyncSocket { private BufferedReader in; private BufferedWriter out; + /** + * Creates a socket server and turns the first incoming connection into an AsyncSocket + * @param port the port to listen on for a connection + * @param handler the handler that will be called when a message is received + * @author Luca Conte + */ public AsyncSocket(int port, AsyncSocketListener handler) { this.setHandler(handler); @@ -45,6 +55,12 @@ public class AsyncSocket { this.connectorThread.start(); } + /** + * Connects to the address provided and turns the resulting socket into an AsyncSocket + * @param address the socket address to connect to + * @param handler the handler that will be called when a message is received + * @author Luca Conte + */ public AsyncSocket(InetSocketAddress address, AsyncSocketListener handler) { this.setHandler(handler); @@ -68,11 +84,22 @@ public class AsyncSocket { this.connectorThread.start(); } + /** + * @param socket the socket to be wrapped in an AsyncSocket + * @param handler the handler that will be called when a message is received + * @author Luca Conte + */ public AsyncSocket(Socket socket, AsyncSocketListener handler) throws IOException { this.setHandler(handler); this.initSocket(socket); } + /** + * creates input and ouput writer / readers as well as a checker thread to repeatedly check + * for incoming messages + * @param socket the socket to be wrapped + * @author Luca Conte + */ private void initSocket(Socket socket) throws IOException { System.out.println("Initialising sockets"); this.socket = socket; @@ -122,17 +149,39 @@ public class AsyncSocket { this.flushBuffer(); } + /** + * sets the message handler for the async socket + * @param handler the `AsyncSocketListener` to be set as the new handler + * @author Luca Conte + */ public void setHandler(AsyncSocketListener handler) { this.handler = handler; } + /** + * sends a message through the socket + * @param socketPackage the socket package to be sent + * @author Luca Conte + */ public synchronized void send(SocketPackage socketPackage) { this.sendLine(socketPackage.toString()); } + /** + * sends a message through the socket + * @param packageName the name of the package to be sent + * @author Luca Conte + */ public synchronized void send(String packageName) { this.send(packageName, ""); } + /** + * sends a message through the socket + * @param packageName the name of the package to be sent + * @param packageContent the content of the package to be sent. + * `packageName` and `packageContent` are joined with a space " " + * @author Luca Conte + */ public synchronized void send(String packageName, String packageContent) { if (packageContent.length() > 0) { packageContent = " " + packageContent; @@ -140,11 +189,19 @@ public class AsyncSocket { this.sendLine(packageName + packageContent); } + /** + * sends a string of text into the socket, concatenated with CRLF + * @author Luca Conte + */ public synchronized void sendLine(String message) { sendBuffer = sendBuffer + message + "\r\n"; this.flushBuffer(); } + /** + * flushes the buffers to send all pending messages + * @author Luca Conte + */ private synchronized void flushBuffer() { if (!this.sendBuffer.isEmpty() && this.out != null) { try { @@ -159,12 +216,16 @@ public class AsyncSocket { } } + /** + * closes the socket connection and removes the checker thread + * @author Luca Conte + */ public void close() { this.shouldStop = true; try { this.socket.close(); - this.checkerThread.join(); + if (this.checkerThread != null) this.checkerThread.join(); } catch (IOException e) { e.printStackTrace(); } catch (InterruptedException e) { diff --git a/src/AsyncSocketListener.java b/src/AsyncSocketListener.java index a8c78ba..af3594e 100644 --- a/src/AsyncSocketListener.java +++ b/src/AsyncSocketListener.java @@ -1,3 +1,6 @@ +/** + * @author Luca Conte + */ public interface AsyncSocketListener { public void receive(String message); } \ No newline at end of file diff --git a/src/Board.java b/src/Board.java index c91468c..1b7095b 100644 --- a/src/Board.java +++ b/src/Board.java @@ -42,6 +42,12 @@ public class Board { return response; } + /** + * finds adjacened hit responses and sets their type to SUNK if they are currently HIT + * this makes it so that all the points of the ship are marked as SUNK, not just the final hit + * @param p the Point from which to propate the SUNK type + * @author Luca Conte + */ private void propagateSunk(Point p) { HitResponse hit = this.getHitResponseOnPoint(p); diff --git a/src/GameController.java b/src/GameController.java index 35b0764..6a921c9 100644 --- a/src/GameController.java +++ b/src/GameController.java @@ -5,28 +5,63 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +/** + * The central Backend Component + * @author Luca Conte + */ public class GameController { private static MainFrame mainFrame; + /** + * @return the current MainFrame + * @author Luca Conte + */ public static MainFrame getMainFrame() { return GameController.mainFrame; } + /** + * @param mainFrame the current MainFrame + * @author Luca Conte + */ public static void setMainFrame(MainFrame mainFrame) { GameController.mainFrame = mainFrame; } + /** + * converts a semester to be played in into its respective board size + * @param semester the semester to be played in + * @author Luca Conte + */ public static int semesterToBoardSize(int semester) { return semester + 13; } + /** + * converts a board size into its respective semester + * @param size the board size to get the semester of + * @author Luca Conte + */ public static int boardSizeToSemester(int size) { return size - 13; } + /** + * the list of supported versions of the online protocol + * https://github.com/lgc-4/ProgProjekt-Netzwerkstandard + */ public static HashMap> supportedVersions = new HashMap<>(Map.of( "1.1.0", OnlinePlayer_1_1_0.class )); + /** + * Starts a game with one local player and one online player. + * @param localPlayerClass the class of the local player to be instantiated. must extend `LocalPlayer` + * @param localPlayerName the name of the local player. Only necessarry when localPlayerClass is `HumanPlayer` + * @param address the Address of the opposing player. If the hostname of the address is set to be 0.0.0.0, it + * is interpreted that this instance should instead listen on the defined port for incoming connections. + * @param size the board size that it is intended to be played in + * @author Luca Conte + */ public static void startOnlineGame(Class localPlayerClass, String localPlayerName, InetSocketAddress address, int size) throws IOException { AsyncSocket clientSocket; @@ -90,6 +125,7 @@ public class GameController { /** * finds the largest common version in two lists of version strings * @return null if no common versions are found + * @author Luca Conte */ public static String findMostRecentVersion(List versions1, List versions2) { if (versions1 == null || versions2 == null) return null; @@ -114,10 +150,13 @@ public class GameController { /** * compares two version strings + * @param version1 the first version to be compared + * @param version2 the second version to be compared * @return * 0 if versions are equal * 1 if version1 is more recent than version2 * -1 otherwise + * @author Luca Conte */ public static int compareVersions(String version1, String version2) { if (!checkVersionString(version1) || !checkVersionString(version2)) { @@ -143,11 +182,21 @@ public class GameController { /** * checks if a provided string matches the format of a version number + * @param versionString the version String to be checked + * @author Luca Conte */ public static boolean checkVersionString(String versionString) { return versionString != null && versionString.matches("\\d+\\.\\d+\\.\\d+"); } + /** + * Starts a game with two local players + * @param localPlayerClass the class of the local player to be instantiated. must extend `LocalPlayer` + * @param localPlayerName the name of the local player. Only necessarry when localPlayerClass is `HumanPlayer` + * @param enemyClass the class of the enemy player. Must extend `AiPlayer`. For Humans VS Human games use an online game instead. + * @param size the board size that it is intended to be played in + * @author Luca Conte + */ public static void startLocalGame(Class localPlayerClass, String localPlayerName, Class enemyClass, int size) { LocalPlayer localPlayer; @@ -175,6 +224,13 @@ public class GameController { startGameWithInstancedPlayers(localPlayer, aiPlayer, size); } + /** + * switches to the ingame screen + * @param p1 the first player. This player is always shown on the left side of the screen and is expected to be the Human player, if there is one. + * @param p2 the second player + * @param boardSize the board size to be played in + * @author Luca Conte + */ public static void startGameWithInstancedPlayers(LocalPlayer p1, Player p2, int boardSize) { mainFrame.showPanelSLG("GameBoard", boardSizeToSemester(boardSize), p1, p2); From 9d62e74877ff97c1b87275c653d667522b92534f Mon Sep 17 00:00:00 2001 From: eyFlorian <45431375+eyFlorian@users.noreply.github.com> Date: Sat, 21 Dec 2024 21:11:21 +0100 Subject: [PATCH 05/13] =?UTF-8?q?AiPlayer=20Kommentare=20hinzugef=C3=BCgt?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bitte nicht schlagen. Kommentare sind drin. Kommentiert ja, High Quality Kommentare nein (._.) Bitte nicht schlagen. --- src/AiPlayer.java | 51 +++++++++++++++++++++++++++------ src/SpecificAiPlayerEasy.java | 9 +++++- src/SpecificAiPlayerHard.java | 19 ++++++++++-- src/SpecificAiPlayerMedium.java | 29 ++++++++++++++++++- 4 files changed, 95 insertions(+), 13 deletions(-) diff --git a/src/AiPlayer.java b/src/AiPlayer.java index 724233c..47f3109 100644 --- a/src/AiPlayer.java +++ b/src/AiPlayer.java @@ -1,3 +1,8 @@ +/** + * Die Klasse AiPlayer ist die Basis für alle Ki Spieler und jede Spezifische Ki erweitert diese Klasse. + * @author Florian und Florian + * */ + import java.util.ArrayList; import java.util.Iterator; import java.util.List; @@ -6,19 +11,34 @@ import java.util.Random; public abstract class AiPlayer extends LocalPlayer implements Runnable { + /** + * Liste aller erstellten ShootThreads + */ List shootThreads; + /** + * Konstruktor + */ public AiPlayer() { this.setName("AI Player"); this.shootThreads = new ArrayList<>(); } + + /** + * Gibt einen zufälligen Punkt im Spielfeld zurück. + * @return Ein zufälliger Punkt + */ public Point RandomPoint() { Random random = new Random(); // Pseudo Random für zufallszahlen int posx = random.nextInt(super.board.getSize()); // Generiert 0 - 13 int posy = random.nextInt(super.board.getSize()); // return new Point(posx,posy); } - + + /** + * Initialisiert das Board. + * @param size größe des Boards + */ @Override public void createBoard(int size) { super.createBoard(size); @@ -26,30 +46,38 @@ public abstract class AiPlayer extends LocalPlayer implements Runnable { this.ready(); } + /** + * Ki Methode zum zufälligen Setzten der Schiffe + */ public void aiSetShips() { for(int i = 0; i < super.board.getShips().size(); i++) { // Interiert durch alle Shiffe //TODO: set horizontal while(!super.board.getShips().get(i).setPosition(RandomPoint(), true, super.board.getShips(), super.board.getSize())) {} - } // Versucht das Aktuelle Shiff zu setzten und wiederholt solange bis es funktioniert + } // Versucht das aktuelle Schiff zu setzten und wiederholt solange bis es funktioniert return; } - + /** + * Ki Methode zum zufälligen Schießen auf das gegnerische Board. + */ public void aiShoot() { this.enemy.receiveShoot(RandomPoint()); return; } + @Override public synchronized void receiveHit(HitResponse hitResponse) { + // Eltern-Klasse LocalPlayer updatet myTurn super.receiveHit(hitResponse); if (this.myTurn) { + // Neuer Schuss wird erstellt und gestartet. Thread t = new Thread(this); t.start(); this.shootThreads.add(t); } } - + @Override public synchronized void receiveShoot(Point point) { super.receiveShoot(point); @@ -59,15 +87,22 @@ public abstract class AiPlayer extends LocalPlayer implements Runnable { this.shootThreads.add(t); } } - - + + /** + * Wird aufgerufen, wenn in determineCoinToss festgestellt wurde das die Ki anfängt. + * Erster Schuss wird gestartet. + */ @Override public void beginTurn() { Thread t = new Thread(this); t.start(); this.shootThreads.add(t); } - + + /** + * Die Methode wird immer aufgerufen, wenn ein Schuss abgefeuert werden soll. + * Es wird erst ein Schuss abgefeuert, wenn der vorherige schuss abgeschlossen wurde. + */ public void run() { Iterator i = this.shootThreads.iterator(); while(i.hasNext()) { @@ -85,7 +120,7 @@ public abstract class AiPlayer extends LocalPlayer implements Runnable { } try { - Thread.sleep(300); + Thread.sleep(250); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); diff --git a/src/SpecificAiPlayerEasy.java b/src/SpecificAiPlayerEasy.java index 4825ec5..a499e81 100644 --- a/src/SpecificAiPlayerEasy.java +++ b/src/SpecificAiPlayerEasy.java @@ -1,6 +1,13 @@ - +/** + * Diese Klasse implementiert den Einfachsten Ki Spieler. + * @author Florian und Florian + * */ public class SpecificAiPlayerEasy extends AiPlayer{ + /** + * Bein einfachen Ki Spieler wird nur der AiPlayer initialisiert und der Name gesetzt, + * da in der Eltern-Klasse AiPlayer eine default implementierung für alle Methoden existieren. + */ public SpecificAiPlayerEasy() { super(); this.setName("AI Player Easy"); diff --git a/src/SpecificAiPlayerHard.java b/src/SpecificAiPlayerHard.java index 079279f..a9a1345 100644 --- a/src/SpecificAiPlayerHard.java +++ b/src/SpecificAiPlayerHard.java @@ -1,3 +1,7 @@ +/** + * Diese Klasse implementiert den Harten Ki Spieler. + * @author Florian und Florian + * */ import java.util.ArrayList; import java.util.Random; @@ -64,7 +68,10 @@ public class SpecificAiPlayerHard extends AiPlayer{ addAdjacentPoints(hitResponse.getPoint()); } } - + /** + * Diese Methode erweitert die hitsQueue um die umliegenden Punkte die Schiffe seien könnten. + * @param point + */ private void addAdjacentPoints(Point point) { int x = point.getX(); int y = point.getY(); @@ -83,12 +90,18 @@ public class SpecificAiPlayerHard extends AiPlayer{ } } } - + /** + * Die Methode gibt zurück, ob eine Position auf dem Board ist. (Boolean) + * @param point Punkt der geprüft werden soll + * @return Ist auf dem Board oder nicht. + */ private boolean isValidPoint(Point point) { return point.getX() >= 0 && point.getX() < gridSize && point.getY() >= 0 && point.getY() < gridSize; } - + /** + * Ki Methode um zu schießen. + */ @Override public void aiShoot() { this.enemy.receiveShoot(getNextMove()); diff --git a/src/SpecificAiPlayerMedium.java b/src/SpecificAiPlayerMedium.java index 0562b3a..a27390a 100644 --- a/src/SpecificAiPlayerMedium.java +++ b/src/SpecificAiPlayerMedium.java @@ -1,8 +1,14 @@ +/** + * Diese Klasse implementiert den Medium Ki Spieler. + * @author Florian und Florian + * */ import java.util.ArrayList; import java.util.List; public class SpecificAiPlayerMedium extends AiPlayer{ - + /** + * Liste an Punkten die beschossen werden sollen. (Mögliche weitere Segmente vom schiff) + */ private List hitsQueue = new ArrayList<>(); public SpecificAiPlayerMedium() { @@ -10,6 +16,9 @@ public class SpecificAiPlayerMedium extends AiPlayer{ this.setName("AI Player Medium"); } + /** + * Ki Methode um zu schießen. + */ @Override public void aiShoot() { Point nextShot = ComputeNextShot(); @@ -26,6 +35,10 @@ public class SpecificAiPlayerMedium extends AiPlayer{ } } + /** + * Die Methode bestimmt welche Position als nächstes beschossen werden soll. + * @return + */ public Point ComputeNextShot() { Point nextShot; @@ -45,6 +58,10 @@ public class SpecificAiPlayerMedium extends AiPlayer{ return nextShot; } + /** + * Diese Methode erweitert die hitsQueue um die umliegenden Punkte die Schiffe seien könnten. + * @param point + */ private void addAdjacentPoints(Point point) { int x = point.getX(); int y = point.getY(); @@ -64,12 +81,22 @@ public class SpecificAiPlayerMedium extends AiPlayer{ } } + /** + * Diese Methode gibt zurück, ob eine Position schon beschossen wurde. (Boolean) + * @param p Punkt der geprüft werden soll + * @return wurde schon beschossen oder nicht. + */ private boolean alreadyShot(Point p) { return this.enemy.board.getHitResponseOnPoint(p) != null; } + /** + * Die Methode gibt zurück, ob eine Position auf dem Board ist. (Boolean) + * @param point Punkt der geprüft werden soll + * @return Ist auf dem Board oder nicht. + */ private boolean isValidPoint(Point point) { return point.getX() >= 0 && point.getX() < board.getSize() && point.getY() >= 0 && point.getY() < board.getSize(); From a4bfe5eb5fd9e8bd6b64e2883d82f9ff88041364 Mon Sep 17 00:00:00 2001 From: eyFlorian <45431375+eyFlorian@users.noreply.github.com> Date: Sun, 22 Dec 2024 16:15:11 +0100 Subject: [PATCH 06/13] KI HART Orientierung MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Harte Ki Orientiert sich an der Orientierung um sich zu Orientieren und unnötige Schüsse zu vermeiden. --- src/SpecificAiPlayerHard.java | 121 ++++++++++++++++++++++++++++++++-- 1 file changed, 114 insertions(+), 7 deletions(-) diff --git a/src/SpecificAiPlayerHard.java b/src/SpecificAiPlayerHard.java index a9a1345..067af48 100644 --- a/src/SpecificAiPlayerHard.java +++ b/src/SpecificAiPlayerHard.java @@ -14,6 +14,17 @@ public class SpecificAiPlayerHard extends AiPlayer{ private int nextChessRow; private int nextChessCol; + // Enum für die Orientierung + private enum Orientierung { + UNBEKANNT, + HORIZONTAL, + VERTIKAL + } + private Orientierung orientierung; + private Point firstHit; // Speichert den ersten Treffer zur Bestimmung der Orientierung + + + public SpecificAiPlayerHard() { super(); this.setName("AI Player Hard"); @@ -24,6 +35,8 @@ public class SpecificAiPlayerHard extends AiPlayer{ this.random = new Random(); this.nextChessRow = 0; this.nextChessCol = 0; + this.orientierung = Orientierung.UNBEKANNT; + this.firstHit = null; } // Checks if a position has already been shot at @@ -37,16 +50,16 @@ public class SpecificAiPlayerHard extends AiPlayer{ this.gridSize = super.board.getSize(); this.shotsFired = new boolean[gridSize][gridSize]; } - // If there are hits to process, prioritize those + // Wenn wir noch Treffer in der Queue haben, diese priorisieren while (!hitQueue.isEmpty()) { - Point target = hitQueue.remove(0); - + Point target = hitQueue.remove(0); if (!alreadyShot(target)) { + shotsFired[target.getX()][target.getY()] = true; return target; } } - // Otherwise, use chess pattern targeting + // Ansonsten weiterhin "Schachbrettmuster" int row = nextChessRow; int col = nextChessCol; while (alreadyShot(new Point(row, col))) { @@ -59,15 +72,109 @@ public class SpecificAiPlayerHard extends AiPlayer{ advanceChessPattern(); return new Point(row, col); } - + @Override public synchronized void receiveHit(HitResponse hitResponse) { super.receiveHit(hitResponse); - // If it's a hit or sunk, add adjacent cells to the hitsQueue + + // Wenn es ein Treffer ist, Adjacent-Punkte hinzufügen if (hitResponse.getHitResponse() == HitResponseType.HIT) { - addAdjacentPoints(hitResponse.getPoint()); + Point hitPoint = hitResponse.getPoint(); + + // Wenn wir noch keinen ersten Treffer haben, speicher ihn + if (firstHit == null) { + firstHit = hitPoint; + // Orientierung noch unbekannt: alle möglichen Richtungen hinzufügen + addAdjacentPoints(hitPoint); + } else { + // Wenn Orientierung noch nicht bestimmt, jetzt prüfen + if (this.orientierung == Orientierung.UNBEKANNT) { + // Prüfen, ob der zweite Treffer horizontal oder vertikal liegt + if (firstHit.getY() == hitPoint.getY()) { + this.orientierung = Orientierung.VERTIKAL; + } else if (firstHit.getX() == hitPoint.getX()) { + this.orientierung = Orientierung.HORIZONTAL; + } + + // Sobald die Orientierung erkannt wurde, entferne alle „unpassenden“ Punkte + if (this.orientierung != Orientierung.UNBEKANNT) { + cleanUpHitQueue(); + } + } + // Für den aktuellen Treffer nur in passender Orientierung erweitern + addPointsByOrientation(hitPoint); + } + } else if (hitResponse.getHitResponse() == HitResponseType.SUNK) { + this.orientierung = Orientierung.UNBEKANNT; + firstHit = null; + hitQueue.clear(); } } + + /** + * Entfernt aus der hitQueue alle Punkte, die nicht der erkannten Orientierung entsprechen. + */ + private void cleanUpHitQueue() { + if (firstHit == null || this.orientierung == Orientierung.UNBEKANNT) { + return; + } + ArrayList toRemove = new ArrayList<>(); + for (Point p : hitQueue) { + if (this.orientierung == Orientierung.HORIZONTAL) { + // HORIZONTAL => gleiche Zeile wie firstHit + if (p.getX() != firstHit.getX()) { + toRemove.add(p); + } + } else if (this.orientierung == Orientierung.VERTIKAL) { + // VERTICAL => gleiche Spalte wie firstHit + if (p.getY() != firstHit.getY()) { + toRemove.add(p); + } + } + } + hitQueue.removeAll(toRemove); + } + + /** + * Fügt benachbarte Felder in der **erkannten Orientierung** hinzu. + * - Ist die Orientierung HORIZONTAL, so werden nur links/rechts hinzugefügt. + * - Ist sie VERTICAL, so werden nur oben/unten hinzugefügt. + */ + private void addPointsByOrientation(Point point) { + if (this.orientierung == Orientierung.UNBEKANNT) { + // Fallback: füge alle benachbarten Punkte hinzu + addAdjacentPoints(point); + return; + } + + int x = point.getX(); + int y = point.getY(); + if (this.orientierung == Orientierung.HORIZONTAL) { + // Gleiche Zeile => links und rechts vom Point + Point left = new Point(x, y - 1); + Point right = new Point(x, y + 1); + + if (isValidPoint(left) && !alreadyShot(left) && !hitQueue.contains(left)) { + hitQueue.add(left); + } + if (isValidPoint(right) && !alreadyShot(right) && !hitQueue.contains(right)) { + hitQueue.add(right); + } + } else if (this.orientierung == Orientierung.VERTIKAL) { + // Gleiche Spalte => oben und unten + Point up = new Point(x - 1, y); + Point down = new Point(x + 1, y); + + if (isValidPoint(up) && !alreadyShot(up) && !hitQueue.contains(up)) { + hitQueue.add(up); + } + if (isValidPoint(down) && !alreadyShot(down) && !hitQueue.contains(down)) { + hitQueue.add(down); + } + } + } + + /** * Diese Methode erweitert die hitsQueue um die umliegenden Punkte die Schiffe seien könnten. * @param point From 6909b9417fa28920a9a65e8f604b745ec027990c Mon Sep 17 00:00:00 2001 From: Luca Conte Date: Mon, 23 Dec 2024 00:03:46 +0100 Subject: [PATCH 07/13] FINALLY FIX THE INDENTATION REEEE --- src/Ship.java | 82 ++++++++++++++++++++++++++++----------------------- 1 file changed, 45 insertions(+), 37 deletions(-) diff --git a/src/Ship.java b/src/Ship.java index 7dd7459..37decfd 100644 --- a/src/Ship.java +++ b/src/Ship.java @@ -6,43 +6,51 @@ import java.util.List; record ShipData (int size, String name){} public class Ship { - static List> semeterList = Arrays.asList(Arrays.asList( - new ShipData(2, "PRG 1"), - new ShipData(2, "GDI"), - new ShipData(2, "MAT 1"), - new ShipData(2, "THI"), - new ShipData(4, "STP"), - new ShipData(6, "ENG")), - Arrays.asList( - new ShipData(2, "PRG 2"), - new ShipData(2, "DBS 1"), - new ShipData(2, "MAT 2"), - new ShipData(2, "STA"), - new ShipData(2, "AUD")), - Arrays.asList( - new ShipData(2, "PRG 3"), - new ShipData(2, "DBS 2"), - new ShipData(2, "MAT 3"), - new ShipData(2, "BSN 1"), - new ShipData(4, "PRP"), - new ShipData(6, "BWL")), - Arrays.asList( - new ShipData(2, "WEB"), - new ShipData(2, "SE 1"), - new ShipData(2, "CG 1"), - new ShipData(2, "BSN 2"), - new ShipData(4, "SEM"), - new ShipData(6, "E BWL")), - Arrays.asList( - new ShipData(2, "WPF 1"), - new ShipData(2, "SE 2"), - new ShipData(2, "CG 2"), - new ShipData(2, "PXP 1"), - new ShipData(6, "EF 1")), - Arrays.asList( - new ShipData(2, "WPF 2"), - new ShipData(1, "PXP 2"), - new ShipData(8, "BAA")) + static List> semeterList = + Arrays.asList( + Arrays.asList( + new ShipData(2, "PRG 1"), + new ShipData(2, "GDI"), + new ShipData(2, "MAT 1"), + new ShipData(2, "THI"), + new ShipData(4, "STP"), + new ShipData(6, "ENG") + ), + Arrays.asList( + new ShipData(2, "PRG 2"), + new ShipData(2, "DBS 1"), + new ShipData(2, "MAT 2"), + new ShipData(2, "STA"), + new ShipData(2, "AUD") + ), + Arrays.asList( + new ShipData(2, "PRG 3"), + new ShipData(2, "DBS 2"), + new ShipData(2, "MAT 3"), + new ShipData(2, "BSN 1"), + new ShipData(4, "PRP"), + new ShipData(6, "BWL") + ), + Arrays.asList( + new ShipData(2, "WEB"), + new ShipData(2, "SE 1"), + new ShipData(2, "CG 1"), + new ShipData(2, "BSN 2"), + new ShipData(4, "SEM"), + new ShipData(6, "E BWL") + ), + Arrays.asList( + new ShipData(2, "WPF 1"), + new ShipData(2, "SE 2"), + new ShipData(2, "CG 2"), + new ShipData(2, "PXP 1"), + new ShipData(6, "EF 1") + ), + Arrays.asList( + new ShipData(2, "WPF 2"), + new ShipData(1, "PXP 2"), + new ShipData(8, "BAA") + ) ); private int size; From 8b4b017e85f28e71b809c3b0bec8703354100d16 Mon Sep 17 00:00:00 2001 From: Luca Conte Date: Mon, 23 Dec 2024 00:03:54 +0100 Subject: [PATCH 08/13] MORE javadoc --- src/Board.java | 23 +++++++++++++ src/HumanPlayer.java | 7 ++++ src/LocalPlayer.java | 21 ++++++++++++ src/OnlinePlayer.java | 12 ++++++- src/OnlinePlayer_1_1_0.java | 27 +++++++++++++++ src/Player.java | 62 ++++++++++++++++++++++++++++++++++ src/Point.java | 67 +++++++++++++++++++++++++++++++++++++ 7 files changed, 218 insertions(+), 1 deletion(-) diff --git a/src/Board.java b/src/Board.java index 1b7095b..0587b0c 100644 --- a/src/Board.java +++ b/src/Board.java @@ -61,6 +61,10 @@ public class Board { propagateSunk(new Point(p.getX(), p.getY() - 1)); } + /** + * creates all the ships on a board given a certain semester + * @param semester the semester to be played in + */ private void createShip(int semester){ List shipData = Ship.semeterList.get(semester -1); for (int i = 0; i < shipData.size(); i++) { @@ -68,10 +72,22 @@ public class Board { } } + /** + * @return a list of all the Ships on the board + */ public List getShips() { return ships; } + /** + * adds a HitResponse to the list of Hits on the board + * If a hit response already exists on the same position, the hit response will not be added + * If the hit response is of type `HitResponseType.SUNK` it will propagate this hit response type + * to all adjacened hit responses with type HIT using `propagateSunk`. + * @param hitResponse the HitResponse to be added + * @return true when the hit response was added, otherwise false + * + */ public synchronized boolean addHits(HitResponse hitResponse) { if (this.getHitResponseOnPoint(hitResponse.getPoint()) == null){ this.hits.add(hitResponse); @@ -87,6 +103,10 @@ public class Board { return false; } + /** + * @param point the position to get the hit response from + * @return the hit response at the position `point` + */ public synchronized HitResponse getHitResponseOnPoint(Point point) { for (int i = 0; i < this.hits.size(); i++){ if (this.hits.get(i).getPoint().equals(point)){ @@ -96,6 +116,9 @@ public class Board { return null; } + /** + * @return the size of the board + */ public int getSize() { return this.size; } diff --git a/src/HumanPlayer.java b/src/HumanPlayer.java index 4dfdbe1..6f00dbe 100644 --- a/src/HumanPlayer.java +++ b/src/HumanPlayer.java @@ -1,7 +1,14 @@ public class HumanPlayer extends LocalPlayer { + /** + * shoots a shot onto the provided point on the enemy board + * if it is not the players turn, this method does nothing. + * @param point the location to be shot + * @author Luca Conte + */ @Override public void shoot(Point point) { + if (!this.myTurn) return; this.myTurn = false; enemy.receiveShoot(point); } diff --git a/src/LocalPlayer.java b/src/LocalPlayer.java index af66e53..4da86a6 100644 --- a/src/LocalPlayer.java +++ b/src/LocalPlayer.java @@ -8,6 +8,11 @@ public class LocalPlayer extends Player { this.myCoin = random.nextBoolean(); } + /** + * receives a shot onto a point from the enemy + * @param point the location to be shot + * @author Luca Conte, Peer Ole Wachtel + */ @Override public synchronized void receiveShoot(Point point) { if (!this.enemy.myTurn) return; @@ -29,6 +34,11 @@ public class LocalPlayer extends Player { GameController.getMainFrame().refreshGameBoard(); } + /** + * receives a hit response from the enemy as a response to a receiveShoot call + * @param hitResponse the hitresponse + * @author Peer Ole Wachtel + */ @Override public synchronized void receiveHit(HitResponse hitResponse) { enemy.board.addHits(hitResponse); @@ -40,6 +50,13 @@ public class LocalPlayer extends Player { GameController.getMainFrame().refreshGameBoard(); } + /** + * receives the enemies coin toss result + * this method does nothing if the player has already received the enemies coin + * it will also call `determineCoinToss` + * @param coin the coin of the enemy player + * @author Luca Conte + */ @Override public synchronized void receiveCoin(boolean coin) { if (!this.hasReceivedCoin) { @@ -57,6 +74,10 @@ public class LocalPlayer extends Player { return; } + /** + * marks the player as ready, if all ships have been placed + * @author Luca Conte + */ @Override public synchronized void ready() { for (Ship ship : this.board.getShips()) { diff --git a/src/OnlinePlayer.java b/src/OnlinePlayer.java index 4f0d56b..2db0a90 100644 --- a/src/OnlinePlayer.java +++ b/src/OnlinePlayer.java @@ -1,9 +1,15 @@ -public abstract class OnlinePlayer extends Player implements AsyncSocketListener{ +public abstract class OnlinePlayer extends Player implements AsyncSocketListener { protected AsyncSocket socket; protected int wantedBoardSize; protected boolean hasReceivedCoinPackage; + /** + * Constructor + * @param size the size of the board the enemy player wants to play with + * the actual board size will be determined once the semester of the online partner is known + * @param socket an AsyncSocket to communicate with the enemy through + */ public OnlinePlayer(Integer size, AsyncSocket socket) { this.socket = socket; this.wantedBoardSize = size; @@ -25,6 +31,10 @@ public abstract class OnlinePlayer extends Player implements AsyncSocketListener @Override public abstract void receiveCoin(boolean coin); + /** + * closes the socket and does player cleanup work + * @author Luca Conte + */ @Override public void destroy() { super.destroy(); diff --git a/src/OnlinePlayer_1_1_0.java b/src/OnlinePlayer_1_1_0.java index eab7f1e..b401a6e 100644 --- a/src/OnlinePlayer_1_1_0.java +++ b/src/OnlinePlayer_1_1_0.java @@ -6,6 +6,12 @@ public class OnlinePlayer_1_1_0 extends OnlinePlayer { } + /** + * receives a message from the AsyncSocket + * implemented according to version 1.1.0 of https://github.com/lgc-4/ProgProjekt-Netzwerkstandard + * @param message the message from the socket + * @author Peer Ole Wachtel, Luca Conte + */ @Override public void receive(String message) { SocketPackage p = new SocketPackage(message); @@ -67,23 +73,44 @@ public class OnlinePlayer_1_1_0 extends OnlinePlayer { } } + /** + * sends introduction package IAM to online partner. + * @author Luca Conte + */ @Override public synchronized void sendIAM() { if (this.enemy == null) throw new RuntimeException("enemy has not yet been defined"); socket.send(new SocketPackage("IAM", GameController.boardSizeToSemester(this.wantedBoardSize) + " " + this.enemy.name)); } + /** + * receives a shot from the enemy and sends it to the online partner + * if it is not the enemies turn, this method does nothing. + * @param point the point to be shot + * @author Peer Ole Wachtel + */ @Override public synchronized void receiveShoot(Point point){ if (!this.enemy.myTurn) return; super.socket.send(new SocketPackage("SHOOT",point.toString())); } + /** + * receives a hitresponse from the enemy player and sends it to the online partner + * @param hitResponse the hitresponse to be sent + * @author Peer Ole Wachtel + */ @Override public synchronized void receiveHit(HitResponse hitResponse) { super.socket.send(new SocketPackage("HIT", hitResponse.toString())); } + /** + * receives the coin toss result from the enemy player and sends it to the online partner + * if this player has already received the enemies coin, this method does nothing. + * @param coin the result of the coin toss + * @author Peer Ole Wachtel, Luca Conte + */ @Override public synchronized void receiveCoin(boolean coin) { if (!this.hasReceivedCoin) { diff --git a/src/Player.java b/src/Player.java index 5ea7ba7..4adf76c 100644 --- a/src/Player.java +++ b/src/Player.java @@ -20,6 +20,11 @@ public abstract class Player { this.gameRunning = false; } + /** + * initialises this players board + * @param size the size of the board to be created + * @author Peer Ole Wachtel + */ public void createBoard(int size) { this.board = new Board(size); } @@ -30,25 +35,54 @@ public abstract class Player { public abstract void shoot(Point point); + /** + * only relevant for AI Players. + * starts the first turn + * @author Luca Conte + */ public void beginTurn() { System.out.println("issa my turn-a"); } + /** + * sets the enemy Player + * @author Peer Ole Wachtel + */ public void setEnemy(Player enemy) { this.enemy = enemy; } + /** + * sets the name of this player + * @param name the name of this player + * @author Luca Conte + */ public void setName(String name) { this.name = name; } + /** + * returns the name of this player + * @return the name of this player + * @author Luca Conte + */ public String getName() { return this.name; } + /** + * returns the board of this player + * @return the board of this player + * @author Lucas Bronson + */ public Board getBoard() { return this.board; } + /** + * marks the player as ready by sending their coin to the enemy player + * calls determineCoinToss if the enemy coin has already been received + * @author Luca Conte + */ public void ready() { this.enemy.receiveCoin(this.myCoin); this.sentCoin = true; @@ -57,6 +91,11 @@ public abstract class Player { } }; + /** + * determines the result of the coin toss + * this method does nothing if either player is not ready yet or has not yet sent their coin + * @author Luca Conte, Peer Ole Wachtel + */ protected void determineCoinToss() { if (!this.sentCoin || this.myCoin == null || !this.hasReceivedCoin || this.enemy.myCoin == null) return; boolean result = this.enemy.myCoin ^ this.myCoin; // XOR @@ -68,16 +107,39 @@ public abstract class Player { GameController.getMainFrame().refreshGameBoard(); } + /** + * receives the coin toss from the enemy player + * @param coin the coin of the enemy player + * @author Peer Ole Wachtel + */ public abstract void receiveCoin(boolean coin); + /** + * returns whether the game this player is in has started, meaning both players are ready and have sent their coins + * @return the game's running state + * @author Luca Conte + */ public boolean isGameRunning() { return this.gameRunning; } + /** + * returns whether this player is ready and has sent their coin to the enemy player + * @return the player's ready state + */ public boolean isReady() { return this.sentCoin; } + /** + * removes connections to the enemy and its board as well as setting myTurn and gameRunning to false + * this stops the AI Players from making more moves and allows the garbage collector to remove the boards + * and players + * + * This method should be called at the end of a game + * + * @author Luca Conte + */ public void destroy() { this.myTurn = false; this.gameRunning = false; diff --git a/src/Point.java b/src/Point.java index d5b06ed..301ec1e 100644 --- a/src/Point.java +++ b/src/Point.java @@ -2,10 +2,26 @@ public class Point { private int x; private int y; + /** + * initialises a point using X and Y coordinates starting at 0 + * @param x the x coordinate of the point starting at 0 + * @param y the y coordinate of the point starting at 0 + */ public Point (int x, int y) { this.setX(x); this.setY(y); } + + /** + * initialises a Point using a coordinate provided in the format of a letter followed by a number + * this coordinate is checked using `isValidSyntax` + * If the coordinate is not in a valid syntax, an `IllegalArgumentException` will be thrown, stating as such + * The number part of the coordinate starts at 1 instead of 0 so for example, the + * string A1 will result in the X and Y coordinates of (0, 0) + * @param str the coordinate in alphanumeric format + * @throws IllegalArgumentException if the coordinate is invalid according to `isValidSyntax` + * @author Peer Ole Wachtel, Luca Conte + */ public Point (String str) { if (Point.isValidSyntax(str)) { this.setX(str.charAt(0)); @@ -15,34 +31,78 @@ public class Point { } } + /** + * returns this point as a string in its alphanumeric format + * @return this point as a string in its alphanumeric format + * @author Luca Conte, Peer Ole Wachtel + */ @Override public String toString() { return (char) ('A' + this.x) + String.valueOf(this.y + 1); } + /** + * returns the X coordinate of the point starting at 0 + * @return the X coordinate of the point starting at 0 + * @author Peer Ole Wachtel + */ public int getX() { return x; } + /** + * returns the Y coordinate of the point starting at 0 + * @return the Y coordinate of the point starting at 0 + * @author Peer Ole Wachtel + */ public int getY() { return y; } + /** + * sets the X coordinate of the point starting at 0 + * @param x the X coordinate of the point starting at 0 + * @author Peer Ole Wachtel + */ public void setX(int x) { this.x = x; } + /** + * sets the Y coordinate of the point starting at 0 + * @param y the Y coordinate of the point starting at 0 + * @author Peer Ole Wachtel + */ public void setY(int y) { this.y = y; } + + /** + * sets the X coordinate of the from its character value in alphanumeric form + * @param c the character to be transformed into + * @author Peer Ole Wachtel + */ public void setX(char c) { this.x = c - 'A'; } + /** + * checks whether a string is a valid alphanumeric point coordinate + * @param str the string to be tested + * @return whether the string is valid according to the regular expression `^[A-Z]\\d+$` + * @author Peer Ole Wachtel + */ public static boolean isValidSyntax(String str) { return str.matches("^[A-Z]\\d+$"); } + /** + * returns whether two points are equal + * two points with equivalent coordinates are considered equal + * @param o the other object/Point to compare this one to + * @return whether the objects are equal + * @author Luca Conte + */ @Override public boolean equals(Object o) { if (this == o) return true; @@ -52,6 +112,13 @@ public class Point { return p.getX() == this.getX() && p.getY() == this.getY(); } + /** + * determines whether two points are neighbours + * points are considered neighbours if their positions are equal or within a difference of 1 on both X and Y axis + * @param other the point to check for neighbourship + * @return whether the points are neighbours + * @author Luca Conte + */ public boolean neighbours(Point other) { if (other == null) return false; return (int)Math.abs(this.getX() - other.getX()) <= 1 && (int)Math.abs(this.getY() - other.getY()) <= 1; From 2cce52b8278c70c8ecf8f313ce1481bca0ed1ae6 Mon Sep 17 00:00:00 2001 From: Luca Conte Date: Mon, 23 Dec 2024 00:28:55 +0100 Subject: [PATCH 09/13] die letzten javadoc kommentare --- src/Ship.java | 95 ++++++++++++++++++++++++++++++++++++------ src/SocketPackage.java | 51 +++++++++++++++++++++++ src/SoundHandler.java | 10 ++--- 3 files changed, 139 insertions(+), 17 deletions(-) diff --git a/src/Ship.java b/src/Ship.java index 37decfd..8844dc9 100644 --- a/src/Ship.java +++ b/src/Ship.java @@ -60,6 +60,12 @@ public class Ship { private int hitsOnMe; private boolean sunk; + /** + * initialises a Ship with a given size and name + * @param size the size of the ship + * @param name the name of the ship + * @author Peer Ole Wachtel + */ public Ship (int size, String name) { this.size = size; this.name = name; @@ -69,10 +75,23 @@ public class Ship { this.sunk = false; } + /** + * resets the position of this ship + * @author Luca Conte + */ public void resetPosition() { this.position = null; } + /** + * sets the position of this ship, provided it is valid + * @param pos the position to move the ship to + * @param horizontal whether the ship is horizontal or not + * @param shipsList the list of other ships on this board. It will be checked whether the ship is touching any of them + * @param boardSize the size of the board the ship is to be placed on + * @return true if the position was set successfully. false if the ship is out of the bounds of the board or touches a different ship + * @author Luca Conte + */ public boolean setPosition(Point pos, boolean horizontal, List shipsList, int boardSize) { if (!this.checkValidPlacement(pos, horizontal, shipsList, boardSize)) return false; @@ -82,6 +101,15 @@ public class Ship { return true; } + /** + * checks whether a position is valid for ship placement + * @param pos the position to check the ship placement at + * @param horizontal whether the ship is to be placed horizontally or not + * @param shipsList the list of other ships on this board. It will be checked whether the ship is touching any of them + * @param boardSize the size of the board the ship is to be placed on + * @return true if the position is valid. false if the ship is out of the bounds of the board or touches a different ship + * @author Florian Hantzschel, Peer Ole Wachtel, Luca Conte + */ public boolean checkValidPlacement(Point pos, boolean horizontal, List shipsList, int boardSize) { // ueberpruefe boundaries if (pos.getX() < 0 || pos.getY() < 0 || pos.getX() >= boardSize || pos.getY() >= boardSize) { @@ -130,7 +158,11 @@ public class Ship { } /** - * Returns the Points on the ship if it were to be placed at positino `pos` in orientation defined by `horizontal` + * Returns the Points on the ship if it were to be placed at position `pos` in orientation defined by `horizontal` + * @param pos the position where the ship should be placed + * @param horizontal whether the ship should be placed horizontally + * @return a list of points the ship would occupy, were it placed at position `pos` in orientation `horizontal` + * @author Florian Hantzschel, Luca Conte */ public List getVirtualOccupiedPoints(Point pos, boolean horizontal) { List points = new ArrayList<>(); @@ -145,23 +177,30 @@ public class Ship { return points; } + /** + * Returns the Points the ship occupies + * @return a list of points the ship occupies + * @author Florian Hantzschel, Luca Conte + */ public List getOccupiedPoints() { - List points = new ArrayList<>(); - if (this.position == null) { - return points; - } - for (int i = 0; i < this.size; i++) { - int x = this.horizontal ? this.position.getX() + i : this.position.getX(); - int y = this.horizontal ? this.position.getY() : this.position.getY() + i; - points.add(new Point(x, y)); - } - return points; + return this.getVirtualOccupiedPoints(this.position, this.horizontal); } + /** + * returns the position of this ship + * @return the position of this ship + * @author Peer Ole Wachte + */ public Point getPosition() { return position; } + /** + * checks whether the ship occupies a certain point + * @param pos the point to be checkd + * @return whether the point provided is one of the points occupied by the ship + * @author Peer Ole Wachtel, Lucas Bronson + */ public boolean isShipOnPos(Point pos){ if(this.position == null){ return false; @@ -173,6 +212,13 @@ public class Ship { return false; } + /** + * "shoots" this ship. + * @return a hit response, depending on whether the ship was hit or not. If the amount of times + * the ship was hit is greater or equal to the size of the ship, the ship is considered sunk. + * @param pos the point where the ship is shot + * @author Peer Ole Wachtel + */ public HitResponseType shootOnShip(Point pos) { if (this.isShipOnPos(pos)) { hitsOnMe++; @@ -187,22 +233,47 @@ public class Ship { } } + /** + * returns whether the ship has been sunk or not + * @return whether the ship has been sunk or not + * @author Peer Ole Wachtel + */ public boolean isSunk() { return sunk; } + /** + * sets the orientation of the ship + * @param horizontal whether the ship is to be placed in a horizontal orientation + * @author Lucas Bronson + */ public void setHorizontal(boolean horizontal) { this.horizontal = horizontal; } + /** + * returns the size of the ship + * @return the size of the ship + * @author Lucas Bronson + */ public int getSize() { return size; } + + /** + * returns the name of the ship + * @return the name of the ship + * @author Lucas Bronson + */ public String getName() { return name; } - //potentiell falsch neu + /** + * returns whether the ship has been placed or not + * @return whether the ship has been placed or not + * @author Lucas Bronson + */ public boolean isPlaced(){ return this.position != null; } diff --git a/src/SocketPackage.java b/src/SocketPackage.java index 0dabd58..767d0e2 100644 --- a/src/SocketPackage.java +++ b/src/SocketPackage.java @@ -1,17 +1,37 @@ import java.util.Arrays; import java.util.List; +/** + * @author Luca Conte + */ public class SocketPackage { private String name = ""; private String data = ""; + /** + * initialises a socket package by prividing a package name and data + * @param name the name of the package + * @param data the data of the package + * @author Luca Conte + */ public SocketPackage(String name, String data) { this.setName(name); this.setData(data); } + /** + * initialises an empty socket package + * @author Luca Conte + */ public SocketPackage() { this("",""); } + + /** + * initialises a socket package from a message + * the message is parsed according to https://github.com/lgc-4/ProgProjekt-Netzwerkstandard + * @param message the message to be parsed + * @author Luca Conte + */ public SocketPackage(String message) { if (message.length() <= 0) { throw new IllegalArgumentException("Socket message cannot be empty."); @@ -25,24 +45,50 @@ public class SocketPackage { } } + /** + * sets the package name + * the name is always stored in upper case + * @param name the new name of the package + * @author Luca Conte + */ public void setName(String name) { if (name == null) name = ""; this.name = name.toUpperCase(); } + /** + * sets the package data + * @param name the new data of the package + * @author Luca Conte + */ public void setData(String data) { if (data == null) data = ""; this.data = data; } + /** + * returns the name of the package + * @return the name of the package + * @author Luca Conte + */ public String getName() { return this.name; } + /** + * returns the data of the package + * @return the data of the package + * @author Luca Conte + */ public String getData() { return this.data; } + /** + * parses the package into a string according to https://github.com/lgc-4/ProgProjekt-Netzwerkstandard + * the package name and data are joined using a space " " `0x20` + * @return the package in string format + */ public String toString() { if (this.data == null || this.data.length() == 0) { return this.name; @@ -51,6 +97,11 @@ public class SocketPackage { } } + /** + * returns the data string as a list, split at every space " " `0x20` + * @return the data string as a list, split at every space " " `0x20` + * @author Luca Conte + */ public List splitData() { return Arrays.asList(this.data.split(" ")); } diff --git a/src/SoundHandler.java b/src/SoundHandler.java index b5d6a82..41fed75 100644 --- a/src/SoundHandler.java +++ b/src/SoundHandler.java @@ -67,9 +67,9 @@ public class SoundHandler { } /** - * TODO funktion beschreiben (potentiell nicht benötigte Funktion?) - * @param soundName - * @param path + * fügt einen neuen Sound zum SoundHanlder hinzu + * @param soundName der intern zu verwendende Name des Sounds + * @param path der Dateipfad zur Sound Datei * @author Ole Wachtel */ static void add(String soundName, String path){ @@ -77,8 +77,8 @@ public class SoundHandler { } /** - * TODO funktion beschreiben (potentiell nicht benötigte Funktion?) - * @param sound + * schaltet den Ton an oder aus + * @param sound ob der sound an ist * @author Ole Wachtel */ static void setSoundOn(boolean sound){ From 4045d3ce7bd78f565071e7677fbd418dc4e1f78f Mon Sep 17 00:00:00 2001 From: eyFlorian <45431375+eyFlorian@users.noreply.github.com> Date: Mon, 23 Dec 2024 15:28:33 +0100 Subject: [PATCH 10/13] Kommentare und Withdraw --- src/Board.java | 11 +++++++- src/OnlinePlayer_1_1_0.java | 9 +++++- src/SpecificAiPlayerEasy.java | 3 +- src/SpecificAiPlayerHard.java | 49 +++++++++++++++++++++++++-------- src/SpecificAiPlayerMedium.java | 19 +++++++++++-- 5 files changed, 75 insertions(+), 16 deletions(-) diff --git a/src/Board.java b/src/Board.java index 0587b0c..c1b2974 100644 --- a/src/Board.java +++ b/src/Board.java @@ -1,3 +1,7 @@ +/** + * Die Board-Klasse repräsentiert das Spielfeld. + * @author Peer Ole Wachtel, Florian Alexy und Florian Hantzschel + */ import java.util.ArrayList; import java.util.List; @@ -8,7 +12,11 @@ public class Board { private List ships; private final int size; - + /** + * Initialisiert das Board und die zu Setzenden schiffe. + * @param size + * @author Peer Ole Wachtel, Florian Alexy und Florian Hantzschel + */ public Board(int size) { this.size = size; this.ships = new ArrayList<>(); @@ -64,6 +72,7 @@ public class Board { /** * creates all the ships on a board given a certain semester * @param semester the semester to be played in + * @author Peer Ole Wachtel */ private void createShip(int semester){ List shipData = Ship.semeterList.get(semester -1); diff --git a/src/OnlinePlayer_1_1_0.java b/src/OnlinePlayer_1_1_0.java index b401a6e..df7c8a9 100644 --- a/src/OnlinePlayer_1_1_0.java +++ b/src/OnlinePlayer_1_1_0.java @@ -10,7 +10,7 @@ public class OnlinePlayer_1_1_0 extends OnlinePlayer { * receives a message from the AsyncSocket * implemented according to version 1.1.0 of https://github.com/lgc-4/ProgProjekt-Netzwerkstandard * @param message the message from the socket - * @author Peer Ole Wachtel, Luca Conte + * @author Peer Ole Wachtel, Luca Conte, Florian Hantzschel */ @Override public void receive(String message) { @@ -67,6 +67,13 @@ public class OnlinePlayer_1_1_0 extends OnlinePlayer { //TODO CHAT break; + case "WITHDRAW": + //Found funny cheese to do this without GUI Access + HitResponse tmp_hit = new HitResponse(0, new Point(0,0)); + tmp_hit.setType(HitResponseType.VICTORY); + this.receiveHit(tmp_hit); + break; + default: //nichts passier da Paket ungültig break; diff --git a/src/SpecificAiPlayerEasy.java b/src/SpecificAiPlayerEasy.java index a499e81..6be23bb 100644 --- a/src/SpecificAiPlayerEasy.java +++ b/src/SpecificAiPlayerEasy.java @@ -1,12 +1,13 @@ /** * Diese Klasse implementiert den Einfachsten Ki Spieler. - * @author Florian und Florian + * @author Florian Alexy und Florian Hantzschel * */ public class SpecificAiPlayerEasy extends AiPlayer{ /** * Bein einfachen Ki Spieler wird nur der AiPlayer initialisiert und der Name gesetzt, * da in der Eltern-Klasse AiPlayer eine default implementierung für alle Methoden existieren. + * @author Florian Alexy und Florian Hantzschel */ public SpecificAiPlayerEasy() { super(); diff --git a/src/SpecificAiPlayerHard.java b/src/SpecificAiPlayerHard.java index 067af48..292bf6d 100644 --- a/src/SpecificAiPlayerHard.java +++ b/src/SpecificAiPlayerHard.java @@ -1,16 +1,16 @@ /** * Diese Klasse implementiert den Harten Ki Spieler. - * @author Florian und Florian + * @author Florian Alexy und Florian Hantzschel * */ import java.util.ArrayList; -import java.util.Random; +// import java.util.Random; wird nicht mehr verwendet public class SpecificAiPlayerHard extends AiPlayer{ private int gridSize; private boolean[][] shotsFired; private final ArrayList hitQueue; - private final Random random; + //private final Random random; wird nicht mehr verwendet private int nextChessRow; private int nextChessCol; @@ -24,7 +24,11 @@ public class SpecificAiPlayerHard extends AiPlayer{ private Point firstHit; // Speichert den ersten Treffer zur Bestimmung der Orientierung - + /** + * Eltern-Klasse wird initialisiert und alle lokalen variablen, + * die gesetzt werden können, werden initialisiert. + * @author Florian Alexy und Florian Hantzschel + */ public SpecificAiPlayerHard() { super(); this.setName("AI Player Hard"); @@ -32,19 +36,28 @@ public class SpecificAiPlayerHard extends AiPlayer{ this.shotsFired = new boolean[gridSize][gridSize];*/ this.gridSize = 0; this.hitQueue = new ArrayList<>(); - this.random = new Random(); + //this.random = new Random(); wird nicht mehr verwendet this.nextChessRow = 0; this.nextChessCol = 0; this.orientierung = Orientierung.UNBEKANNT; this.firstHit = null; } - // Checks if a position has already been shot at + /** + * Prüft, ob auf den punkt schonmal geschossen wurde. + * @param p zu prüfender Punkt + * @return boolean + * @author Florian Alexy und Florian Hantzschel + */ public boolean alreadyShot(Point p) { return shotsFired[p.getX()][p.getY()]; } - // Generates the next move for the AI + /** + * Bestimmt den nächsten punkt, der beschossen werden soll. + * @return Position + * @author Florian Alexy und Florian Hantzschel + */ public Point getNextMove() { if(gridSize == 0) { this.gridSize = super.board.getSize(); @@ -73,6 +86,12 @@ public class SpecificAiPlayerHard extends AiPlayer{ return new Point(row, col); } + /** + * Nachdem receiveShoot beim gegner den schuss verarbeitet hat, + * wird diese Methode mit der antwort aufgerufen. + * @param hitResponse the hitresponse + * @author Florian Alexy und Florian Hantzschel + */ @Override public synchronized void receiveHit(HitResponse hitResponse) { super.receiveHit(hitResponse); @@ -113,6 +132,7 @@ public class SpecificAiPlayerHard extends AiPlayer{ /** * Entfernt aus der hitQueue alle Punkte, die nicht der erkannten Orientierung entsprechen. + * @author Florian Alexy und Florian Hantzschel */ private void cleanUpHitQueue() { if (firstHit == null || this.orientierung == Orientierung.UNBEKANNT) { @@ -136,9 +156,10 @@ public class SpecificAiPlayerHard extends AiPlayer{ } /** - * Fügt benachbarte Felder in der **erkannten Orientierung** hinzu. - * - Ist die Orientierung HORIZONTAL, so werden nur links/rechts hinzugefügt. - * - Ist sie VERTICAL, so werden nur oben/unten hinzugefügt. + * Fügt benachbarte Felder in der erkannten Orientierung hinzu. + * Ist die Orientierung HORIZONTAL, so werden nur links/rechts hinzugefügt. + * Ist sie VERTICAL, so werden nur oben/unten hinzugefügt. + * @author Florian Alexy und Florian Hantzschel */ private void addPointsByOrientation(Point point) { if (this.orientierung == Orientierung.UNBEKANNT) { @@ -178,6 +199,7 @@ public class SpecificAiPlayerHard extends AiPlayer{ /** * Diese Methode erweitert die hitsQueue um die umliegenden Punkte die Schiffe seien könnten. * @param point + * @author Florian Alexy und Florian Hantzschel */ private void addAdjacentPoints(Point point) { int x = point.getX(); @@ -201,6 +223,7 @@ public class SpecificAiPlayerHard extends AiPlayer{ * Die Methode gibt zurück, ob eine Position auf dem Board ist. (Boolean) * @param point Punkt der geprüft werden soll * @return Ist auf dem Board oder nicht. + * @author Florian Alexy und Florian Hantzschel */ private boolean isValidPoint(Point point) { return point.getX() >= 0 && point.getX() < gridSize && @@ -208,13 +231,17 @@ public class SpecificAiPlayerHard extends AiPlayer{ } /** * Ki Methode um zu schießen. + * @author Florian Alexy und Florian Hantzschel */ @Override public void aiShoot() { this.enemy.receiveShoot(getNextMove()); } - // Advances the chess pattern to the next cell + /** + * Die Zeilen und spalten variable wird hier angepasst, sodass beim nächsten schuss im Muster geschossen wird. + * @author Florian Alexy und Florian Hantzschel + */ private void advanceChessPattern() { nextChessCol += 2; if (nextChessCol >= gridSize) { diff --git a/src/SpecificAiPlayerMedium.java b/src/SpecificAiPlayerMedium.java index a27390a..aa2c6ca 100644 --- a/src/SpecificAiPlayerMedium.java +++ b/src/SpecificAiPlayerMedium.java @@ -1,6 +1,6 @@ /** * Diese Klasse implementiert den Medium Ki Spieler. - * @author Florian und Florian + * @author Florian Alexy und Florian Hantzschel * */ import java.util.ArrayList; import java.util.List; @@ -11,6 +11,10 @@ public class SpecificAiPlayerMedium extends AiPlayer{ */ private List hitsQueue = new ArrayList<>(); + /** + * Eltern-Klasse wird initialisiert und der Name wird gesetzt. + * @author Florian Alexy und Florian Hantzschel + */ public SpecificAiPlayerMedium() { super(); this.setName("AI Player Medium"); @@ -18,6 +22,7 @@ public class SpecificAiPlayerMedium extends AiPlayer{ /** * Ki Methode um zu schießen. + * @author Florian Alexy und Florian Hantzschel */ @Override public void aiShoot() { @@ -25,7 +30,13 @@ public class SpecificAiPlayerMedium extends AiPlayer{ // Shoot at the enemy and receive the hit response enemy.receiveShoot(nextShot); } - + + /** + * Nachdem receiveShoot beim gegner den schuss verarbeitet hat, + * wird diese Methode mit der antwort aufgerufen. + * @param hitResponse the hitresponse + * @author Florian Alexy und Florian Hantzschel + */ @Override public synchronized void receiveHit(HitResponse hitResponse) { super.receiveHit(hitResponse); @@ -38,6 +49,7 @@ public class SpecificAiPlayerMedium extends AiPlayer{ /** * Die Methode bestimmt welche Position als nächstes beschossen werden soll. * @return + * @author Florian Alexy und Florian Hantzschel */ public Point ComputeNextShot() { Point nextShot; @@ -61,6 +73,7 @@ public class SpecificAiPlayerMedium extends AiPlayer{ /** * Diese Methode erweitert die hitsQueue um die umliegenden Punkte die Schiffe seien könnten. * @param point + * @author Florian Alexy und Florian Hantzschel */ private void addAdjacentPoints(Point point) { int x = point.getX(); @@ -85,6 +98,7 @@ public class SpecificAiPlayerMedium extends AiPlayer{ * Diese Methode gibt zurück, ob eine Position schon beschossen wurde. (Boolean) * @param p Punkt der geprüft werden soll * @return wurde schon beschossen oder nicht. + * @author Florian Alexy und Florian Hantzschel */ private boolean alreadyShot(Point p) { @@ -96,6 +110,7 @@ public class SpecificAiPlayerMedium extends AiPlayer{ * Die Methode gibt zurück, ob eine Position auf dem Board ist. (Boolean) * @param point Punkt der geprüft werden soll * @return Ist auf dem Board oder nicht. + * @author Florian Alexy und Florian Hantzschel */ private boolean isValidPoint(Point point) { return point.getX() >= 0 && point.getX() < board.getSize() && From 44f04a454fc74e95b8e2f57a3cd123c8f9b56ddf Mon Sep 17 00:00:00 2001 From: Luca Conte Date: Mon, 23 Dec 2024 20:02:11 +0100 Subject: [PATCH 11/13] proper thread killing and online player myTurn handling --- src/AsyncSocket.java | 5 ++++- src/HumanPlayer.java | 1 - src/LocalPlayer.java | 12 ++++++++---- src/OnlinePlayer.java | 6 ------ src/OnlinePlayer_1_1_0.java | 32 ++++++++++++++++++++++++++++++-- 5 files changed, 42 insertions(+), 14 deletions(-) diff --git a/src/AsyncSocket.java b/src/AsyncSocket.java index 506309f..1937afb 100644 --- a/src/AsyncSocket.java +++ b/src/AsyncSocket.java @@ -225,7 +225,10 @@ public class AsyncSocket { try { this.socket.close(); - if (this.checkerThread != null) this.checkerThread.join(); + if (this.checkerThread != null) { + this.checkerThread.interrupt(); + this.checkerThread.join(); + } } catch (IOException e) { e.printStackTrace(); } catch (InterruptedException e) { diff --git a/src/HumanPlayer.java b/src/HumanPlayer.java index 6f00dbe..36203ec 100644 --- a/src/HumanPlayer.java +++ b/src/HumanPlayer.java @@ -9,7 +9,6 @@ public class HumanPlayer extends LocalPlayer { @Override public void shoot(Point point) { if (!this.myTurn) return; - this.myTurn = false; enemy.receiveShoot(point); } } diff --git a/src/LocalPlayer.java b/src/LocalPlayer.java index 2705263..aac063c 100644 --- a/src/LocalPlayer.java +++ b/src/LocalPlayer.java @@ -15,7 +15,11 @@ public class LocalPlayer extends Player { */ @Override public synchronized void receiveShoot(Point point) { - if (!this.enemy.myTurn) return; + if (!this.enemy.myTurn) { + System.out.println("enemy tried to fire when not their turn!"); + return; + } + this.enemy.myTurn = false; HitResponse hitResponse = board.getHitResponseOnPoint(point); if (!(hitResponse == null)){ @@ -29,7 +33,7 @@ public class LocalPlayer extends Player { switch (hitResponse.getType()) { case HIT, SUNK -> this.myTurn = false; case MISS -> this.myTurn = true; - case VICTORY -> GameController.getMainFrame().showPanelLose("", this); //TODO Was halt bei victory passiert ist hier wurder verloheren + case VICTORY -> GameController.getMainFrame().showPanelLose("LoseScreen", this); } GameController.getMainFrame().refreshGameBoard(); } @@ -45,7 +49,7 @@ public class LocalPlayer extends Player { switch (hitResponse.getType()) { case HIT, SUNK -> this.myTurn = true; case MISS -> this.myTurn = false; - case VICTORY -> GameController.getMainFrame().showPanelWin("", this); // TODO was halt beim victory passier ist hier wurde gewonnen + case VICTORY -> GameController.getMainFrame().showPanelWin("", this); } GameController.getMainFrame().refreshGameBoard(); } @@ -86,4 +90,4 @@ public class LocalPlayer extends Player { super.ready(); } -} \ No newline at end of file +} diff --git a/src/OnlinePlayer.java b/src/OnlinePlayer.java index 2db0a90..486a48d 100644 --- a/src/OnlinePlayer.java +++ b/src/OnlinePlayer.java @@ -22,12 +22,6 @@ public abstract class OnlinePlayer extends Player implements AsyncSocketListener public abstract void receive(String message); - @Override - public abstract void receiveShoot(Point point); - - @Override - public abstract void receiveHit(HitResponse hitResponse); - @Override public abstract void receiveCoin(boolean coin); diff --git a/src/OnlinePlayer_1_1_0.java b/src/OnlinePlayer_1_1_0.java index b401a6e..6ba3b96 100644 --- a/src/OnlinePlayer_1_1_0.java +++ b/src/OnlinePlayer_1_1_0.java @@ -58,7 +58,23 @@ public class OnlinePlayer_1_1_0 extends OnlinePlayer { Point point = new Point(data.get(0)); int typeIndex = Integer.parseInt(data.get(1)); if (Point.isValidSyntax(data.get(0)) && typeIndex >= 0 && typeIndex < HitResponseType.values().length){ - this.enemy.receiveHit(new HitResponse(typeIndex, point)); + + HitResponse hitResponse = new HitResponse(typeIndex, point); + + this.enemy.receiveHit(hitResponse); + + switch (hitResponse.getType()) { + case HIT, SUNK: + this.myTurn = false; + break; + case MISS: + this.myTurn = true; + break; + + case VICTORY: + // GameController.getMainFrame().showPanelWin("", this.enemy); + break; + } } } break; @@ -102,6 +118,18 @@ public class OnlinePlayer_1_1_0 extends OnlinePlayer { */ @Override public synchronized void receiveHit(HitResponse hitResponse) { + switch (hitResponse.getType()) { + case HIT, SUNK: + this.myTurn = true; + break; + case MISS: + this.myTurn = false; + break; + + case VICTORY: + // GameController.getMainFrame().showPanelLose("", this.enemy); + break; + } super.socket.send(new SocketPackage("HIT", hitResponse.toString())); } @@ -125,4 +153,4 @@ public class OnlinePlayer_1_1_0 extends OnlinePlayer { // SHOULD NEVER BE CALLED ON ONLINE PLAYER. ONLY ON HUMAN PLAYER return; } -} \ No newline at end of file +} From 9d51e708e50ec94f0f2550e55872504e0300420a Mon Sep 17 00:00:00 2001 From: Luca Conte Date: Mon, 23 Dec 2024 20:13:52 +0100 Subject: [PATCH 12/13] remove game board on win or lose --- src/MainFrame.java | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/MainFrame.java b/src/MainFrame.java index 1d0e16c..821417b 100644 --- a/src/MainFrame.java +++ b/src/MainFrame.java @@ -134,6 +134,12 @@ public class MainFrame extends JFrame { if(player != gameBoard.getP1()){ return; } + + this.gameBoard.getP1().destroy(); + this.gameBoard.getP2().destroy(); + this.gameBoard.removeAll(); + this.gameBoard = null; + WinScreen winScreen = new WinScreen(this); mainPanel.add(winScreen, panelName); mainPanel.revalidate(); @@ -151,8 +157,12 @@ public class MainFrame extends JFrame { if(player != gameBoard.getP1()){ return; } + this.gameBoard.getP1().destroy(); this.gameBoard.getP2().destroy(); + this.gameBoard.removeAll(); + this.gameBoard = null; + LoseScreen looseScreen = new LoseScreen(this); mainPanel.add(looseScreen,panelName); mainPanel.revalidate(); From e85f151b337cf40f38932d7b4a8aca1c8e443368 Mon Sep 17 00:00:00 2001 From: Luca Conte Date: Mon, 23 Dec 2024 20:28:06 +0100 Subject: [PATCH 13/13] a bit cleaner withdraw --- src/GameBoard.java | 9 +++------ src/LocalPlayer.java | 4 ++-- src/OnlinePlayer_1_1_0.java | 11 +++++++---- src/Player.java | 17 +++++++++++++++++ 4 files changed, 29 insertions(+), 12 deletions(-) diff --git a/src/GameBoard.java b/src/GameBoard.java index 4b6aa7a..f9f915d 100644 --- a/src/GameBoard.java +++ b/src/GameBoard.java @@ -56,12 +56,9 @@ public class GameBoard extends JPanel { List shipsP1 =p1.getBoard().getShips(); List shipsP2 =p2.getBoard().getShips(); - giveUpButton.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - // TODO Hier könnte Ihr Backend Code stehen - frame.showPanel("MainMenu"); - } + giveUpButton.addActionListener((e) -> { + frame.showPanel("MainMenu"); + p1.withdraw(); }); } diff --git a/src/LocalPlayer.java b/src/LocalPlayer.java index aac063c..ffd87c5 100644 --- a/src/LocalPlayer.java +++ b/src/LocalPlayer.java @@ -33,7 +33,7 @@ public class LocalPlayer extends Player { switch (hitResponse.getType()) { case HIT, SUNK -> this.myTurn = false; case MISS -> this.myTurn = true; - case VICTORY -> GameController.getMainFrame().showPanelLose("LoseScreen", this); + case VICTORY -> this.lose(); } GameController.getMainFrame().refreshGameBoard(); } @@ -49,7 +49,7 @@ public class LocalPlayer extends Player { switch (hitResponse.getType()) { case HIT, SUNK -> this.myTurn = true; case MISS -> this.myTurn = false; - case VICTORY -> GameController.getMainFrame().showPanelWin("", this); + case VICTORY -> this.win(); } GameController.getMainFrame().refreshGameBoard(); } diff --git a/src/OnlinePlayer_1_1_0.java b/src/OnlinePlayer_1_1_0.java index 69cfaf7..2ba932a 100644 --- a/src/OnlinePlayer_1_1_0.java +++ b/src/OnlinePlayer_1_1_0.java @@ -84,10 +84,7 @@ public class OnlinePlayer_1_1_0 extends OnlinePlayer { break; case "WITHDRAW": - //Found funny cheese to do this without GUI Access - HitResponse tmp_hit = new HitResponse(0, new Point(0,0)); - tmp_hit.setType(HitResponseType.VICTORY); - this.receiveHit(tmp_hit); + this.withdraw(); break; default: @@ -160,4 +157,10 @@ public class OnlinePlayer_1_1_0 extends OnlinePlayer { // SHOULD NEVER BE CALLED ON ONLINE PLAYER. ONLY ON HUMAN PLAYER return; } + + @Override + public void receiveWithdraw() { + this.socket.send(new SocketPackage("WITHDRAW")); + super.receiveWithdraw(); + } } diff --git a/src/Player.java b/src/Player.java index 4adf76c..8dfc776 100644 --- a/src/Player.java +++ b/src/Player.java @@ -137,6 +137,7 @@ public abstract class Player { * and players * * This method should be called at the end of a game + * This method should be called at the end of a game * * @author Luca Conte */ @@ -146,4 +147,20 @@ public abstract class Player { this.board = null; this.enemy = null; } + + public void win() { + GameController.getMainFrame().showPanelWin("", this); + } + public void lose() { + GameController.getMainFrame().showPanelLose("", this); + } + + public void withdraw() { + this.enemy.receiveWithdraw(); + this.lose(); + } + + public void receiveWithdraw(){ + this.win(); + } }