Compare commits

...

43 Commits

Author SHA1 Message Date
Joshua 48bc601a0d Added BoardDisplay, startet connecting FrontEnd/BackAnd.
Added new graphics.
Added startLocalGameLoadingScreen
2024-12-03 15:33:15 +01:00
Luca Conte f20896566c Merge pull request 'game-controller-adjustments' (#11) from game-controller-adjustments into main
Reviewed-on: #11
2024-12-03 12:48:14 +00:00
Luca Conte d9baeec957 make all methods static, add player name to start game method params 2024-12-03 13:47:36 +01:00
Luca Conte f166200499 add static main frame 2024-12-03 13:47:13 +01:00
Luca Conte 2c84e02261 Merge pull request 'Network and Frontend' (#10) from ole into main
Reviewed-on: #10
Reviewed-by: lgc <main@lugico.de>
2024-12-03 12:13:27 +00:00
ole 175bb20345 change idea settings 2024-12-03 13:11:06 +01:00
ole 0ce9e012dd Merge remote-tracking branch 'origin/lucasjoshua' into ole
# Conflicts:
#	src/startMultiplayerGame.java
2024-12-03 12:28:26 +01:00
ole 2160b5d410 add shoot to OnlinePlayer_1_1_0.java 2024-12-03 12:20:40 +01:00
Ole Wachtel 43545afb45 add coin flip and turn logic 2024-12-03 12:11:06 +01:00
Luca Conte addf542300 strip string before passing to handler 2024-11-30 18:43:04 +01:00
Luca Conte 1fb284eb1a add IAM Package 2024-11-30 18:40:04 +01:00
Luca Conte bdde2066f3 add getter and setter for name 2024-11-30 18:39:58 +01:00
Luca Conte ab1aae7798 add method to convert semester to board size 2024-11-30 18:39:41 +01:00
Luca Conte cecc44abf4 fix: remove board size from constructor 2024-11-30 18:28:05 +01:00
Luca Conte 998ff3d663 Merge branch 'networking' into networking-start-online-game 2024-11-30 18:16:27 +01:00
Luca Conte 2c6f9adf54 move board size out of player constructor 2024-11-30 18:15:07 +01:00
Luca Conte 3eeb4d25bd start online game 2024-11-30 17:58:24 +01:00
ole b1273e759d Merge remote-tracking branch 'origin/ole' into ole
# Conflicts:
#	src/OnlinePlayer.java
2024-11-30 17:15:51 +01:00
ole 6a4e157605 add: Network implementation 2024-11-30 17:09:44 +01:00
ole 22950cd155 add: Thread protection Player.java 2024-11-30 17:07:11 +01:00
ole 058d069ff2 change: all Points from java.awt.point too new Point.java 2024-11-30 17:06:25 +01:00
ole c2ca83c718 chore: remove all unjust imports 2024-11-30 17:04:29 +01:00
ole 5a48e7e0a9 Merge branch 'networking' into ole 2024-11-30 14:17:54 +01:00
Luca Conte 8bc64bd9ba move joined logic out of if statement 2024-11-30 14:14:29 +01:00
Luca Conte ff9ffbd628 sleep first in loop to avoid skipping sleep with continue 2024-11-30 14:13:15 +01:00
Luca Conte 7303f49d0d avoid nulls 2024-11-30 14:13:01 +01:00
ole 48a5958414 add Thread safety for Player 2024-11-30 13:48:50 +01:00
Luca Conte c92b3b3551 networking basis 2024-11-30 13:45:06 +01:00
Ole Wachtel a381c8d660 add OnlinePlayer Konstructer 2024-11-30 13:25:42 +01:00
Luca Conte d425e64fa0 Merge pull request 'hotfixes - so we can at least run it' (#9) from hotfixes into main
Reviewed-on: #9
2024-11-27 12:01:15 +00:00
Luca Conte b2a26c1f81 fix compiler errors 2024-11-27 13:00:18 +01:00
Luca Conte 73add1442b fix class names 2024-11-27 13:00:05 +01:00
Luca Conte 11c7dda19b fix deprecated function calls 2024-11-27 12:59:55 +01:00
alexy f3d56b37c7 Merge pull request 'Schiffe setzen Validierung hinzugefuegt' (#8) from oleFundF into main
Reviewed-on: #8
Reviewed-by: flo <florian.hantzschel@stud.hs-hannover.de>
2024-11-26 16:00:08 +00:00
FlorianAlexy c8b3f4f2db Schiffe setzen Validierung hinzugefuegt
Florian und Florian haben eine schoene Validierung zum setzen der Position eines Schiffes hinzugefuegt.
2024-11-26 16:43:25 +01:00
Luca Conte ec789dd562 Merge pull request 'ole' (#7) from ole into main
Reviewed-on: #7
Reviewed-by: lgc <main@lugico.de>
2024-11-26 14:01:01 +00:00
ole d00e12e72f Merge remote-tracking branch 'origin/lucasjoshua' into ole
# Conflicts:
#	src/HalloSchiffeVersenken.java
2024-11-26 14:56:19 +01:00
eyFlorian aaa9d57f68 Easy/MediumAI
Haben eine sehr einfache und Medium KI hinzugefügt. F&F

Fragenaufwerfende Methoden:

https://cdn.discordapp.com/attachments/1296860613212897413/1310209916325068894/WhatsApp_Bild_2024-11-24_um_12.31.02_fb836c3d.jpg?ex=67446392&is=67431212&hm=82f37b83dc5e711622abb43abe51edd62833450dddf91ed524991da6d0981f38&
2024-11-24 12:47:45 +01:00
ole ce4995fb94 add Shoot logik and Structure for backend 2024-11-15 17:35:35 +01:00
ole 22937ab45d Merge pull request 'Kronjuwild' (#6) from Kronjuwild into main
Reviewed-on: #6
Reviewed-by: ole <git@peer-ole.de>
2024-11-14 16:23:21 +00:00
Luca Conte b9a0a21503 fix some player stuff 2024-11-12 15:18:16 +01:00
Ole Wachtel 579ce9831d Merge branch 'FF24' into ole 2024-11-12 15:06:33 +01:00
eyFlorian 8ae51f6316 Locales Spiel Initialisierung
Florian und Florian Haben 3 Stunden an diesem kack gearbeitet.
Player, AiPlayer und jeweils die Boards wurden erstellt und Initialisiert.
Erweiterung zu Hitresponse /- type für die Board.
2024-11-03 12:39:19 +01:00
29 changed files with 1120 additions and 46 deletions

View File

@ -1,8 +1,7 @@
<component name="libraryTable">
<library name="jlayer-1.0.3">
<CLASSES>
<root url="jar://$USER_HOME$/Downloads/jlayer-master/jlayer-master/target/jlayer-1.0.3.jar!/" />
<root url="jar://$USER_HOME$/Downloads/jlayer-1.0.3.jar!/" />
<root url="jar://$PROJECT_DIR$/libs/jlayer-1.0.3.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES />

BIN
graphics/botPlayerEasy.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 854 B

BIN
graphics/botPlayerHard.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 875 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 889 B

24
src/AiPlayer.java Normal file
View File

@ -0,0 +1,24 @@
import java.util.Random;
public abstract class AiPlayer extends LocalPlayer {
public AiPlayer() {}
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);
}
public void AiSetShips() {
for(int i = 0; i < super.board.getShips().size(); i++) { // Interiert durch alle Shiffe
while(!super.board.getShips().get(i).setPosition(RandomPoint(), super.board.getShips(), super.board.getSize())) {}
} // Versucht das Aktuelle Shiff zu setzten und wiederholt solange bis es funktioniert
return;
}
public void AiShoot() {
super.board.hit(RandomPoint());
return;
}
}

80
src/AsyncSocket.java Normal file
View File

@ -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();
}
}
}

View File

@ -0,0 +1,3 @@
public interface AsyncSocketListener {
public void receive(String message);
}

View File

@ -1,2 +1,75 @@
import java.util.List;
public class Board {
private List<HitResponse> hits;
private List<Ship> ships;
private final int size;
public Board(int size) {
this.size = size;
this.createShip(size - 13);
}
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);
if ( type == HitResponseType.SUNK) {
for (int ii = 0; i < this.ships.size(); ii++) {
if (!this.ships.get(ii).isSunk()) {
response.setType(type);
this.addHits(response);
return response;
}
}
response.setType(HitResponseType.VICTORY);
this.addHits(response);
return response;
} else if (type == HitResponseType.HIT) {
response.setType(type);
this.addHits(response);
return response;
}
}
this.addHits(response);
return response;
}
private void createShip(int semester){
List<ShipData> shipData = Ship.semeterList.get(semester -1);
for (int i = 0; i < shipData.size(); i++) {
this.ships.add(new Ship(shipData.get(i).size(), shipData.get(i).name()));
}
}
public List<Ship> getShips() {
return ships;
}
public synchronized boolean addHits(HitResponse hitResponse) {
if (this.getHitResponsOnPoint(hitResponse.getPoint()) == null){
this.hits.add(hitResponse);
return true;
}
return false;
}
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);
}
}
return null;
}
public int getSize() {
return this.size;
}
}

