package fr.iut_fbleau.HexGame; import fr.iut_fbleau.GameAPI.*; import java.util.*; /** * Plateau du jeu de Hex. * * Joueur 1 relie la gauche et la droite. * Joueur 2 relie le haut et le bas. */ public class HexBoard extends AbstractBoard { private final int size; private Player[][] cells; private Deque historyLocal; private static final int[][] NEIGHBORS = { {-1, 0}, {+1, 0}, { 0, -1}, { 0, +1}, {-1, +1}, {+1, -1} }; public HexBoard(int size) { super(); this.size = size; this.cells = new Player[size][size]; this.historyLocal = new ArrayDeque<>(); this.currentPlayer = Player.PLAYER1; } private boolean inBounds(int r, int c) { return r >= 0 && r < size && c >= 0 && c < size; } private Player getCell(int r, int c) { return cells[r][c]; } private void setCell(int r, int c, Player p) { cells[r][c] = p; } private boolean hasPlayer1Won() { boolean[][] visited = new boolean[size][size]; Deque stack = new ArrayDeque<>(); for (int r = 0; r < size; r++) { if (getCell(r, 0) == Player.PLAYER1) { visited[r][0] = true; stack.push(new int[]{r, 0}); } } while (!stack.isEmpty()) { int[] cur = stack.pop(); int cr = cur[0]; int cc = cur[1]; if (cc == size - 1) return true; for (int[] d : NEIGHBORS) { int nr = cr + d[0], nc = cc + d[1]; if (inBounds(nr, nc) && !visited[nr][nc] && getCell(nr, nc) == Player.PLAYER1) { visited[nr][nc] = true; stack.push(new int[]{nr, nc}); } } } return false; } private boolean hasPlayer2Won() { boolean[][] visited = new boolean[size][size]; Deque stack = new ArrayDeque<>(); for (int c = 0; c < size; c++) { if (getCell(0, c) == Player.PLAYER2) { visited[0][c] = true; stack.push(new int[]{0, c}); } } while (!stack.isEmpty()) { int[] cur = stack.pop(); int cr = cur[0]; int cc = cur[1]; if (cr == size - 1) return true; for (int[] d : NEIGHBORS) { int nr = cr + d[0], nc = cc + d[1]; if (inBounds(nr, nc) && !visited[nr][nc] && getCell(nr, nc) == Player.PLAYER2) { visited[nr][nc] = true; stack.push(new int[]{nr, nc}); } } } return false; } @Override public boolean isLegal(AbstractPly move) { if (!(move instanceof HexPly)) return false; HexPly hp = (HexPly) move; int r = hp.getRow(), c = hp.getCol(); return inBounds(r, c) && getCell(r, c) == null && hp.getPlayer() == this.getCurrentPlayer(); } @Override public void doPly(AbstractPly move) { if (!(move instanceof HexPly)) throw new IllegalArgumentException("Coup invalide: " + move); HexPly hp = (HexPly) move; if (!isLegal(hp)) throw new IllegalStateException("Coup illégal: " + hp); setCell(hp.getRow(), hp.getCol(), hp.getPlayer()); historyLocal.push(hp); setNextPlayer(); } @Override public boolean isGameOver() { return hasPlayer1Won() || hasPlayer2Won(); } @Override public Result getResult() { if (hasPlayer1Won()) return Result.WIN; if (hasPlayer2Won()) return Result.LOSS; return Result.DRAW; } @Override public Iterator getPlies() { Player me = this.getCurrentPlayer(); List moves = new ArrayList<>(); for (int r = 0; r < size; r++) { for (int c = 0; c < size; c++) { if (getCell(r, c) == null) moves.add(new HexPly(me, r, c)); } } return moves.iterator(); } @Override public Iterator getHistory() { return historyLocal.iterator(); } @Override public void undoLastPly() { if (historyLocal.isEmpty()) return; HexPly last = (HexPly) historyLocal.pop(); setCell(last.getRow(), last.getCol(), null); this.currentPlayer = last.getPlayer(); } @Override public IBoard safeCopy() { HexBoard copy = new HexBoard(this.size); copy.currentPlayer = this.currentPlayer; for (int r = 0; r < size; r++) { for (int c = 0; c < size; c++) { copy.cells[r][c] = this.cells[r][c]; } } copy.historyLocal = new ArrayDeque<>(this.historyLocal); return copy; } @Override public String toString() { StringBuilder sb = new StringBuilder(); for (int r = 0; r < size; r++) { for (int k = 0; k < r; k++) sb.append(" "); for (int c = 0; c < size; c++) { Player p = getCell(r, c); char ch = '.'; if (p == Player.PLAYER1) ch = '1'; else if (p == Player.PLAYER2) ch = '2'; sb.append(ch).append(" "); } sb.append("\n"); } sb.append("Current player: ").append(getCurrentPlayer()).append("\n"); return sb.toString(); } public int getSize() { return size; } }