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() { super(); this.setName("AI Player Hard"); /*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(Point p) { return shotsFired[p.getX()][p.getY()]; } // Generates the next move for the AI public Point 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()) { Point target = hitQueue.remove(0); if (!alreadyShot(target)) { return target; } } // Otherwise, use chess pattern targeting int row = nextChessRow; int col = nextChessCol; while (alreadyShot(new Point(row, col))) { advanceChessPattern(); row = nextChessRow; col = nextChessCol; } shotsFired[row][col] = true; 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 if (hitResponse.getHitResponse() == HitResponseType.HIT) { addAdjacentPoints(hitResponse.getPoint()); } } 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) && !hitQueue.contains(p)) { hitQueue.add(p); } } } private boolean isValidPoint(Point point) { return point.getX() >= 0 && point.getX() < gridSize && point.getY() >= 0 && point.getY() < gridSize; } @Override public void aiShoot() { this.enemy.receiveShoot(getNextMove()); } // 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}); } }*/ }