15
src/BoardDisplay.java Normal file
View File

@ -0,0 +1,15 @@
import javax.swing.*;
import java.awt.*;
// Erstellt Spielfeld für Spieler1/Spieler2
public class BoardDisplay extends JPanel {
public BoardDisplay(int gridSize, Icon buttonIcon) {
super(new GridLayout(gridSize, gridSize));
// Buttons zum Panel hinzufügen
for (int i = 0; i < gridSize; i++) {
for (int j = 0; j < gridSize; j++) {
add(new JButton(buttonIcon));
}
}
}
}

View File

@ -26,6 +26,7 @@ public class GameBoard extends JPanel {
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");
@ -68,10 +69,14 @@ public class GameBoard extends JPanel {
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));
int gridSize = GameController.semesterToBoardSize(semesterCounter); // Größe des Spielfelds
// Spielfelder werden in BoardDisplay erstellt
//JPanel ownBoardPanel = new JPanel(new GridLayout(gridSize, gridSize));
//JPanel opponentBoardPanel = new JPanel(new GridLayout(gridSize, gridSize));
JPanel ownBoardPanel = new BoardDisplay(gridSize, gameBoardEmtpy);
JPanel opponentBoardPanel = new BoardDisplay(gridSize, gameBoardEmtpy);
/* Alter code ohne BoardDisplay
// Buttons für das eigene Spielfeld hinzufügen
for (int i = 0; i < gridSize; i++) {
for (int j = 0; j < gridSize; j++) {
@ -85,6 +90,7 @@ public class GameBoard extends JPanel {
opponentBoardPanel.add(new JButton(gameBoardEmtpy));
}
}
*/
// Panel für beide Spielfelder (nebeneinander in der Mitte)
JPanel centerPanel = new JPanel();
@ -99,7 +105,7 @@ public class GameBoard extends JPanel {
add(centerPanel, BorderLayout.CENTER);
}
GameBoard(MainFrame frame,int semesterCounter) {
GameBoard(MainFrame frame, int semesterCounter,Player p1, Player p2) {
buildPanel(frame, semesterCounter);
/*
rightPlayerRightButton.addActionListener(new ActionListener() {

191
src/GameController.java Normal file
View File

@ -0,0 +1,191 @@
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 {
private static MainFrame mainFrame;
public static MainFrame getMainFrame() {
return GameController.mainFrame;
}
public static void setMainFrame(MainFrame mainFrame) {
GameController.mainFrame = mainFrame;
}
// 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 static HashMap<String, Class<? extends OnlinePlayer>> supportedVersions = new HashMap<>(Map.of(
"1.1.0", OnlinePlayer_1_1_0.class
));
public static void startOnlineGame(Class<? extends LocalPlayer> localPlayerClass, String localPlayerName, InetSocketAddress address, int size) throws IOException {
AsyncSocket clientSocket;
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<String> opponentSupportedVersions = socketPackage.splitData();
String usedVersion = findMostRecentVersion(new ArrayList<String>(supportedVersions.keySet()), opponentSupportedVersions);
if (usedVersion == null) {
throw new RuntimeException("No common versions found");
}
// instantiate players
Class<? extends OnlinePlayer> 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 static String findMostRecentVersion(List<String> versions1, List<String> 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 static 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 static boolean checkVersionString(String versionString) {
return versionString != null && versionString.matches("\\d+\\.\\d+\\.\\d+");
}
public static void startLocalGame(Class<? extends LocalPlayer> localPlayerClass, String localPlayerName, Class<? extends AiPlayer> enemyClass, int size) {
LocalPlayer localPlayer;
AiPlayer aiPlayer;
try {
localPlayer = localPlayerClass.getDeclaredConstructor().newInstance();
aiPlayer = enemyClass.getDeclaredConstructor().newInstance();
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException("Unable to instantiate players");
}
localPlayer.createBoard(size);
aiPlayer.createBoard(size);
startGameWithInstancedPlayers(localPlayer, aiPlayer);
}
private static void startGameWithInstancedPlayers(LocalPlayer p1, Player p2) {
p1.setEnemy(p2);
p2.setEnemy(p1);
// TODO: frontend configuration
}
}

View File

@ -1,17 +1,12 @@
public class HalloSchiffeVersenken {
public static void main(String[] args) throws InterruptedException {
//LUCAS CODE
//coinToss ct = new coinToss();
//MainMenuModel model = new MainMenuModel();
//MainMenuView view = new MainMenuView(new MainFrame());
//MainMenuController controller = new MainMenuController(model, view);
MainFrame mf = new MainFrame();
mf.setVisible(true);
//System.out.println("HelloSchiffeVersenekn");
System.out.println("HelloSchiffeVersenekn");
/*
System.out.println("sound");
SoundHandler.playSound("hit");
@ -20,10 +15,7 @@ public class HalloSchiffeVersenken {
SoundHandler.setSoundOn(false);
System.out.println("sound off");
SoundHandler.playSound("hit");
*/
//JOSHUA CODE
//startLocalGame localTest = new startLocalGame();
//startMultiplayerGame multiplayerTest = new startMultiplayerGame();
}
}

