diff --git a/src/AiPlayer.java b/src/AiPlayer.java index ea6f42b..724233c 100644 --- a/src/AiPlayer.java +++ b/src/AiPlayer.java @@ -1,9 +1,16 @@ +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; import java.util.Random; -public abstract class AiPlayer extends LocalPlayer { + +public abstract class AiPlayer extends LocalPlayer implements Runnable { + + List shootThreads; public AiPlayer() { this.setName("AI Player"); + this.shootThreads = new ArrayList<>(); } public Point RandomPoint() { Random random = new Random(); // Pseudo Random für zufallszahlen @@ -11,8 +18,15 @@ public abstract class AiPlayer extends LocalPlayer { int posy = random.nextInt(super.board.getSize()); // return new Point(posx,posy); } + + @Override + public void createBoard(int size) { + super.createBoard(size); + this.aiSetShips(); + this.ready(); + } - public void AiSetShips() { + 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())) {} @@ -20,8 +34,63 @@ public abstract class AiPlayer extends LocalPlayer { return; } - public void AiShoot() { - super.board.hit(RandomPoint()); + public void aiShoot() { + this.enemy.receiveShoot(RandomPoint()); return; } + + @Override + public synchronized void receiveHit(HitResponse hitResponse) { + super.receiveHit(hitResponse); + if (this.myTurn) { + Thread t = new Thread(this); + t.start(); + this.shootThreads.add(t); + } + + } + + @Override + public synchronized void receiveShoot(Point point) { + super.receiveShoot(point); + if (this.myTurn) { + Thread t = new Thread(this); + t.start(); + this.shootThreads.add(t); + } + } + + + @Override + public void beginTurn() { + Thread t = new Thread(this); + t.start(); + this.shootThreads.add(t); + } + + public void run() { + Iterator i = this.shootThreads.iterator(); + while(i.hasNext()) { + Thread thread = i.next(); + if (!thread.isAlive()) { + try { + thread.join(); + i.remove(); + } catch (InterruptedException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + + } + + try { + Thread.sleep(300); + } catch (InterruptedException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + + this.aiShoot(); + } } \ No newline at end of file diff --git a/src/GameController.java b/src/GameController.java index f76b7f7..35b0764 100644 --- a/src/GameController.java +++ b/src/GameController.java @@ -159,13 +159,17 @@ public class GameController { e.printStackTrace(); throw new RuntimeException("Unable to instantiate players"); } + + localPlayer.isServer = true; + aiPlayer.isServer = false; + + localPlayer.setEnemy(aiPlayer); + aiPlayer.setEnemy(localPlayer); + localPlayer.createBoard(size); aiPlayer.createBoard(size); - localPlayer.setEnemy(aiPlayer); - aiPlayer.setEnemy(localPlayer); - localPlayer.setName(localPlayerName); startGameWithInstancedPlayers(localPlayer, aiPlayer, size); diff --git a/src/MainFrame.java b/src/MainFrame.java index 02db6b1..ea49617 100644 --- a/src/MainFrame.java +++ b/src/MainFrame.java @@ -119,6 +119,9 @@ public class MainFrame extends JFrame { } public void refreshGameBoard() { + if(this.gameBoard == null) { + return; + } this.gameBoard.refresh(); } } \ No newline at end of file diff --git a/src/SoundHandler.java b/src/SoundHandler.java index ade013e..0db2f8c 100644 --- a/src/SoundHandler.java +++ b/src/SoundHandler.java @@ -6,6 +6,7 @@ import java.io.FileInputStream; import java.io.FileNotFoundException; import java.util.ArrayList; import java.util.HashMap; +import java.util.Iterator; import java.util.Map; public class SoundHandler { @@ -35,12 +36,14 @@ public class SoundHandler { thread.start(); runningThreads.add(thread); } - for (Thread oldThread : runningThreads) { + Iterator i = runningThreads.iterator(); + while (i.hasNext()) { + Thread oldThread = i.next(); if (!oldThread.isAlive()) { try { oldThread.join(); - runningThreads.remove(oldThread); + i.remove(); System.out.println("cleared thread"); } catch (InterruptedException e) { e.printStackTrace(); diff --git a/src/SpecificAiPlayerEasy.java b/src/SpecificAiPlayerEasy.java index 2e4a62c..601e702 100644 --- a/src/SpecificAiPlayerEasy.java +++ b/src/SpecificAiPlayerEasy.java @@ -1,3 +1,4 @@ public class SpecificAiPlayerEasy extends AiPlayer{ + } diff --git a/src/SpecificAiPlayerHard.java b/src/SpecificAiPlayerHard.java index a8d5dd4..6d6d04c 100644 --- a/src/SpecificAiPlayerHard.java +++ b/src/SpecificAiPlayerHard.java @@ -1,3 +1,88 @@ +import java.util.ArrayList; +import java.util.Random; public class SpecificAiPlayerHard extends AiPlayer{ -} + + private int gridSize; + private boolean[][] shotsFired; + private final ArrayList hitQueue; + private final Random random; + private int nextChessRow; + private int nextChessCol; + + public SpecificAiPlayerHard() { + /*this.gridSize = super.board.getSize(); + this.shotsFired = new boolean[gridSize][gridSize];*/ + this.gridSize = 0; + this.hitQueue = new ArrayList<>(); + this.random = new Random(); + this.nextChessRow = 0; + this.nextChessCol = 0; + } + + // Checks if a position has already been shot at + public boolean alreadyShot(int row, int col) { + return shotsFired[row][col]; + } + + // Generates the next move for the AI + public int[] getNextMove() { + if(gridSize == 0) { + this.gridSize = super.board.getSize(); + this.shotsFired = new boolean[gridSize][gridSize]; + } + // If there are hits to process, prioritize those + while (!hitQueue.isEmpty()) { + int[] target = hitQueue.remove(0); + int row = target[0]; + int col = target[1]; + + if (!alreadyShot(row, col)) { + shotsFired[row][col] = true; + return target; + } + } + + // Otherwise, use chess pattern targeting + int row = nextChessRow; + int col = nextChessCol; + while (alreadyShot(row, col)) { + advanceChessPattern(); + row = nextChessRow; + col = nextChessCol; + } + + shotsFired[row][col] = true; + advanceChessPattern(); + return new int[]{row, col}; + } + + // Advances the chess pattern to the next cell + private void advanceChessPattern() { + nextChessCol += 2; + if (nextChessCol >= gridSize) { + nextChessRow += 1; + nextChessCol = (nextChessRow % 2 == 0) ? 0 : 1; // Alternate starting points for chess pattern + } + if (nextChessRow >= gridSize) { + nextChessRow = 0; + nextChessCol = 0; // Reset if pattern wraps around + } + } + + // Adds adjacent cells to the hit queue + public void processHit(int row, int col) { + if (row > 0 && !alreadyShot(row - 1, col)) { + hitQueue.add(new int[]{row - 1, col}); + } + if (row < gridSize - 1 && !alreadyShot(row + 1, col)) { + hitQueue.add(new int[]{row + 1, col}); + } + if (col > 0 && !alreadyShot(row, col - 1)) { + hitQueue.add(new int[]{row, col - 1}); + } + if (col < gridSize - 1 && !alreadyShot(row, col + 1)) { + hitQueue.add(new int[]{row, col + 1}); + } + } +} \ No newline at end of file diff --git a/src/SpecificAiPlayerMedium.java b/src/SpecificAiPlayerMedium.java index de7c14e..1405d0f 100644 --- a/src/SpecificAiPlayerMedium.java +++ b/src/SpecificAiPlayerMedium.java @@ -10,7 +10,7 @@ public class SpecificAiPlayerMedium extends AiPlayer{ } @Override - public void AiShoot() { + public void aiShoot() { Point nextShot = ComputeNextShot(); // Shoot at the enemy and receive the hit response enemy.receiveShoot(nextShot); @@ -61,8 +61,9 @@ public class SpecificAiPlayerMedium extends AiPlayer{ } private boolean alreadyShot(Point p) { - // TODO Auto-generated method stub - throw new UnsupportedOperationException("Unimplemented method 'alreadyShot'"); + + return this.enemy.board.getHitResponseOnPoint(p) != null; + } private boolean isValidPoint(Point point) { diff --git a/src/startLocalGame.java b/src/startLocalGame.java index c9e5d55..e6bb5ad 100644 --- a/src/startLocalGame.java +++ b/src/startLocalGame.java @@ -216,27 +216,27 @@ public class startLocalGame extends JPanel { } } else if (leftPlayerIcon.getIcon() == aiPlayerEasyIcon) { if (rightPlayerIcon.getIcon() == aiPlayerEasyIcon) { - GameController.startLocalGame(HumanPlayer.class, leftPlayerNickname, SpecificAiPlayerEasy.class, GameController.semesterToBoardSize(semesterCounter)); + GameController.startLocalGame(SpecificAiPlayerEasy.class, leftPlayerNickname, SpecificAiPlayerEasy.class, GameController.semesterToBoardSize(semesterCounter)); } else if (rightPlayerIcon.getIcon() == aiPlayerNormalIcon) { - GameController.startLocalGame(HumanPlayer.class, leftPlayerNickname, SpecificAiPlayerMedium.class, GameController.semesterToBoardSize(semesterCounter)); + GameController.startLocalGame(SpecificAiPlayerEasy.class, leftPlayerNickname, SpecificAiPlayerMedium.class, GameController.semesterToBoardSize(semesterCounter)); } else if (rightPlayerIcon.getIcon() == aiPlayerHardIcon) { - GameController.startLocalGame(HumanPlayer.class, leftPlayerNickname, SpecificAiPlayerHard.class, GameController.semesterToBoardSize(semesterCounter)); + GameController.startLocalGame(SpecificAiPlayerEasy.class, leftPlayerNickname, SpecificAiPlayerHard.class, GameController.semesterToBoardSize(semesterCounter)); } } else if (rightPlayerIcon.getIcon() == aiPlayerNormalIcon) { if (rightPlayerIcon.getIcon() == aiPlayerEasyIcon) { - GameController.startLocalGame(HumanPlayer.class, leftPlayerNickname, SpecificAiPlayerEasy.class, GameController.semesterToBoardSize(semesterCounter)); + GameController.startLocalGame(SpecificAiPlayerMedium.class, leftPlayerNickname, SpecificAiPlayerEasy.class, GameController.semesterToBoardSize(semesterCounter)); } else if (rightPlayerIcon.getIcon() == aiPlayerNormalIcon) { - GameController.startLocalGame(HumanPlayer.class, leftPlayerNickname, SpecificAiPlayerMedium.class, GameController.semesterToBoardSize(semesterCounter)); + GameController.startLocalGame(SpecificAiPlayerMedium.class, leftPlayerNickname, SpecificAiPlayerMedium.class, GameController.semesterToBoardSize(semesterCounter)); } else if (rightPlayerIcon.getIcon() == aiPlayerHardIcon) { - GameController.startLocalGame(HumanPlayer.class, leftPlayerNickname, SpecificAiPlayerHard.class, GameController.semesterToBoardSize(semesterCounter)); + GameController.startLocalGame(SpecificAiPlayerMedium.class, leftPlayerNickname, SpecificAiPlayerHard.class, GameController.semesterToBoardSize(semesterCounter)); } } else if (rightPlayerIcon.getIcon() == aiPlayerHardIcon) { if (rightPlayerIcon.getIcon() == aiPlayerEasyIcon) { - GameController.startLocalGame(HumanPlayer.class, leftPlayerNickname, SpecificAiPlayerEasy.class, GameController.semesterToBoardSize(semesterCounter)); + GameController.startLocalGame(SpecificAiPlayerHard.class, leftPlayerNickname, SpecificAiPlayerEasy.class, GameController.semesterToBoardSize(semesterCounter)); } else if (rightPlayerIcon.getIcon() == aiPlayerNormalIcon) { - GameController.startLocalGame(HumanPlayer.class, leftPlayerNickname, SpecificAiPlayerMedium.class, GameController.semesterToBoardSize(semesterCounter)); + GameController.startLocalGame(SpecificAiPlayerHard.class, leftPlayerNickname, SpecificAiPlayerMedium.class, GameController.semesterToBoardSize(semesterCounter)); } else if (rightPlayerIcon.getIcon() == aiPlayerHardIcon) { - GameController.startLocalGame(HumanPlayer.class, leftPlayerNickname, SpecificAiPlayerHard.class, GameController.semesterToBoardSize(semesterCounter)); + GameController.startLocalGame(SpecificAiPlayerHard.class, leftPlayerNickname, SpecificAiPlayerHard.class, GameController.semesterToBoardSize(semesterCounter)); } }