Document GomokuBoard class file

This commit is contained in:
Dorian HAMDANI
2025-05-08 19:05:47 +02:00
parent 6996b6548d
commit cf188f5e43

View File

@@ -71,6 +71,8 @@ public class GomokuBoard {
this(width, height, null); this(width, height, null);
} }
// - Private methods ----------------------------------
/** /**
* Generate the cells of the board. * Generate the cells of the board.
* *
@@ -83,41 +85,52 @@ public class GomokuBoard {
* @param colors Array of Color to fill the board. * @param colors Array of Color to fill the board.
*/ */
private void generateCells(int width, int height, Color[][] colors) { private void generateCells(int width, int height, Color[][] colors) {
// Initialize the top-left cell of the board
// If colors is null, set the cell to empty (NIL)
this.topLeftCell = new GomokuCell(colors == null ? Color.NIL : colors[0][0]); this.topLeftCell = new GomokuCell(colors == null ? Color.NIL : colors[0][0]);
GomokuCell act = this.topLeftCell; GomokuCell currentCell = this.topLeftCell;
GomokuCell top = null; GomokuCell previousLineCell = null;
// Run through the height of the board
for (int i = 0; i < height; i++) { for (int i = 0; i < height; i++) {
GomokuCell nextLine = null; GomokuCell nextLineCell = null;
if (i != height - 1) {
nextLine = new GomokuCell(colors == null ? Color.NIL : colors[i + 1][0]);
GomokuCell.link(act, nextLine, Cardinal.S);
}
for (int j = 0; j < width; j++) {
if (top != null) {
GomokuCell.link(act, top.getNeighbour(Cardinal.W), Cardinal.NW);
GomokuCell.link(act, top, Cardinal.N);
top = top.getNeighbour(Cardinal.E);
GomokuCell.link(act, top, Cardinal.NE);
// Create the first cell of the next line, except for the last line
if (i != height - 1) {
nextLineCell = new GomokuCell(colors == null ? Color.NIL : colors[i + 1][0]);
GomokuCell.link(currentCell, nextLineCell, Cardinal.S);
}
// Run through the width of the board
for (int j = 0; j < width; j++) {
// Link the current cell with the 3 cells above it
// (if they exist) to create the diagonal and up links
if (previousLineCell != null) {
GomokuCell.link(currentCell, previousLineCell.getNeighbour(Cardinal.W), Cardinal.NW);
GomokuCell.link(currentCell, previousLineCell, Cardinal.N);
previousLineCell = previousLineCell.getNeighbour(Cardinal.E);
GomokuCell.link(currentCell, previousLineCell, Cardinal.NE);
} }
// Create the cell to the right of the current cell
// and link it to the current cell, then set it as the current cell
if (j != width - 1) { if (j != width - 1) {
GomokuCell right = new GomokuCell(colors == null ? Color.NIL : colors[i][j + 1]); GomokuCell right = new GomokuCell(colors == null ? Color.NIL : colors[i][j + 1]);
GomokuCell.link(act, right, Cardinal.E); GomokuCell.link(currentCell, right, Cardinal.E);
act = right; currentCell = right;
} }
} }
act = nextLine; // Move to the next line, and update the previous line cell
if (act == null) currentCell = nextLineCell;
break; if (currentCell != null) {
top = act.getNeighbour(Cardinal.N); previousLineCell = currentCell.getNeighbour(Cardinal.N);
}
} }
} }
// ------------------Gets-------------------------- // - Getters ------------------------------------------
/** /**
* Returns the width of the board. * Return the width of the board.
* *
* @return The width of the board. * @return The width of the board.
*/ */
@@ -126,7 +139,7 @@ public class GomokuBoard {
} }
/** /**
* Returns the height of the board. * Return the height of the board.
* *
* @return The height of the board. * @return The height of the board.
*/ */
@@ -135,61 +148,78 @@ public class GomokuBoard {
} }
/** /**
* This method get a cell in specific position in the board. * Return the cell at the specified coordinates.
*
* This method returns the cell at the specified coordinates (x, y) on the
* board. If the coordinates are out of bounds of the board size,
* it returns null.
* *
* @param x The position x on the board. * @param x The position x on the board.
* @param y The position y on the board. * @param y The position y on the board.
* @return GomokuCell in the position. * @return The cell at the specified coordinates, or null if out of bounds.
*/ */
public GomokuCell get(int x, int y) { public GomokuCell get(int x, int y) {
if (x < 0 || x >= this.width) if (x < 0 || x >= this.width) return null;
return null; if (y < 0 || y >= this.height) return null;
if (y < 0 || y >= this.height)
return null;
int i = 0, j = 0; int i = 0, j = 0;
GomokuCell act = this.topLeftCell; GomokuCell act = this.topLeftCell;
// Move to the desired cell
// by following the neighbours in the SE direction
// until the desired coordinates are reached
while (i != x || j != y) { while (i != x || j != y) {
Cardinal c = Cardinal.SE; Cardinal c = Cardinal.SE;
if (i < x) if (i < x) i++; // if not in the desired column, move to the right
i++; else c = Cardinal.S; // otherwise, move down
else if (j < y) j++; // if not in the desired row, move down
c = Cardinal.S; else c = Cardinal.E; // otherwise, move to the right
if (j < y) // get the next cell in that direction
j++;
else
c = Cardinal.E;
act = act.getNeighbour(c); act = act.getNeighbour(c);
} }
return act; return act;
} }
/** /**
* This method get a cell in specific position in the board. * Return the cell at the specified coordinates.
* *
* @param xy The position on the board. * This method returns the cell at the specified coordinates (x, y) on the
* @return GomokuCell in the position. * board. If the coordinates are out of bounds of the board size,
* it returns null.
*
* @param xy The coordinates of the cell to get.
* @return The cell at the specified coordinates, or null if out of bounds.
*/ */
public GomokuCell get(Coordinate xy) { public GomokuCell get(Coordinate xy) {
return this.get(xy.x, xy.y); return this.get(xy.x, xy.y);
} }
/** /**
* This method return all cells in the board in the order. * Return all cells of the board.
* *
* @return All cells with a array 2D. * This method returns all cells of the board in a 2D array. Each cell is
* represented by its coordinates (x, y) in the array, and the array is
* organized in rows and columns the same way as the board.
*
* @return A 2D array of all cells on the board.
* @see GomokuCell
* @see GomokuBoard#get(int, int)
*/ */
private GomokuCell[][] getAllCells() { private GomokuCell[][] getAllCells() {
// Create a 2D array to hold all cells
GomokuCell[][] cells = new GomokuCell[this.height][this.width]; GomokuCell[][] cells = new GomokuCell[this.height][this.width];
// Start from the top-left cell and fill the array from left to right
// and top to bottom
GomokuCell act = this.topLeftCell; GomokuCell act = this.topLeftCell;
GomokuCell nextLine = this.topLeftCell.getNeighbour(Cardinal.S); GomokuCell nextLine = this.topLeftCell.getNeighbour(Cardinal.S);
// Iterate through the height and width of the board
for (int i = 0; i < this.height; i++) { for (int i = 0; i < this.height; i++) {
// Fill the current row with cells
for (int j = 0; j < this.width; j++) { for (int j = 0; j < this.width; j++) {
cells[i][j] = act; cells[i][j] = act;
act = act.getNeighbour(Cardinal.E); act = act.getNeighbour(Cardinal.E);
} }
act = nextLine; // Move to the next line (if it exists)
if (act != null) { if (nextLine != null) {
act = nextLine;
nextLine = act.getNeighbour(Cardinal.S); nextLine = act.getNeighbour(Cardinal.S);
} }
} }
@@ -197,60 +227,56 @@ public class GomokuBoard {
} }
/** /**
* This method return a list of playable cell. * Return all playable cells of the board.
* *
* @return List of GomokuCell wich all is playable. * This method returns a list of all playable cells on the board.
* A cell is considered playable if it has not been played on yet
* (i.e., it is empty) and is next to at least one occupied cell.
* The method iterates through all cells on the board and checks their
* playability status. It returns a list of cells that are playable.
*
* @return A list of all playable cells on the board.
*/ */
public List<GomokuCell> getPlayableCells() { public List<GomokuCell> getPlayableCells() {
List<GomokuCell> output = new ArrayList<>(); List<GomokuCell> playableCells = new ArrayList<>();
for (GomokuCell[] line : this.getAllCells()) { GomokuCell[][] cells = this.getAllCells();
for (GomokuCell c : line) { // Iterate through all cells on the board
if (c.isPlayable() && c.getState() == Color.NIL) for (GomokuCell[] line : cells) {
output.add(c); for (GomokuCell cell : line) {
// Check if the cell is playable
if (cell.isPlayable()) {
playableCells.add(cell);
}
} }
} }
return playableCells;
return output;
} }
// ------------------Gets-------------------------- // - Methods ------------------------------------------
/** /**
* Set the width of the board. * Return the number of aligned cells in each direction.
* *
* @param width The new width of the board. * This method takes a cell as input and returns a map of the number of
*/ * aligned cells in each cardinal direction.
public void setWidth(int width) { * The method checks the state of the cell and its neighbours in each
this.width = width; * direction and counts the number of aligned cells.
} * The current cell is included in the count, thus the count starts at 1.
/**
* Set the height of the board.
* *
* @param height The new height of the board. * @param cell The cell to check for aligned cells.
* @return A map of the number of aligned cells in each direction.
*/ */
public void setHeight(int height) { public Map<Cardinal, Integer> countAlignedCells(GomokuCell cell) {
this.height = height;
}
// ------------------Methods-------------------------- Map<Cardinal, Integer> map = new EnumMap<>(Cardinal.class);
/** // Iterate over 4 non-opposite directions
* This method return a Map of number aligned cells. // (N, NE, E, SE) and count the number of aligned cells in that direction
* // as well as in the opposite direction (S, SW, W, NW)
* @param cell A cell.
* @return Map of number aligned cells.
*/
public EnumMap<Cardinal, Integer> countAlignedCells(GomokuCell cell) {
EnumMap<Cardinal, Integer> map = new EnumMap<>(Cardinal.class);
// Iterate over all different axes (4 directions)
for (int i = 0; i < 4; i++) { for (int i = 0; i < 4; i++) {
// Get the direction
Cardinal direction = Cardinal.fromInt(i); Cardinal direction = Cardinal.fromInt(i);
int count = 1; // Start with the current cell int count = 1; // Include the current cell in the count
// Check in the positive direction // Check in the positive direction
GomokuCell nextCell = cell.getNeighbour(direction); GomokuCell nextCell = cell.getNeighbour(direction);
@@ -265,23 +291,24 @@ public class GomokuBoard {
count++; count++;
nextCell = nextCell.getNeighbour(direction.inverse()); nextCell = nextCell.getNeighbour(direction.inverse());
} }
// Store the count in the map
map.put(direction, count); map.put(direction, count);
} }
return map; return map;
} }
/** /**
* This method return the number max of the aligned Cells. * Count the maximum number of aligned cells.
* *
* @param mapColor A map of number aligned cells. * This method takes a map of aligned cells in each direction
* @return int, the number max of the aligned Cells. * and returns the maximum number of aligned cells.
*
* @param cellCountMap The map of aligned cells in each direction.
* @return The maximum number of aligned cells.
*/ */
public int countMax(Map<Cardinal, Integer> mapColor) { public int countMax(Map<Cardinal, Integer> cellCountMap) {
int max = 0; int max = 0;
for (Map.Entry<Cardinal, Integer> entry : mapColor.entrySet()) { for (Map.Entry<Cardinal, Integer> entry : cellCountMap.entrySet()) {
if (entry.getValue() > max) { if (entry.getValue() > max) {
max = entry.getValue(); max = entry.getValue();
} }
@@ -290,8 +317,8 @@ public class GomokuBoard {
} }
/** /**
* Expands the board in the specified direction. * Expand the board in the specified direction.
* This method is used to add a new row, column, or both to the board. * This method is used to add a new row, column, or both, to the board.
* It creates new cells in the specified direction and links them to the * It creates new cells in the specified direction and links them to the
* existing cells. * existing cells.
* It also updates the board dimensions accordingly. * It also updates the board dimensions accordingly.
@@ -306,11 +333,16 @@ public class GomokuBoard {
// if the direction is not even, it is a composed direction // if the direction is not even, it is a composed direction
// call the same function in both components // call the same function in both components
this.expandBoard(direction.rotate(-1)); this.expandBoard(direction.rotate(-1));
this.expandBoard(direction.rotate(1)); this.expandBoard(direction.rotate( 1));
return; return;
} }
// find the suitable corner cell to expand from // find the suitable corner cell to expand from
// e.g. for an expansion to the North, the corner cell is the
// top-left cell of the board
// the corner cell is defined as, when looking from the center of the
// board in the direction of the expansion, the leftmost cell at the
// edge of the board.
Cardinal cornerCellDirection = direction.rotate(-1); Cardinal cornerCellDirection = direction.rotate(-1);
// move to the corner cell // move to the corner cell
@@ -326,7 +358,8 @@ public class GomokuBoard {
cornerCellDirection = direction; cornerCellDirection = direction;
nextCell = cornerCell.getNeighbour(cornerCellDirection); nextCell = cornerCell.getNeighbour(cornerCellDirection);
// if we already reached the end of the board, try the // if we already reached the end of the board, try the
// direction perpendicular to the original direction // direction perpendicular to the original direction, but
// to the left (to get to the leftmost cell)
if (nextCell == null) { if (nextCell == null) {
cornerCellDirection = direction.rotate90CCW(); cornerCellDirection = direction.rotate90CCW();
nextCell = cornerCell.getNeighbour(cornerCellDirection); nextCell = cornerCell.getNeighbour(cornerCellDirection);
@@ -339,10 +372,10 @@ public class GomokuBoard {
// then, add (n - 1) cells in the direction rotated by 90 degrees CW, // then, add (n - 1) cells in the direction rotated by 90 degrees CW,
// where n is either the board width or board height. // where n is either the board width or board height.
// e.g. for an expansion to the North, add (n - 1) cells to the EAST // e.g. for an expansion to the North, add (n - 1) cells to the EAST
// of the anchor cell // of the anchor cell, which will be the nth cell in the row
GomokuCell anchor = new GomokuCell(Color.NIL); GomokuCell anchor = new GomokuCell(Color.NIL);
GomokuCell nextTo = cornerCell;
GomokuCell before = cornerCell.getNeighbour(direction.rotate90CCW()); GomokuCell before = cornerCell.getNeighbour(direction.rotate90CCW());
GomokuCell nextTo = cornerCell;
GomokuCell after = cornerCell.getNeighbour(direction.rotate90CW()); GomokuCell after = cornerCell.getNeighbour(direction.rotate90CW());
Cardinal forwardDirection = direction.rotate90CW(); Cardinal forwardDirection = direction.rotate90CW();
@@ -355,8 +388,9 @@ public class GomokuBoard {
// if the end of the board is not reached (to avoid creating an // if the end of the board is not reached (to avoid creating an
// additional cell) // additional cell)
nextCell = null; nextCell = null;
if (after != null) if (after != null) {
nextCell = new GomokuCell(Color.NIL); nextCell = new GomokuCell(Color.NIL);
}
GomokuCell.link(anchor, nextCell, forwardDirection); GomokuCell.link(anchor, nextCell, forwardDirection);
// set the anchor to the next cell and update the neighbours // set the anchor to the next cell and update the neighbours
anchor = nextCell; anchor = nextCell;
@@ -380,20 +414,27 @@ public class GomokuBoard {
} }
} }
// ------------------Overides-------------------------- // - Override Methods ---------------------------------
/** /**
* This method print the board cell by cell with change line when * Return a string representation of the board.
* the line is finished. *
* This method returns a string representation of the board. The string
* representation is based on the state of each cell on the board.
*
* @return The string representation of the board.
*/ */
@Override @Override
public String toString() { public String toString() {
StringBuilder out = new StringBuilder(); StringBuilder out = new StringBuilder();
GomokuCell[][] cells = this.getAllCells(); GomokuCell[][] cells = this.getAllCells();
// Iterate through all cells on the board
for (GomokuCell[] line : cells) { for (GomokuCell[] line : cells) {
// Append the string representation of each cell to the output
for (GomokuCell c : line) { for (GomokuCell c : line) {
out.append(c.toString()); out.append(c.toString());
} }
// Add a new line after each row
out.append("\n"); out.append("\n");
} }
return out.toString(); return out.toString();