View File

@ -1,6 +1,41 @@
import java.awt.*;
public class HitResponse {
private HitResponseType type;
private Point point;
public HitResponse(HitResponseType type, Point point) {
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;
}
public Point getPoint() {
return this.point;
}
public void setType(HitResponseType type) {
this.type = type;
}
@Override
public String toString() {
return this.getPoint().toString() + " " + this.type.ordinal();
}
public HitResponseType getType() {
return type;
}
}

4
src/HumanPlayer.java Normal file
View File

@ -0,0 +1,4 @@
public class HumanPlayer extends LocalPlayer {
}

58
src/LocalPlayer.java Normal file
View File

@ -0,0 +1,58 @@
import java.util.Random;
public class LocalPlayer extends Player {
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);
}
}

View File

@ -35,6 +35,7 @@ public class MainFrame extends JFrame {
// Verschiedene Panels erstellen und hinzufügen
MainMenuView mainMenuView = new MainMenuView(this);
startLocalGame localGame = new startLocalGame(this);
//startLocalGameLoadingScreen LocalGameLoadingScreen = new startLocalGameLoadingScreen(this);
startMultiplayerGame multiplayerGame = new startMultiplayerGame(this);
coinToss coinToss = new coinToss(this);
Verbinden verbinden = new Verbinden(this);
@ -60,6 +61,7 @@ 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;
@ -73,12 +75,14 @@ public class MainFrame extends JFrame {
cardLayout.show(mainPanel, panelName); // Show the panel
}
// --- ShowPanel der startLocalGame Klasse
public void showPanelSLG(String panelName,int semesterCounter) {
// --- ShowPanel der startLocalGameLoadingScreen Klasse (DURCH BACKEND AUFGERUFEN)
public void showPanelSLG(String panelName,int semesterCounter, Player p1, Player p2) {
this.semesterCounter = semesterCounter;
//if (!isPanelPresent(panelName)) { //TODO potentiell raus
GameBoard gameBoard = new GameBoard(this, semesterCounter);
// gameBoard muss player übergeben bekommen
GameBoard gameBoard = new GameBoard(this, semesterCounter, p1, p2);
//mainPanel.add(mainMenuView, "MainMenu");
mainPanel.add(gameBoard, panelName);
mainPanel.revalidate(); // Refresh
mainPanel.repaint();
@ -86,6 +90,20 @@ public class MainFrame extends JFrame {
cardLayout.show(mainPanel, panelName); // Show the panel
}
// --- ShowPanel der startLocalGame Klasse
public void showPanelSLGLS(String panelName,int semesterCounter) {
this.semesterCounter = semesterCounter;
// gameBoard muss player übergeben bekommen
startLocalGameLoadingScreen LocalGameLoadingScreen = new startLocalGameLoadingScreen(this, semesterCounter);
mainPanel.add(LocalGameLoadingScreen, 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()) {
@ -96,6 +114,20 @@ public class MainFrame extends JFrame {
return false;
} */
// Methoden für übergabe von playern an GameBoard
/*
public void setPlayerData() {
this.semesterCounter = semesterCounter;
//if (!isPanelPresent(panelName)) { //TODO potentiell raus
// gameBoard muss player übergeben bekommen
GameBoard gameBoard = new GameBoard(this, semesterCounter);
mainPanel.add(gameBoard, panelName);
mainPanel.revalidate(); // Refresh
mainPanel.repaint();
}*/
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
MainFrame frame = new MainFrame();

View File

@ -1,5 +1,25 @@
import java.net.Socket;
public abstract class OnlinePlayer extends Player implements AsyncSocketListener{
protected AsyncSocket socket;
protected int wantedBoardSize;
protected boolean hasReceivedCoinPackage;
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);
public abstract class OnlinePlayer extends Player{
private Socket socket;
}

View File

@ -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<String> 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()));
}
}

View File

@ -1,26 +1,48 @@
import java.awt.*;
import java.util.Random;
public abstract class Player {
private boolean myTurn;
private boolean isServer;
private boolean waitingForResponse;
private Player enemy;
private String name;
private Board board;
protected boolean myTurn;
protected boolean isServer;
protected boolean waitingForResponse;
protected Player enemy;
protected String name;
protected Board board;
protected boolean myCoin;
public void receiveShoot(Point point) {
protected boolean sendCoin;
protected boolean haseReceivedCoin;
public Player() {
this.haseReceivedCoin = false;
this.sendCoin = false;
}
public void receiveHit(HitResponse hitResponse) {
public void createBoard(int size) {
this.board = new Board(size);
}
public void click(Point point) {
public abstract void receiveShoot(Point point);
}
public abstract void receiveHit(HitResponse hitResponse);
public abstract void shoot(Point point);
public void beginTrun() {
}
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);
}

45
src/Point.java Normal file
View File

@ -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+$");
}
}

