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);
}
// - Private methods ----------------------------------
/**
* Generate the cells of the board.
*
@@ -83,41 +85,52 @@ public class GomokuBoard {
* @param colors Array of Color to fill the board.
*/
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]);
GomokuCell act = this.topLeftCell;
GomokuCell top = null;
GomokuCell currentCell = this.topLeftCell;
GomokuCell previousLineCell = null;
// Run through the height of the board
for (int i = 0; i < height; i++) {
GomokuCell nextLine = 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);
GomokuCell nextLineCell = null;
// 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) {
GomokuCell right = new GomokuCell(colors == null ? Color.NIL : colors[i][j + 1]);
GomokuCell.link(act, right, Cardinal.E);
act = right;
GomokuCell.link(currentCell, right, Cardinal.E);
currentCell = right;
}
}
act = nextLine;
if (act == null)
break;
top = act.getNeighbour(Cardinal.N);
// Move to the next line, and update the previous line cell
currentCell = nextLineCell;
if (currentCell != null) {
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.
*/
@@ -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.
*/
@@ -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 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) {
if (x < 0 || x >= this.width)
return null;
if (y < 0 || y >= this.height)
return null;
if (x < 0 || x >= this.width) return null;
if (y < 0 || y >= this.height) return null;
int i = 0, j = 0;
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) {
Cardinal c = Cardinal.SE;
if (i < x)
i++;
else
c = Cardinal.S;
if (j < y)
j++;
else
c = Cardinal.E;
if (i < x) i++; // if not in the desired column, move to the right
else c = Cardinal.S; // otherwise, move down
if (j < y) j++; // if not in the desired row, move down
else c = Cardinal.E; // otherwise, move to the right
// get the next cell in that direction
act = act.getNeighbour(c);
}
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.
* @return GomokuCell in the position.
* 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 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) {
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() {
// Create a 2D array to hold all cells
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 nextLine = this.topLeftCell.getNeighbour(Cardinal.S);
// Iterate through the height and width of the board
for (int i = 0; i < this.height; i++) {
// Fill the current row with cells
for (int j = 0; j < this.width; j++) {
cells[i][j] = act;
act = act.getNeighbour(Cardinal.E);
}
act = nextLine;
if (act != null) {
// Move to the next line (if it exists)
if (nextLine != null) {
act = nextLine;
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() {
List<GomokuCell> output = new ArrayList<>();
for (GomokuCell[] line : this.getAllCells()) {
for (GomokuCell c : line) {
if (c.isPlayable() && c.getState() == Color.NIL)
output.add(c);
List<GomokuCell> playableCells = new ArrayList<>();
GomokuCell[][] cells = this.getAllCells();
// Iterate through all cells on the board
for (GomokuCell[] line : cells) {
for (GomokuCell cell : line) {
// Check if the cell is playable
if (cell.isPlayable()) {
playableCells.add(cell);
}
}
}
return output;
return playableCells;
}
// ------------------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.
*/
public void setWidth(int width) {
this.width = width;
}
/**
* Set the height of the board.
* This method takes a cell as input and returns a map of the number of
* aligned cells in each cardinal direction.
* The method checks the state of the cell and its neighbours in each
* direction and counts the number of aligned cells.
* The current cell is included in the count, thus the count starts at 1.
*
* @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) {
this.height = height;
}
public Map<Cardinal, Integer> countAlignedCells(GomokuCell cell) {
// ------------------Methods--------------------------
Map<Cardinal, Integer> map = new EnumMap<>(Cardinal.class);
/**
* This method return a Map of number aligned cells.
*
* @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)
// Iterate over 4 non-opposite directions
// (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)
for (int i = 0; i < 4; i++) {
// Get the direction
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
GomokuCell nextCell = cell.getNeighbour(direction);
@@ -265,23 +291,24 @@ public class GomokuBoard {
count++;
nextCell = nextCell.getNeighbour(direction.inverse());
}
// Store the count in the map
map.put(direction, count);
}
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.
* @return int, the number max of the aligned Cells.
* This method takes a map of aligned cells in each direction
* 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;
for (Map.Entry<Cardinal, Integer> entry : mapColor.entrySet()) {
for (Map.Entry<Cardinal, Integer> entry : cellCountMap.entrySet()) {
if (entry.getValue() > max) {
max = entry.getValue();
}
@@ -290,8 +317,8 @@ public class GomokuBoard {
}
/**
* Expands the board in the specified direction.
* This method is used to add a new row, column, or both to the board.
* Expand the board in the specified direction.
* 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
* existing cells.
* 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
// call the same function in both components
this.expandBoard(direction.rotate(-1));
this.expandBoard(direction.rotate(1));
this.expandBoard(direction.rotate( 1));
return;
}
// 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);
// move to the corner cell
@@ -326,7 +358,8 @@ public class GomokuBoard {
cornerCellDirection = direction;
nextCell = cornerCell.getNeighbour(cornerCellDirection);
// 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) {
cornerCellDirection = direction.rotate90CCW();
nextCell = cornerCell.getNeighbour(cornerCellDirection);
@@ -339,10 +372,10 @@ public class GomokuBoard {
// then, add (n - 1) cells in the direction rotated by 90 degrees CW,
// 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
// of the anchor cell
// of the anchor cell, which will be the nth cell in the row
GomokuCell anchor = new GomokuCell(Color.NIL);
GomokuCell nextTo = cornerCell;
GomokuCell before = cornerCell.getNeighbour(direction.rotate90CCW());
GomokuCell nextTo = cornerCell;
GomokuCell after = cornerCell.getNeighbour(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
// additional cell)
nextCell = null;
if (after != null)
if (after != null) {
nextCell = new GomokuCell(Color.NIL);
}
GomokuCell.link(anchor, nextCell, forwardDirection);
// set the anchor to the next cell and update the neighbours
anchor = nextCell;
@@ -380,20 +414,27 @@ public class GomokuBoard {
}
}
// ------------------Overides--------------------------
// - Override Methods ---------------------------------
/**
* This method print the board cell by cell with change line when
* the line is finished.
* Return a string representation of the board.
*
* 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
public String toString() {
StringBuilder out = new StringBuilder();
GomokuCell[][] cells = this.getAllCells();
// Iterate through all cells on the board
for (GomokuCell[] line : cells) {
// Append the string representation of each cell to the output
for (GomokuCell c : line) {
out.append(c.toString());
}
// Add a new line after each row
out.append("\n");
}
return out.toString();