diff --git a/.idea/libraries/jlayer_1_0_3.xml b/.idea/libraries/jlayer_1_0_3.xml index b09f4ed..1ff1dec 100644 --- a/.idea/libraries/jlayer_1_0_3.xml +++ b/.idea/libraries/jlayer_1_0_3.xml @@ -1,8 +1,7 @@ - - + diff --git a/graphics/gameboardempty.png b/graphics/gameboardempty.png new file mode 100644 index 0000000..366ceab Binary files /dev/null and b/graphics/gameboardempty.png differ diff --git a/graphics/gameboardx.png b/graphics/gameboardx.png new file mode 100644 index 0000000..18e1fed Binary files /dev/null and b/graphics/gameboardx.png differ diff --git a/src/AiPlayer.java b/src/AiPlayer.java index ca8c82d..2d3ba33 100644 --- a/src/AiPlayer.java +++ b/src/AiPlayer.java @@ -1,11 +1,8 @@ import java.util.Random; -import java.awt.Point; -public abstract class AiPlayer extends Player { +public abstract class AiPlayer extends LocalPlayer { - public AiPlayer(int size) { - super(size); - } + public AiPlayer() {} public Point RandomPoint() { Random random = new Random(); // Pseudo Random für zufallszahlen int posx = random.nextInt(super.board.getSize()); // Generiert 0 - 13 diff --git a/src/AsyncSocket.java b/src/AsyncSocket.java new file mode 100644 index 0000000..0201e4e --- /dev/null +++ b/src/AsyncSocket.java @@ -0,0 +1,80 @@ +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.OutputStreamWriter; +import java.io.PrintWriter; +import java.net.Socket; + +public class AsyncSocket { + private Socket socket; + private Thread checkerThread; + private AsyncSocketListener handler; + private boolean shouldStop = false; + + private BufferedReader in; + private PrintWriter out; + + public AsyncSocket(Socket socket, AsyncSocketListener handler) throws IOException { + this.socket = socket; + + this.in = new BufferedReader(new InputStreamReader(this.socket.getInputStream())); + this.out = new PrintWriter(new OutputStreamWriter(this.socket.getOutputStream())); + + this.handler = handler; + + this.checkerThread = new Thread(() -> { + while (!this.shouldStop) { + try { + Thread.sleep(100); + } catch (InterruptedException e) { + e.printStackTrace(); + } + try { + if (!this.in.ready()) continue; + if (this.handler == null) continue; + + String message = this.in.readLine(); + if (message.length() <= 0) continue; + + message = message.strip(); + this.handler.receive(message); + } catch (IOException e) { + e.printStackTrace(); + } + } + }); + this.checkerThread.start(); + } + + public void setHandler(AsyncSocketListener handler) { + this.handler = handler; + } + + + public void send(SocketPackage socketPackage) { + this.sendLine(socketPackage.toString()); + } + public void send(String packageName) { + this.send(packageName, ""); + } + public void send(String packageName, String packageContent) { + if (packageContent.length() > 0) { + packageContent = " " + packageContent; + } + this.sendLine(packageName + packageContent); + } + + public void sendLine(String message) { + this.out.print(message + "\r\n"); + } + + public void close() { + this.shouldStop = true; + + try { + this.socket.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } +} \ No newline at end of file diff --git a/src/AsyncSocketListener.java b/src/AsyncSocketListener.java new file mode 100644 index 0000000..a8c78ba --- /dev/null +++ b/src/AsyncSocketListener.java @@ -0,0 +1,3 @@ +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 ae205a3..eaf8d41 100644 --- a/src/Board.java +++ b/src/Board.java @@ -1,4 +1,4 @@ -import java.awt.*; + import java.util.List; public class Board { @@ -13,7 +13,7 @@ public class Board { this.createShip(size - 13); } - public HitResponse hit (Point point){ + public synchronized HitResponse hit (Point point){ HitResponse response = new HitResponse(HitResponseType.MISS,point); for (int i = 0; i < this.ships.size(); i++) { HitResponseType type = this.ships.get(i).shootOnShip(point); @@ -50,7 +50,7 @@ public class Board { return ships; } - public boolean addHits(HitResponse hitResponse) { + public synchronized boolean addHits(HitResponse hitResponse) { if (this.getHitResponsOnPoint(hitResponse.getPoint()) == null){ this.hits.add(hitResponse); return true; @@ -58,7 +58,7 @@ public class Board { return false; } - public HitResponse getHitResponsOnPoint(Point point) { + public synchronized HitResponse getHitResponsOnPoint(Point point) { for (int i = 0; i < this.hits.size(); i++){ if (this.hits.get(i).getPoint().equals(point)){ return this.hits.get(i); diff --git a/src/GameBoard.java b/src/GameBoard.java index 61bdb72..43c3974 100644 --- a/src/GameBoard.java +++ b/src/GameBoard.java @@ -1,3 +1,114 @@ -public class GameBoard { +import javax.swing.*; +import java.awt.*; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +public class GameBoard extends JPanel { + // Funktionshilfen + //int semesterCounter = 1; //TODO: ersetzen durch param von vorpanel + + // Grafiken + ImageIcon backButtonIcon = new ImageIcon("graphics/backButton.png"); + ImageIcon gameBoardEmtpy = new ImageIcon("graphics/gameboardempty.png"); + ImageIcon gameBoardX = new ImageIcon("graphics/gameboardx.png"); + + // Labels + JLabel frameTitle = new JLabel("GameBoard"); + JLabel kontextText = new JLabel("Beispielhafter Kontext-Text"); + //kontextText.setFont(new Font("Roboto", Font.BOLD, 24)); //TODO setFont fixen + + JButton backButton = new JButton(backButtonIcon); + // Eigene ModulButtons + JButton leftPlayerModul1 = new JButton("Modul 1"); //TODO: Dynamische Namen durch abgleich mit Semester + JButton leftPlayerModul2 = new JButton("Modul 2"); + JButton leftPlayerModul3 = new JButton("Modul 3"); + JButton leftPlayerModul4 = new JButton("Modul 4"); + JButton leftPlayerModul5 = new JButton("Modul 5"); + JButton leftPlayerModul6 = new JButton("Modul 6"); + JButton leftPlayerModul7 = new JButton("Reset"); + // Gegnerische ModulButtons + JButton rightPlayerModul1 = new JButton("Modul 1"); + JButton rightPlayerModul2 = new JButton("Modul 2"); + JButton rightPlayerModul3 = new JButton("Modul 3"); + JButton rightPlayerModul4 = new JButton("Modul 4"); + JButton rightPlayerModul5 = new JButton("Modul 5"); + JButton rightPlayerModul6 = new JButton("Modul 6"); + JButton rightPlayerModul7 = new JButton("Bereit"); + + public void buildPanel(MainFrame frame, int semesterCounter) { + // Hauptlayout - BorderLayout für die Anordnung der Komponenten + setLayout(new BorderLayout()); + + // Panel für das Kontext-Text-Feld + JPanel headerPanel = new JPanel(); + headerPanel.setLayout(new BorderLayout()); + headerPanel.add(kontextText, BorderLayout.WEST); + headerPanel.add(backButton, BorderLayout.EAST); + + // Panel für die Buttons des linken Spielers (ganz links) + JPanel leftButtonsPanel = new JPanel(); + leftButtonsPanel.setLayout(new GridLayout(7, 1)); // 6 Buttons untereinander + leftButtonsPanel.add(leftPlayerModul1); + leftButtonsPanel.add(leftPlayerModul2); + leftButtonsPanel.add(leftPlayerModul3); + leftButtonsPanel.add(leftPlayerModul4); + leftButtonsPanel.add(leftPlayerModul5); + leftButtonsPanel.add(leftPlayerModul6); + leftButtonsPanel.add(leftPlayerModul7); + + // Panel für die Buttons des rechten Spielers (ganz rechts) + JPanel rightButtonsPanel = new JPanel(); + rightButtonsPanel.setLayout(new GridLayout(7, 1)); // 6 Buttons untereinander + rightButtonsPanel.add(rightPlayerModul1); + rightButtonsPanel.add(rightPlayerModul2); + rightButtonsPanel.add(rightPlayerModul3); + rightButtonsPanel.add(rightPlayerModul4); + rightButtonsPanel.add(rightPlayerModul5); + rightButtonsPanel.add(rightPlayerModul6); + rightButtonsPanel.add(rightPlayerModul7); + + // Spielfelder erstellen (eigenes und gegnerisches) + int gridSize = 13 + semesterCounter; // Größe des Spielfelds + JPanel ownBoardPanel = new JPanel(new GridLayout(gridSize, gridSize)); + JPanel opponentBoardPanel = new JPanel(new GridLayout(gridSize, gridSize)); + + // Buttons für das eigene Spielfeld hinzufügen + for (int i = 0; i < gridSize; i++) { + for (int j = 0; j < gridSize; j++) { + ownBoardPanel.add(new JButton(gameBoardEmtpy)); + } + } + + // Buttons für das gegnerische Spielfeld hinzufügen + for (int i = 0; i < gridSize; i++) { + for (int j = 0; j < gridSize; j++) { + opponentBoardPanel.add(new JButton(gameBoardEmtpy)); + } + } + + // Panel für beide Spielfelder (nebeneinander in der Mitte) + JPanel centerPanel = new JPanel(); + centerPanel.setLayout(new GridLayout(1, 2, 20, 0)); // 2 Spielfelder nebeneinander, mit Abstand von 20 Pixeln + centerPanel.add(ownBoardPanel); + centerPanel.add(opponentBoardPanel); + + // Panels dem Hauptlayout hinzufügen + add(leftButtonsPanel, BorderLayout.WEST); + add(rightButtonsPanel, BorderLayout.EAST); + add(headerPanel, BorderLayout.NORTH); + add(centerPanel, BorderLayout.CENTER); + } + + GameBoard(MainFrame frame,int semesterCounter) { + buildPanel(frame, semesterCounter); + /* + rightPlayerRightButton.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + toggleRightPlayerIcon(); + updateTextFields(); + } + }); */ + backButton.addActionListener(e -> frame.showPanel("MainMenu")); + } } diff --git a/src/GameController.java b/src/GameController.java index 1d562eb..44b0444 100644 --- a/src/GameController.java +++ b/src/GameController.java @@ -1,11 +1,160 @@ +import java.io.IOException; +import java.net.InetSocketAddress; +import java.net.ServerSocket; +import java.net.Socket; +import java.net.SocketTimeoutException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + public class GameController { + + // Connection timeout for client sockets in milliseconds + public static final int CONNECTION_TIMEOUT = 10 * 1000; + + public static int semesterToBoardSize(int semester) { + return semester + 13; + } + public HashMap> supportedVersions = new HashMap<>(Map.of( + "1.1.0", OnlinePlayer_1_1_0.class + )); - public void startOnlineGame() { - // fuck you Luca and Ole von Florian und nicht von Florian - } + public void startOnlineGame(Class localPlayerClass, InetSocketAddress address, int size) throws IOException { + AsyncSocket clientSocket; - public void startLocalGame(Class localPlayerClass, Class enemyClass, int size) throws InstantiationException, IllegalAccessException { + boolean localPlayerIsServer = address.getHostName() == null; + + if (localPlayerIsServer) { + // SERVER MODE + + ServerSocket serverSocket = new ServerSocket(address.getPort()); + + System.out.println("Waiting for client connection..."); + + clientSocket = new AsyncSocket(serverSocket.accept(), null); + + serverSocket.close(); + } else { + // CLIENT MODE + + Socket socket = new Socket(); + + try { + socket.connect(address, CONNECTION_TIMEOUT); + + clientSocket = new AsyncSocket(socket, null); + } catch (SocketTimeoutException e) { + e.printStackTrace(); + throw new RuntimeException("Connection timed out"); + } finally { + socket.close(); + } + + } + + clientSocket.send("VERSION", "Gruppe03 " + String.join(" ", supportedVersions.keySet())); + clientSocket.setHandler((message) -> { + + SocketPackage socketPackage = new SocketPackage(message); + if (socketPackage.getName().equals("VERSION")) { + + List opponentSupportedVersions = socketPackage.splitData(); + + String usedVersion = findMostRecentVersion(new ArrayList(supportedVersions.keySet()), opponentSupportedVersions); + + if (usedVersion == null) { + throw new RuntimeException("No common versions found"); + } + + // instantiate players + Class onlinePlayerClass = supportedVersions.get(usedVersion); + + LocalPlayer localPlayer; + OnlinePlayer onlinePlayer; + try { + localPlayer = localPlayerClass.getDeclaredConstructor().newInstance(); + onlinePlayer = onlinePlayerClass.getDeclaredConstructor().newInstance((Integer)size, clientSocket); + } catch (Exception e) { + e.printStackTrace(); + throw new RuntimeException("Unable to instantiate players"); + } + + localPlayer.isServer = localPlayerIsServer; + onlinePlayer.isServer = !localPlayerIsServer; + + startGameWithInstancedPlayers(localPlayer, onlinePlayer); + + } else { + throw new RuntimeException("Unexpected Package received before game initialisation"); + } + }); + + } + + /** + * finds the largest common version in two lists of version strings + * @return null if no common versions are found + */ + public String findMostRecentVersion(List versions1, List versions2) { + if (versions1 == null || versions2 == null) return null; + String largestCommonVersion = null; + for (String v1 : versions1) { + if (!checkVersionString(v1)) continue; + + for (String v2 : versions2) { + if (!checkVersionString(v2)) continue; + + // strings within the lists must be equal + // if no largest common version has been found or currently checked version is larger than + // previous largest common version, new largest version has been found + if (compareVersions(v1, v2) == 0 && (largestCommonVersion == null || compareVersions(v1, largestCommonVersion) >= 1)) { + largestCommonVersion = v1; + continue; + } + } + } + return largestCommonVersion; + } + + /** + * compares two version strings + * @return + * 0 if versions are equal + * 1 if version1 is more recent than version2 + * -1 otherwise + */ + public int compareVersions(String version1, String version2) { + if (!checkVersionString(version1) || !checkVersionString(version2)) { + throw new IllegalArgumentException("Version is not valid version string"); + } + + String[] version1Split = version1.split("\\."); + String[] version2Split = version2.split("\\."); + + for (int i = 0; i < version1Split.length; i++) { + int v1 = Integer.parseInt(version1Split[i]); + int v2 = Integer.parseInt(version2Split[i]); + + if (v1 == v2) continue; + if (v1 > v2) { + return 1; + } else { + return -1; + } + } + return 0; + } + + /** + * checks if a provided string matches the format of a version number + */ + public boolean checkVersionString(String versionString) { + return versionString != null && versionString.matches("\\d+\\.\\d+\\.\\d+"); + } + + public void startLocalGame(Class localPlayerClass, Class enemyClass, int size) { LocalPlayer localPlayer; AiPlayer aiPlayer; @@ -14,10 +163,20 @@ public class GameController { aiPlayer = enemyClass.getDeclaredConstructor().newInstance(); } catch (Exception e) { e.printStackTrace(); - return; + throw new RuntimeException("Unable to instantiate players"); } - localPlayer.setEnemy(aiPlayer); - aiPlayer.setEnemy(localPlayer); + + localPlayer.createBoard(size); + aiPlayer.createBoard(size); + + startGameWithInstancedPlayers(localPlayer, aiPlayer); + } + + private void startGameWithInstancedPlayers(LocalPlayer p1, Player p2) { + p1.setEnemy(p2); + p2.setEnemy(p1); + + // TODO: frontend configuration } } \ No newline at end of file diff --git a/src/HitResponse.java b/src/HitResponse.java index bc9fca0..2e5f0ca 100644 --- a/src/HitResponse.java +++ b/src/HitResponse.java @@ -1,4 +1,4 @@ -import java.awt.*; + public class HitResponse { private HitResponseType type; @@ -8,6 +8,15 @@ public class HitResponse { this.type = type; this.point = point; } + + public HitResponse (int typeIndex, Point point) { + if (typeIndex >= 0 && typeIndex < HitResponseType.values().length) { + this.type = HitResponseType.values()[typeIndex]; + this.point = point; + } else { + throw new IllegalArgumentException(); + } + } public HitResponseType getHitResponse() { return this.type; @@ -20,4 +29,13 @@ public class HitResponse { public void setType(HitResponseType type) { this.type = type; } + + @Override + public String toString() { + return this.getPoint().toString() + " " + this.type.ordinal(); + } + + public HitResponseType getType() { + return type; + } } diff --git a/src/HumanPlayer.java b/src/HumanPlayer.java index 6723e71..ae0e298 100644 --- a/src/HumanPlayer.java +++ b/src/HumanPlayer.java @@ -1,7 +1,4 @@ public class HumanPlayer extends LocalPlayer { - public HumanPlayer(int size) { - super(size); - } } diff --git a/src/JoinGame.java b/src/JoinGame.java index e980b58..b3ac5a0 100644 --- a/src/JoinGame.java +++ b/src/JoinGame.java @@ -1,10 +1,10 @@ import java.awt.*; -import java.awt.event.ActionEvent; -import javax.swing.JFrame; import javax.swing.*; public class JoinGame extends JPanel { - JLabel spielBeitretenLabel= new JLabel("Spiel beitreten"); + ImageIcon backButtonIcon = new ImageIcon("graphics/backButton.png"); + + JLabel spielBeitretenLabel; JLabel ipLabel = new JLabel("IP-Adresse"); JLabel portLabel = new JLabel("Port"); @@ -12,17 +12,25 @@ public class JoinGame extends JPanel { JTextField portTextField = new JTextField(20); JButton losButton = new JButton("Los!"); + JButton backButton = new JButton(backButtonIcon); Font robotoFont = new Font("Roboto", Font.BOLD, 45); - public JoinGame(MainFrame frame) { + public JoinGame(MainFrame frame,int g) { setLayout(null); - buildPanel(frame); + buildPanel(frame,g); } - private void buildPanel(MainFrame frame) { + private void buildPanel(MainFrame frame,int g) { + if(g==1){ + spielBeitretenLabel= new JLabel("Spiel beitreten"); + }else{ + spielBeitretenLabel= new JLabel("Spiel erstellen"); + } + spielBeitretenLabel.setBounds(20,20,700, 100); losButton.setBounds(320, 225, 100, 50); + backButton.setBounds(1380, 20, 80, 80); ipLabel.setBounds(50, 125, 200, 30); portLabel.setBounds(50, 200, 200, 30); @@ -39,6 +47,9 @@ public class JoinGame extends JPanel { add(losButton); add(ipTextField); add(portTextField); - } + add(backButton); + backButton.addActionListener(e -> frame.showPanel("MultiplayerGame")); + losButton.addActionListener(e -> frame.showPanel("Verbinden")); + } } diff --git a/src/LocalPlayer.java b/src/LocalPlayer.java index cfa7cab..5bc6dd9 100644 --- a/src/LocalPlayer.java +++ b/src/LocalPlayer.java @@ -1,8 +1,58 @@ +import java.util.Random; + public class LocalPlayer extends Player { - LocalPlayer(int size) { - super(size); + public LocalPlayer(){ + super(); + Random random = new Random(); + this.myCoin = random.nextBoolean(); + } + + @Override + public synchronized void receiveShoot(Point point) { + HitResponse hitResponse = board.getHitResponsOnPoint(point); + if (!(hitResponse == null)){ + enemy.receiveHit(hitResponse); + + } else { + hitResponse = this.board.hit(point); + enemy.receiveHit(hitResponse); + } + + switch (hitResponse.getType()) { + case HIT, SUNK -> this.myTurn = false; + case MISS -> this.myTurn = true; + case VICTORY -> System.out.println("Game Over"); //TODO Was halt bei victory passiert ist hier wurder verloheren + } + } + + @Override + public synchronized void receiveHit(HitResponse hitResponse) { + enemy.board.addHits(hitResponse); + switch (hitResponse.getType()) { + case HIT, SUNK -> this.myTurn = true; + case MISS -> this.myTurn = false; + case VICTORY -> System.out.println("Win"); // TODO was halt beim victory passier ist hier wurde gewonnen + } + } + + @Override + public synchronized void receiveCoin(boolean coin) { + if (!this.haseReceivedCoin) { + boolean result = coin ^ this.myCoin; // XOR + this.myTurn = result == this.isServer; + this.haseReceivedCoin = true; + } + } + + public void sendCoin() { + enemy.receiveCoin(this.myCoin); + } + + @Override + public void shoot(Point point){ + this.myTurn = false; + enemy.receiveShoot(point); } - } \ No newline at end of file diff --git a/src/MainFrame.java b/src/MainFrame.java index f8a5204..2e53062 100644 --- a/src/MainFrame.java +++ b/src/MainFrame.java @@ -6,6 +6,16 @@ public class MainFrame extends JFrame { private CardLayout cardLayout; private JPanel mainPanel; + // ---------- // + // Diverse Hilfsvariablen (für Parameterübergabe etc.) + // Von startMultiplayerGame an JoinGame + int localMult; + + // Von startLocalGame an GameBoard + int semesterCounter; + // ---------- // + + public MainFrame() { setTitle("Studium Versenken"); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); @@ -27,13 +37,18 @@ public class MainFrame extends JFrame { startLocalGame localGame = new startLocalGame(this); startMultiplayerGame multiplayerGame = new startMultiplayerGame(this); coinToss coinToss = new coinToss(this); - JoinGame joinGame = new JoinGame(this); + Verbinden verbinden = new Verbinden(this); + //JoinGame joinGame = new JoinGame(this,localMult); + //GameBoard gameBoard = new GameBoard(this, localMult); mainPanel.add(mainMenuView, "MainMenu"); mainPanel.add(localGame, "LocalGame"); mainPanel.add(multiplayerGame, "MultiplayerGame"); mainPanel.add(coinToss, "coinToss"); - mainPanel.add(joinGame, "JoinGame"); + mainPanel.add(verbinden, "Verbinden"); + //mainPanel.add(joinGame, "JoinGame"); + //mainPanel.add(gameBoard, "GameBoard"); + // Hauptpanel in JFrame hinzufügen add(mainPanel); @@ -45,6 +60,41 @@ public class MainFrame extends JFrame { public void showPanel(String panelName) { cardLayout.show(mainPanel, panelName); } + // --- ShowPanel der startMultiplayerGame Klasse + public void showPanelSMG(String panelName, int num) { + this.localMult = num; + + //if (!isPanelPresent(panelName)) { //TODO potentiell raus + JoinGame joinGame = new JoinGame(this, localMult); + mainPanel.add(joinGame, panelName); + mainPanel.revalidate(); // Refresh + mainPanel.repaint(); + //} + + cardLayout.show(mainPanel, panelName); // Show the panel + } + // --- ShowPanel der startLocalGame Klasse + public void showPanelSLG(String panelName,int semesterCounter) { + this.semesterCounter = semesterCounter; + + //if (!isPanelPresent(panelName)) { //TODO potentiell raus + GameBoard gameBoard = new GameBoard(this, semesterCounter); + mainPanel.add(gameBoard, panelName); + mainPanel.revalidate(); // Refresh + mainPanel.repaint(); + //} + + cardLayout.show(mainPanel, panelName); // Show the panel + } + /* TODO ist dies unnötig? + private boolean isPanelPresent(String panelName) { + for (Component component : mainPanel.getComponents()) { + if (panelName.equals(mainPanel.getClientProperty("name"))) { + return true; + } + } + return false; + } */ public static void main(String[] args) { SwingUtilities.invokeLater(() -> { diff --git a/src/MainMenuView.java b/src/MainMenuView.java index 958d610..af862f3 100644 --- a/src/MainMenuView.java +++ b/src/MainMenuView.java @@ -1,5 +1,6 @@ import java.awt.*; import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; import javax.swing.JFrame; import javax.swing.*; @@ -36,9 +37,29 @@ public class MainMenuView extends JPanel { add(soundButton); // Event Listener für Buttons - lokalButton.addActionListener(e -> frame.showPanel("LocalGame")); - multiButton.addActionListener(e -> frame.showPanel("MultiplayerGame")); - soundButton.addActionListener(e -> toggleMute()); + lokalButton.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + System.out.println("Lokales Spiel ausgewählt."); + frame.showPanel("LocalGame"); // Panel wechseln + } + }); + + multiButton.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + System.out.println("Multiplayer-Spiel ausgewählt."); + frame.showPanel("MultiplayerGame"); // Panel wechseln + } + }); + + soundButton.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + System.out.println("Soundbutton geklickt."); + toggleMute(); + } + }); } private void toggleMute() { diff --git a/src/OnlinePlayer.java b/src/OnlinePlayer.java index 66316d6..88ac476 100644 --- a/src/OnlinePlayer.java +++ b/src/OnlinePlayer.java @@ -1,11 +1,25 @@ -import java.net.Socket; +public abstract class OnlinePlayer extends Player implements AsyncSocketListener{ + protected AsyncSocket socket; + protected int wantedBoardSize; -public abstract class OnlinePlayer extends Player{ - private Socket socket; + protected boolean hasReceivedCoinPackage; - public OnlinePlayer(int size, Socket socket) { - super(size); + public OnlinePlayer(int size, AsyncSocket socket) { this.socket = socket; + this.wantedBoardSize = size; + socket.setHandler(this); //TODO Auto-generated constructor stub } + + 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 new file mode 100644 index 0000000..6c2a784 --- /dev/null +++ b/src/OnlinePlayer_1_1_0.java @@ -0,0 +1,91 @@ +import java.util.List; + +public class OnlinePlayer_1_1_0 extends OnlinePlayer { + public OnlinePlayer_1_1_0(int size, AsyncSocket socket) { + super(size, socket); + } + + + + @Override + public void receive(String message) { + SocketPackage p = new SocketPackage(message); + + List data = p.splitData(); + switch (p.getName()) { + case "IAM": + if (data.size() < 2) break; + if (this.board != null) break; + + int semester = Integer.parseInt(data.get(0)); + String username = p.getData().substring(data.get(0).length() + 1); + + int usedBoardSize = Math.min(GameController.semesterToBoardSize(semester), this.wantedBoardSize); + + this.setName(username); + this.createBoard(usedBoardSize); + this.enemy.createBoard(usedBoardSize); + + break; + + // TODO: IAMU + + case "COIN": + if(!this.hasReceivedCoinPackage && (p.getData().equals("1") || p.getData().equals("0"))){ + this.myCoin = p.getData().equals("1"); + enemy.receiveCoin(this.myCoin); + this.hasReceivedCoinPackage = true; + } + break; + + + case "SHOOT": + if (Point.isValidSyntax(p.getData())){ + Point point = new Point(p.getData()); + this.enemy.receiveShoot(point); + } + break; + + case "HIT": + if (data.size()==2){ + 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)); + } + } + break; + + case "CHAT": + //TODO CHAT + break; + + default: + //nichts passier da Paket ungültig + break; + } + } + + @Override + public synchronized void receiveShoot(Point point){ + super.socket.send(new SocketPackage("SHOOT",point.toString())); + } + + @Override + public synchronized void receiveHit(HitResponse hitResponse) { + super.socket.send(new SocketPackage("HIT", hitResponse.toString())); + } + + @Override + public synchronized void receiveCoin(boolean coin) { + if (!this.haseReceivedCoin) { + super.socket.send(new SocketPackage("COIN", String.valueOf(coin ? 1 : 0))); + this.haseReceivedCoin = true; + } + } + + @Override + public synchronized void shoot(Point point) { + super.socket.send(new SocketPackage("SHOOT", point.toString())); + } +} \ No newline at end of file diff --git a/src/Player.java b/src/Player.java index 192b3f4..faf9abb 100644 --- a/src/Player.java +++ b/src/Player.java @@ -1,5 +1,4 @@ -import java.awt.*; -import java.util.List; +import java.util.Random; public abstract class Player { protected boolean myTurn; @@ -8,27 +7,26 @@ public abstract class Player { protected Player enemy; protected String name; protected Board board; + protected boolean myCoin; - public Player(int size) { + protected boolean sendCoin; + + protected boolean haseReceivedCoin; + + public Player() { + this.haseReceivedCoin = false; + this.sendCoin = false; + } + + public void createBoard(int size) { this.board = new Board(size); } - public void receiveShoot(Point point) { - HitResponse hitResponse = board.getHitResponsOnPoint(point); - if (!(hitResponse == null)){ - enemy.receiveHit(hitResponse); - } else { - enemy.receiveHit(this.board.hit(point)); - } - } + public abstract void receiveShoot(Point point); - public void receiveHit(HitResponse hitResponse) { - enemy.board.addHits(hitResponse); - } + public abstract void receiveHit(HitResponse hitResponse); - public void click(Point point) { - - } + public abstract void shoot(Point point); public void beginTrun() { @@ -37,4 +35,14 @@ public abstract class Player { public void setEnemy(Player enemy) { this.enemy = enemy; } + + public void setName(String name) { + this.name = name; + } + public String getName() { + return this.name; + } + + + public abstract void receiveCoin(boolean coin); } diff --git a/src/Point.java b/src/Point.java new file mode 100644 index 0000000..bf2b127 --- /dev/null +++ b/src/Point.java @@ -0,0 +1,45 @@ +public class Point { + private int x; + private int y; + + public Point (int x, int y) { + this.setX(x); + this.setY(y); + } + public Point (String str) { + if (Point.isValidSyntax(str)) { + this.setX(str.charAt(0)); + this.setY(Integer.parseInt(str.substring(1))); + } else { + throw new IllegalArgumentException("String ist keine gültige Koordinate"); + } + } + + @Override + public String toString() { + return (char) ('A' + this.x) + String.valueOf(this.y); + } + + public int getX() { + return x; + } + + public int getY() { + return y; + } + + public void setX(int x) { + this.x = x; + } + + public void setY(int y) { + this.y = y; + } + public void setX(char c) { + this.x = c - 'A'; + } + + public static boolean isValidSyntax(String str) { + return str.matches("^[A-Z]\\d+$"); + } +} diff --git a/src/Ship.java b/src/Ship.java index de6cbff..0c3c7f6 100644 --- a/src/Ship.java +++ b/src/Ship.java @@ -1,6 +1,4 @@ - -import java.awt.Point; import java.util.ArrayList; import java.util.Arrays; import java.util.List; @@ -65,21 +63,21 @@ public class Ship { public boolean setPosition(Point pos, List shipsList, int boardSize) { // ueberpruefe boundaries - if (pos.x < 0 || pos.y < 0 || pos.x >= boardSize || pos.y >= boardSize) { + if (pos.getX() < 0 || pos.getY() < 0 || pos.getX() >= boardSize || pos.getY() >= boardSize) { return false; } // bestimme die Endposition anhand der Ausrichtung - int endX = pos.x; - int endY = pos.y; + int endX = pos.getX(); + int endY = pos.getY(); if (this.horizontal) { // rechts links - endX = pos.x + this.size - 1; + endX = pos.getX() + this.size - 1; if (endX >= boardSize) { return false; } } else { // oben unten - endY = pos.y + this.size - 1; + endY = pos.getY() + this.size - 1; if (endY >= boardSize) { return false; } @@ -88,8 +86,8 @@ public class Ship { // Liste an Punkten die das Schiff einnehmen wuerde List shipPoints = new ArrayList<>(); for (int i = 0; i < this.size; i++) { - int x = this.horizontal ? pos.x + i : pos.x; //falls horizontal dann pos.x + i ansonsten pos.x - int y = this.horizontal ? pos.y : pos.y + i; + int x = this.horizontal ? pos.getX() + i : pos.getX(); //falls horizontal dann pos.x + i ansonsten pos.x + int y = this.horizontal ? pos.getY() : pos.getY() + i; shipPoints.add(new Point(x, y)); } @@ -125,8 +123,8 @@ public class Ship { return points; } for (int i = 0; i < this.size; i++) { - int x = this.horizontal ? this.position.x + i : this.position.x; - int y = this.horizontal ? this.position.y : this.position.y + 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; @@ -137,8 +135,8 @@ public class Ship { } public boolean isShipOnPos(Point pos){ - if ((this.horizontal && pos.y == this.position.y && pos.x >= this.position.x && pos.x < this.position.x + size) || - (!(this.horizontal) && pos.x == this.position.x && pos.y >= this.position.y && pos.y < this.position.y + size)) { + if ((this.horizontal && pos.getY() == this.position.getY() && pos.getX() >= this.position.getX() && pos.getX() < this.position.getX() + size) || + (!(this.horizontal) && pos.getX() == this.position.getX() && pos.getY() >= this.position.getY() && pos.getY() < this.position.getY() + size)) { return true; } return false; diff --git a/src/SocketPackage.java b/src/SocketPackage.java new file mode 100644 index 0000000..0dabd58 --- /dev/null +++ b/src/SocketPackage.java @@ -0,0 +1,57 @@ +import java.util.Arrays; +import java.util.List; +public class SocketPackage { + + private String name = ""; + private String data = ""; + + public SocketPackage(String name, String data) { + this.setName(name); + this.setData(data); + } + public SocketPackage() { + this("",""); + } + public SocketPackage(String message) { + if (message.length() <= 0) { + throw new IllegalArgumentException("Socket message cannot be empty."); + } + String[] components = message.split(" "); + this.setName(components[0]); + if (components.length > 1) { + this.setData(message.substring(components[0].length() + 1)); + } else { + this.setData(""); + } + } + + public void setName(String name) { + if (name == null) name = ""; + this.name = name.toUpperCase(); + } + + public void setData(String data) { + if (data == null) data = ""; + this.data = data; + } + + public String getName() { + return this.name; + } + + public String getData() { + return this.data; + } + + public String toString() { + if (this.data == null || this.data.length() == 0) { + return this.name; + } else { + return this.name + " " + this.data; + } + } + + public List splitData() { + return Arrays.asList(this.data.split(" ")); + } +} diff --git a/src/SoundHandler.java b/src/SoundHandler.java index d7b385b..f9d04a3 100644 --- a/src/SoundHandler.java +++ b/src/SoundHandler.java @@ -3,7 +3,6 @@ import javazoom.jl.player.Player; import java.io.FileInputStream; import java.io.FileNotFoundException; -import java.util.ArrayList; import java.util.HashMap; import java.util.Map; diff --git a/src/SpecificAiPlayerEasy.java b/src/SpecificAiPlayerEasy.java index c3ac64f..2e4a62c 100644 --- a/src/SpecificAiPlayerEasy.java +++ b/src/SpecificAiPlayerEasy.java @@ -1,7 +1,3 @@ public class SpecificAiPlayerEasy extends AiPlayer{ - - public SpecificAiPlayerEasy(int size) { - super(size); - } } diff --git a/src/SpecificAiPlayerHard.java b/src/SpecificAiPlayerHard.java index a28fa6c..a8d5dd4 100644 --- a/src/SpecificAiPlayerHard.java +++ b/src/SpecificAiPlayerHard.java @@ -1,7 +1,3 @@ public class SpecificAiPlayerHard extends AiPlayer{ - - public SpecificAiPlayerHard(int size) { - super(size); - } } diff --git a/src/SpecificAiPlayerMedium.java b/src/SpecificAiPlayerMedium.java index c122f43..81561b2 100644 --- a/src/SpecificAiPlayerMedium.java +++ b/src/SpecificAiPlayerMedium.java @@ -1,15 +1,10 @@ import java.util.ArrayList; import java.util.List; -import java.awt.Point; public class SpecificAiPlayerMedium extends AiPlayer{ private List hitsQueue = new ArrayList<>(); - public SpecificAiPlayerMedium(int size) { - super(size); - } - @Override public void AiShoot() { Point nextShot = ComputeNextShot(); @@ -43,8 +38,8 @@ public class SpecificAiPlayerMedium extends AiPlayer{ } private void addAdjacentPoints(Point point) { - int x = point.x; - int y = point.y; + int x = point.getX(); + int y = point.getY(); // Possible adjacent positions (up, down, left, right) Point[] adjacentPoints = { @@ -67,7 +62,7 @@ public class SpecificAiPlayerMedium extends AiPlayer{ } private boolean isValidPoint(Point point) { - return point.x >= 0 && point.x < board.getSize() && - point.y >= 0 && point.y < board.getSize(); + return point.getX() >= 0 && point.getX() < board.getSize() && + point.getY() >= 0 && point.getY() < board.getSize(); } } \ No newline at end of file diff --git a/src/Verbinden.java b/src/Verbinden.java new file mode 100644 index 0000000..ca4feb7 --- /dev/null +++ b/src/Verbinden.java @@ -0,0 +1,23 @@ +import javax.swing.*; +import java.awt.*; + +public class Verbinden extends JPanel{ + + ImageIcon backButtonIcon = new ImageIcon("graphics/backButton.png"); + + JLabel verbindenLabel = new JLabel("Verbinde . . .",SwingConstants.CENTER); + + Font robotoFont = new Font("Roboto", Font.BOLD, 45); + + public Verbinden(MainFrame frame) { + setLayout(null); + buildPanel(frame); + } + + private void buildPanel(MainFrame frame) { + setLayout(new BorderLayout()); + verbindenLabel.setFont(robotoFont.deriveFont(50f)); + add(verbindenLabel, BorderLayout.CENTER); + } + } + diff --git a/src/startLocalGame.java b/src/startLocalGame.java index 8dcc513..8b01131 100644 --- a/src/startLocalGame.java +++ b/src/startLocalGame.java @@ -1,5 +1,4 @@ import javax.swing.*; -import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; @@ -143,7 +142,7 @@ public class startLocalGame extends JPanel { backButton.addActionListener(e -> frame.showPanel("MainMenu")); - startButton.addActionListener(e -> frame.showPanel("coinToss")); // TODO ECHTE FUNKTION EINFÜGEN + startButton.addActionListener(e -> frame.showPanelSLG("GameBoard", semesterCounter)); // TODO ECHTE FUNKTION EINFÜGEN } private void toggleLeftPlayerIcon() { diff --git a/src/startMultiplayerGame.java b/src/startMultiplayerGame.java index 4598994..e1d00be 100644 --- a/src/startMultiplayerGame.java +++ b/src/startMultiplayerGame.java @@ -1,12 +1,9 @@ import javax.swing.*; -import java.awt.*; -import java.awt.event.ActionEvent; public class startMultiplayerGame extends JPanel { // Funktionshilfen int semesterCounter = 1; // Semester Counter Label String PlayerNickname = "Spieler 1"; - // Grafiken ImageIcon backButtonIcon = new ImageIcon("graphics/backButton.png"); ImageIcon humanPlayerIcon = new ImageIcon("graphics/humanPlayer.png"); @@ -109,7 +106,8 @@ public class startMultiplayerGame extends JPanel { // ActionListener für den "Back" Button, um zum vorherigen Panel zurückzukehren backButton.addActionListener(e -> frame.showPanel("MainMenu")); - joinGameButton.addActionListener(e -> frame.showPanel("JoinGame")); + joinGameButton.addActionListener(e -> frame.showPanelSMG("JoinGame",1)); + createGameButton.addActionListener(e -> frame.showPanelSMG("JoinGame",0)); } // TOGGLE METHODEN