162
src/Ship.java Normal file
View File

@ -0,0 +1,162 @@
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
record ShipData (int size, String name){}
public class Ship {
static List<List<ShipData>> 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;
private boolean horizontal;
private Point position;
private String name;
private int hitsOnMe;
private boolean sunk;
public Ship (int size, String name) {
this.size = size;
this.name = name;
this.horizontal = false; //true = von Punkt aus nach rechts; false = von Punkt aus nach unten
this.position = null;
this.hitsOnMe = 0;
this.sunk = false;
}
public boolean setPosition(Point pos, List<Ship> shipsList, int boardSize) {
// ueberpruefe boundaries
if (pos.getX() < 0 || pos.getY() < 0 || pos.getX() >= boardSize || pos.getY() >= boardSize) {
return false;
}
// bestimme die Endposition anhand der Ausrichtung
int endX = pos.getX();
int endY = pos.getY();
if (this.horizontal) { // rechts links
endX = pos.getX() + this.size - 1;
if (endX >= boardSize) {
return false;
}
} else { // oben unten
endY = pos.getY() + this.size - 1;
if (endY >= boardSize) {
return false;
}
}
// Liste an Punkten die das Schiff einnehmen wuerde
List<Point> shipPoints = new ArrayList<>();
for (int i = 0; i < this.size; 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));
}
// ueberlappen mit anderen Schiffen pruefen
for (Ship otherShip : shipsList) {
// eigenes Schiff ueberspringen
if (otherShip == this) {
continue;
}
// ueberspringe falls noch nicht gesetzt
if (otherShip.position == null) {
continue;
}
// Punkte die das andere Schiff besetzt
List<Point> otherShipPoints = otherShip.getOccupiedPoints();
// ueberlappen checken
for (Point p : shipPoints) {
if (otherShipPoints.contains(p)) {
// ueberlappen entdeckt
return false;
}
}
}
// kein ueberlappen also setze das Schiff
this.position = pos;
return true;
}
public List<Point> getOccupiedPoints() {
List<Point> 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;
}
public Point getPosition() {
return position;
}
public boolean isShipOnPos(Point pos){
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;
}
public HitResponseType shootOnShip(Point pos) {
if (this.isShipOnPos(pos)) {
hitsOnMe++;
if (hitsOnMe >= size) {
this.sunk = true;
return HitResponseType.SUNK;
} else {
return HitResponseType.HIT;
}
} else {
return HitResponseType.MISS;
}
}
public boolean isSunk() {
return sunk;
}
}

