Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
114 changes: 111 additions & 3 deletions .idea/copilotDiffState.xml

Large diffs are not rendered by default.

223 changes: 223 additions & 0 deletions src/main/java/es/iesquevedo/model/Board.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,223 @@
package es.iesquevedo.model;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Queue;
import java.util.Set;

/**
* Representa el tablero de Inazuma Go (9x9 intersecciones).
* Estado de cada celda: vacía (0), negra (1), blanca (2).
*/
public class Board {
private static final int SIZE = 9;
private int[][] board; // 0 = empty, 1 = black, 2 = white

public Board() {
this.board = new int[SIZE][SIZE];
}

public Board(Board other) {
this.board = new int[SIZE][SIZE];
for (int r = 0; r < SIZE; r++) {
for (int c = 0; c < SIZE; c++) {
this.board[r][c] = other.board[r][c];
}
}
}

/**
* Obtiene el tamaño del tablero.
*/
public int getSize() {
return SIZE;
}

/**
* Obtiene el estado de una celda (0=vacía, 1=negra, 2=blanca).
*/
public int getCell(int row, int col) {
if (!isValid(row, col)) return -1;
return board[row][col];
}

/**
* Coloca una piedra en el tablero.
*/
public void placeStone(int row, int col, int color) {
if (isValid(row, col)) {
board[row][col] = color;
}
}

/**
* Remueve una piedra del tablero.
*/
public void removeStone(int row, int col) {
if (isValid(row, col)) {
board[row][col] = 0;
}
}

/**
* Verifica si una coordenada es válida.
*/
public boolean isValid(int row, int col) {
return row >= 0 && row < SIZE && col >= 0 && col < SIZE;
}

/**
* Verifica si una celda está vacía.
*/
public boolean isEmpty(int row, int col) {
return isValid(row, col) && board[row][col] == 0;
}

/**
* Obtiene los vecinos ortogonales de una celda.
*/
public List<int[]> getNeighbors(int row, int col) {
List<int[]> neighbors = new ArrayList<>();
int[][] directions = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}};
for (int[] dir : directions) {
int nr = row + dir[0];
int nc = col + dir[1];
if (isValid(nr, nc)) {
neighbors.add(new int[]{nr, nc});
}
}
return neighbors;
}

/**
* Calcula las libertades (grados de libertad) de un grupo.
* Retorna el número de intersecciones vacías adyacentes al grupo.
*/
public int countLibertiesForGroup(int row, int col) {
int color = board[row][col];
if (color == 0) return 0;

Set<String> visited = new HashSet<>();
Set<String> liberties = new HashSet<>();
Queue<int[]> queue = new LinkedList<>();
queue.add(new int[]{row, col});
visited.add(row + "," + col);

while (!queue.isEmpty()) {
int[] current = queue.poll();
int r = current[0];
int c = current[1];

for (int[] neighbor : getNeighbors(r, c)) {
int nr = neighbor[0];
int nc = neighbor[1];
String key = nr + "," + nc;

if (isEmpty(nr, nc)) {
liberties.add(key);
} else if (board[nr][nc] == color && !visited.contains(key)) {
visited.add(key);
queue.add(new int[]{nr, nc});
}
}
}

return liberties.size();
}

/**
* Obtiene todas las piedras de un grupo.
*/
public Set<String> getGroup(int row, int col) {
int color = board[row][col];
if (color == 0) return new HashSet<>();

Set<String> group = new HashSet<>();
Queue<int[]> queue = new LinkedList<>();
queue.add(new int[]{row, col});
group.add(row + "," + col);

while (!queue.isEmpty()) {
int[] current = queue.poll();
int r = current[0];
int c = current[1];

for (int[] neighbor : getNeighbors(r, c)) {
int nr = neighbor[0];
int nc = neighbor[1];
String key = nr + "," + nc;

if (board[nr][nc] == color && !group.contains(key)) {
group.add(key);
queue.add(new int[]{nr, nc});
}
}
}

return group;
}

/**
* Detecta y captura grupos sin libertades.
* Retorna el número de piedras capturadas.
*/
public int captureGroupsWithoutLiberties() {
int captured = 0;
for (int r = 0; r < SIZE; r++) {
for (int c = 0; c < SIZE; c++) {
if (board[r][c] != 0 && countLibertiesForGroup(r, c) == 0) {
Set<String> group = getGroup(r, c);
for (String stone : group) {
String[] parts = stone.split(",");
int sr = Integer.parseInt(parts[0]);
int sc = Integer.parseInt(parts[1]);
removeStone(sr, sc);
captured++;
}
}
}
}
return captured;
}

/**
* Crea una copia del tablero.
*/
public Board clone() {
return new Board(this);
}

/**
* Compara dos tableros.
*/
@Override
public boolean equals(Object obj) {
if (!(obj instanceof Board)) return false;
Board other = (Board) obj;
for (int r = 0; r < SIZE; r++) {
for (int c = 0; c < SIZE; c++) {
if (this.board[r][c] != other.board[r][c]) return false;
}
}
return true;
}

