From cf188f5e43a8107120b1856b2b0c778ecc277a27 Mon Sep 17 00:00:00 2001 From: Dorian HAMDANI Date: Thu, 8 May 2025 19:05:47 +0200 Subject: [PATCH] Document GomokuBoard class file --- src/GomokuBoard.java | 241 +++++++++++++++++++++++++------------------ 1 file changed, 141 insertions(+), 100 deletions(-) diff --git a/src/GomokuBoard.java b/src/GomokuBoard.java index d8cbace..c332c26 100644 --- a/src/GomokuBoard.java +++ b/src/GomokuBoard.java @@ -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 getPlayableCells() { - List output = new ArrayList<>(); - for (GomokuCell[] line : this.getAllCells()) { - for (GomokuCell c : line) { - if (c.isPlayable() && c.getState() == Color.NIL) - output.add(c); + List 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 countAlignedCells(GomokuCell cell) { - // ------------------Methods-------------------------- + Map 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 countAlignedCells(GomokuCell cell) { - - EnumMap 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 mapColor) { - + public int countMax(Map cellCountMap) { int max = 0; - for (Map.Entry entry : mapColor.entrySet()) { + for (Map.Entry 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();