57
src/SocketPackage.java Normal file
View File

@ -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<String> splitData() {
return Arrays.asList(this.data.split(" "));
}
}

View File

@ -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;

View File

@ -0,0 +1,3 @@
public class SpecificAiPlayerEasy extends AiPlayer{
}

View File

@ -0,0 +1,3 @@
public class SpecificAiPlayerHard extends AiPlayer{
}

View File

@ -0,0 +1,68 @@
import java.util.ArrayList;
import java.util.List;
public class SpecificAiPlayerMedium extends AiPlayer{
private List<Point> hitsQueue = new ArrayList<>();
@Override
public void AiShoot() {
Point nextShot = ComputeNextShot();
// Shoot at the enemy and receive the hit response
enemy.receiveShoot(nextShot);
HitResponse hitResponse = enemy.board.getHitResponsOnPoint(nextShot);
// If it's a hit or sunk, add adjacent cells to the hitsQueue
if (hitResponse.getHitResponse() == HitResponseType.HIT) {
addAdjacentPoints(nextShot);
}
}
public Point ComputeNextShot() {
Point nextShot;
// Prioritize shots from the hitsQueue
while (!hitsQueue.isEmpty()) {
nextShot = hitsQueue.remove(0);
if (!alreadyShot(nextShot)) {
return nextShot;
}
}
// If hitsQueue is empty, pick a random point that hasn't been shot
do {
nextShot = RandomPoint();
} while (alreadyShot(nextShot));
return nextShot;
}
private void addAdjacentPoints(Point point) {
int x = point.getX();
int y = point.getY();
// Possible adjacent positions (up, down, left, right)
Point[] adjacentPoints = {
new Point(x, y - 1),
new Point(x, y + 1),
new Point(x - 1, y),
new Point(x + 1, y)
};
for (Point p : adjacentPoints) {
if (isValidPoint(p) && !alreadyShot(p) && !hitsQueue.contains(p)) {
hitsQueue.add(p);
}
}
}
private boolean alreadyShot(Point p) {
// TODO Auto-generated method stub
throw new UnsupportedOperationException("Unimplemented method 'alreadyShot'");
}
private boolean isValidPoint(Point point) {
return point.getX() >= 0 && point.getX() < board.getSize() &&
point.getY() >= 0 && point.getY() < board.getSize();
}
}