/**
* Representación en texto del tablero.
*/
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
for (int r = 0; r < SIZE; r++) {
for (int c = 0; c < SIZE; c++) {
char ch = board[r][c] == 0 ? '.' : (board[r][c] == 1 ? 'X' : 'O');
sb.append(ch).append(" ");
}
sb.append("\n");
}
return sb.toString();
}
}

18 changes: 18 additions & 0 deletions src/main/java/es/iesquevedo/model/Game.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@ public class Game {
private String winnerPlayerId;
private LocalDateTime createdAt;
private LocalDateTime finishedAt;
private Board board;
private List<Move> moves;
private int consecutivePasses;
private Board lastBoardState;

public Game(String name, Player player1) {
this.id = UUID.randomUUID().toString();
Expand All @@ -27,6 +31,10 @@ public Game(String name, Player player1) {
this.winnerPlayerId = null;
this.createdAt = LocalDateTime.now();
this.finishedAt = null;
this.board = new Board();
this.moves = new ArrayList<>();
this.consecutivePasses = 0;
this.lastBoardState = null;
}

public String getId() { return id; }
Expand All @@ -44,6 +52,13 @@ public Player getCurrentPlayer() {
public void setWinnerPlayerId(String playerId) { this.winnerPlayerId = playerId; }
public LocalDateTime getCreatedAt() { return createdAt; }
public LocalDateTime getFinishedAt() { return finishedAt; }
public Board getBoard() { return board; }
public List<Move> getMoves() { return moves; }
public int getConsecutivePasses() { return consecutivePasses; }
public void incrementConsecutivePasses() { this.consecutivePasses++; }
public void resetConsecutivePasses() { this.consecutivePasses = 0; }
public Board getLastBoardState() { return lastBoardState; }
public void setLastBoardState(Board boardState) { this.lastBoardState = boardState; }

public void addPlayer(Player player) {
if (state != GameState.WAITING) {
Expand All @@ -61,6 +76,9 @@ public void start() {
}
this.state = GameState.IN_PROGRESS;
this.currentPlayerIndex = 0;
this.board = new Board(); // Reinicializar tablero limpio
this.moves = new ArrayList<>();
this.consecutivePasses = 0;
}

public void nextTurn() {
Expand Down
77 changes: 77 additions & 0 deletions src/main/java/es/iesquevedo/model/Move.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
package es.iesquevedo.model;

import java.util.UUID;

/**
* Representa un movimiento en una partida de Inazuma Go.
*/
public class Move {
private String id;
private String playerId;
private int row;
private int col;
private boolean isPass; // true si es un pase, false si es colocar piedra
private long timestamp;
private int capturedCount; // número de piedras capturadas en este movimiento

public Move(String playerId, int row, int col) {
this.id = UUID.randomUUID().toString();
this.playerId = playerId;
this.row = row;
this.col = col;
this.isPass = false;
this.timestamp = System.currentTimeMillis();
this.capturedCount = 0;
}

public Move(String playerId, boolean isPass) {
this.id = UUID.randomUUID().toString();
this.playerId = playerId;
this.isPass = isPass;
this.timestamp = System.currentTimeMillis();
this.capturedCount = 0;
this.row = -1;
this.col = -1;
}

public String getId() {
return id;
}

public String getPlayerId() {
return playerId;
}

public int getRow() {
return row;
}

public int getCol() {
return col;
}

public boolean isPass() {
return isPass;
}

public long getTimestamp() {
return timestamp;
}

public int getCapturedCount() {
return capturedCount;
}

public void setCapturedCount(int count) {
this.capturedCount = count;
}

@Override
public String toString() {
if (isPass) {
return "Move{" + "playerId='" + playerId + '\'' + ", PASS" + ", timestamp=" + timestamp + '}';
}
return "Move{" + "playerId='" + playerId + '\'' + ", row=" + row + ", col=" + col + ", timestamp=" + timestamp + '}';
}
}

22 changes: 22 additions & 0 deletions src/main/java/es/iesquevedo/service/MoveValidator.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package es.iesquevedo.service;

import es.iesquevedo.exception.InvalidMoveException;
import es.iesquevedo.exception.PlayerNotInTurnException;
import es.iesquevedo.model.Game;
import es.iesquevedo.model.Move;

/**
* Interfaz para validar movimientos en una partida de Inazuma Go.
*/
public interface MoveValidator {
/**
* Valida un movimiento en el contexto de una partida.
*
* @param game La partida actual
* @param move El movimiento a validar
* @throws InvalidMoveException si el movimiento es inválido
* @throws PlayerNotInTurnException si no es el turno del jugador
*/
void validateMove(Game game, Move move) throws InvalidMoveException, PlayerNotInTurnException;
}

Loading
Loading