View File

@ -1,9 +1,12 @@
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class startLocalGame extends JPanel {
// Player
//Player p1;
//Player p2;
// Funktionshilfen
int semesterCounter = 1; // Semester Counter Label
String leftPlayerNickname = "Spieler 1";
@ -12,7 +15,9 @@ public class startLocalGame extends JPanel {
// Grafiken
ImageIcon backButtonIcon = new ImageIcon("graphics/backButton.png");
ImageIcon humanPlayerIcon = new ImageIcon("graphics/humanPlayer.png");
ImageIcon aiPlayerIcon = new ImageIcon("graphics/aiPlayer.png");
ImageIcon aiPlayerEasyIcon = new ImageIcon("graphics/botPlayerEasy.png");
ImageIcon aiPlayerNormalIcon = new ImageIcon("graphics/botPlayerNormal.png");
ImageIcon aiPlayerHardIcon = new ImageIcon("graphics/botPlayerHard.png");
// Labels und Buttons
JLabel frameTitle = new JLabel("Lokales Spiel");
@ -20,7 +25,7 @@ public class startLocalGame extends JPanel {
JLabel leftPlayerName = new JLabel("Name");
JLabel rightPlayerName = new JLabel("KI-Level");
JLabel leftPlayerIcon = new JLabel(humanPlayerIcon);
JLabel rightPlayerIcon = new JLabel(aiPlayerIcon);
JLabel rightPlayerIcon = new JLabel(aiPlayerEasyIcon);
JLabel semesterCounterLabel = new JLabel(String.valueOf(semesterCounter));
JButton backButton = new JButton(backButtonIcon);
@ -94,6 +99,7 @@ public class startLocalGame extends JPanel {
rightPlayerTextField.setText(rightPlayerNickname);
add(rightPlayerTextField);
// ActionListener für Buttons
semesterUpButton.addActionListener(e -> {
if (semesterCounter < 6) {
@ -143,12 +149,67 @@ public class startLocalGame extends JPanel {
backButton.addActionListener(e -> frame.showPanel("MainMenu"));
startButton.addActionListener(e -> frame.showPanelSLG("GameBoard", semesterCounter)); // TODO ECHTE FUNKTION EINFÜGEN
//startButton.addActionListener(e -> frame.showPanelSLG("GameBoard", semesterCounter,p1, p2)); // TODO ECHTE FUNKTION EINFÜGEN
startButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
frame.showPanelSLGLS("startLocalGameLoadingScreen", semesterCounter); //TODO
if (leftPlayerIcon.getIcon() == humanPlayerIcon) {// TODO Diverse KiIcons erstellen für diffs
if (rightPlayerIcon.getIcon() == aiPlayerEasyIcon) {
GameController.startLocalGame(HumanPlayer.class, leftPlayerNickname, SpecificAiPlayerEasy.class, GameController.semesterToBoardSize(semesterCounter));
} else if (rightPlayerIcon.getIcon() == aiPlayerNormalIcon) {
GameController.startLocalGame(HumanPlayer.class, leftPlayerNickname, SpecificAiPlayerMedium.class, GameController.semesterToBoardSize(semesterCounter));
} else if (rightPlayerIcon.getIcon() == aiPlayerHardIcon) {
GameController.startLocalGame(HumanPlayer.class, leftPlayerNickname, SpecificAiPlayerEasy.class, GameController.semesterToBoardSize(semesterCounter));
}
} else if (leftPlayerIcon.getIcon() == aiPlayerEasyIcon) {
if (rightPlayerIcon.getIcon() == aiPlayerEasyIcon) {
GameController.startLocalGame(HumanPlayer.class, leftPlayerNickname, SpecificAiPlayerEasy.class, GameController.semesterToBoardSize(semesterCounter));
} else if (rightPlayerIcon.getIcon() == aiPlayerNormalIcon) {
GameController.startLocalGame(HumanPlayer.class, leftPlayerNickname, SpecificAiPlayerMedium.class, GameController.semesterToBoardSize(semesterCounter));
} else if (rightPlayerIcon.getIcon() == aiPlayerHardIcon) {
GameController.startLocalGame(HumanPlayer.class, leftPlayerNickname, SpecificAiPlayerEasy.class, GameController.semesterToBoardSize(semesterCounter));
}
} else if (rightPlayerIcon.getIcon() == aiPlayerNormalIcon) {
if (rightPlayerIcon.getIcon() == aiPlayerEasyIcon) {
GameController.startLocalGame(HumanPlayer.class, leftPlayerNickname, SpecificAiPlayerEasy.class, GameController.semesterToBoardSize(semesterCounter));
} else if (rightPlayerIcon.getIcon() == aiPlayerNormalIcon) {
GameController.startLocalGame(HumanPlayer.class, leftPlayerNickname, SpecificAiPlayerMedium.class, GameController.semesterToBoardSize(semesterCounter));
} else if (rightPlayerIcon.getIcon() == aiPlayerHardIcon) {
GameController.startLocalGame(HumanPlayer.class, leftPlayerNickname, SpecificAiPlayerEasy.class, GameController.semesterToBoardSize(semesterCounter));
}
} else if (rightPlayerIcon.getIcon() == aiPlayerHardIcon) {
if (rightPlayerIcon.getIcon() == aiPlayerEasyIcon) {
GameController.startLocalGame(HumanPlayer.class, leftPlayerNickname, SpecificAiPlayerEasy.class, GameController.semesterToBoardSize(semesterCounter));
} else if (rightPlayerIcon.getIcon() == aiPlayerNormalIcon) {
GameController.startLocalGame(HumanPlayer.class, leftPlayerNickname, SpecificAiPlayerMedium.class, GameController.semesterToBoardSize(semesterCounter));
} else if (rightPlayerIcon.getIcon() == aiPlayerHardIcon) {
GameController.startLocalGame(HumanPlayer.class, leftPlayerNickname, SpecificAiPlayerEasy.class, GameController.semesterToBoardSize(semesterCounter));
}
}
}
});
// GameController.startLocalGame(SpecificAiPlayerEasy.class, rightPlayerNickname, SpecificAiPlayerEasy.class, GameController.semesterToBoardSize(semesterCounter));
// TODO Zwischenscreen einfügen ("Spiel wird erstellt")
/*
if (leftPlayerIcon.getIcon() == humanPlayerIcon) {// TODO Diverse KiIcons erstellen für diffs
if (rightPlayerIcon.getIcon() == aiPlayerIcon) { // Platzhalter da nur eine KI gerade exisitert
//...
GameController.startLocalGame(HumanPlayer.class, leftPlayerNickname, SpecificAiPlayerEasy.class, GameController.semesterToBoardSize(semesterCounter));
}
} else if (leftPlayerIcon.getIcon() == aiPlayerIcon) {
//...
GameController.startLocalGame(SpecificAiPlayerEasy.class, rightPlayerNickname, SpecificAiPlayerEasy.class, GameController.semesterToBoardSize(semesterCounter));
}
*/
}
private void toggleLeftPlayerIcon() {
if (leftPlayerIcon.getIcon() == humanPlayerIcon) {
leftPlayerIcon.setIcon(aiPlayerIcon);
leftPlayerIcon.setIcon(aiPlayerEasyIcon);
} else {
leftPlayerIcon.setIcon(humanPlayerIcon);
}
@ -156,7 +217,7 @@ public class startLocalGame extends JPanel {
private void toggleRightPlayerIcon() {
if (rightPlayerIcon.getIcon() == humanPlayerIcon) {
rightPlayerIcon.setIcon(aiPlayerIcon);
rightPlayerIcon.setIcon(aiPlayerEasyIcon);
} else {
rightPlayerIcon.setIcon(humanPlayerIcon);
}

View File

@ -0,0 +1,20 @@
import javax.swing.*;
import java.awt.*;
public class startLocalGameLoadingScreen extends JPanel{
startLocalGameLoadingScreen(MainFrame frame, int semesterCounter) {
// Layout setzen
setLayout(new BorderLayout());
// Label mit dem Text erstellen
JLabel loadingLabel = new JLabel("Spiel wird gestartet, bitte warten...");
loadingLabel.setHorizontalAlignment(SwingConstants.CENTER); // Horizontal zentrieren
loadingLabel.setVerticalAlignment(SwingConstants.CENTER); // Vertikal zentrieren
// Schriftgröße anpassen (optional)
loadingLabel.setFont(new Font("Arial", Font.PLAIN, 18));
// Label zum Panel hinzufügen
add(loadingLabel, BorderLayout.CENTER);
}
}

View File

@ -1,4 +1,6 @@
import javax.swing.*;
import java.io.IOException;
import java.net.InetSocketAddress;
public class startMultiplayerGame extends JPanel {
// Funktionshilfen
@ -76,6 +78,15 @@ public class startMultiplayerGame extends JPanel {
PlayerTextField.setText(PlayerNickname);
add(PlayerTextField);
/* TODO: Muss in Lucas klasse rein.
public static void startOnlineGame(Class<? extends LocalPlayer> localPlayerClass, String localPlayerName, InetSocketAddress
address, int size) throws IOException {
*/
//GameController.startOnlineGame(...);
// ActionListener für Buttons
// SEMESTERBUTTONS
semesterUpButton.addActionListener(e -> {