import java.util.*; public class Generator { /* * Generates player's utility using different heuristics * @param boardSize the board size * @param heuristic the user's choice of heuristic */ public Generator(int boardSize, int heuristic) { this.boardSize = boardSize; this.heuristic = heuristic; } /* * Calculates the utility for the given player, choosing among various heuristics * @param pl the current player requesting its utility * @param boardMatrix the current board matrix * @param possM the current possbile moves matrix * @param x the x-coordinate of the move * @param y the y-coordinate of the move * @param turnNum the current turn number * @return the current utility score for the Player pl */ public int getUtility(Player pl, int boardMatrix[][], int possM[][], int x, int y, int turnNum) { int playerUtil = 0; switch (heuristic) { case 1: playerUtil = mobPos(pl, boardMatrix, boardWeight, turnNum); break; case 2: playerUtil = position(pl, boardMatrix, boardWeight); break; case 3: boardWeight = checkNeighbours(pl, boardWeight, 3, boardMatrix); playerUtil = mobPos(pl, boardMatrix, boardWeight, turnNum); break; case 4: boardWeight = checkNeighbours(pl, boardWeight, 3, boardMatrix); playerUtil = position(pl, boardMatrix, boardWeight); break; case 5: boardWeight = enlargeCornerArea(pl, boardMatrix, boardWeight, x, y, 3); playerUtil = mobPos(pl, boardMatrix, boardWeight, turnNum); break; case 6: boardWeight = enlargeCornerArea(pl, boardMatrix, boardWeight, x, y, 3); playerUtil = position(pl, boardMatrix, boardWeight); break; case 7: playerUtil = mostflipped(pl, boardMatrix, possM, 3); break; case 8: playerUtil = lowSurroundings(possM); break; default: break; } return playerUtil; } /* * Calculates the player utility score by its position and mobility, together with the board weights * @param pl the current player * @param matrix the board matrix * @param boardWeight the board weight matrix * @param turnNum the total number of strokes * @return the current utility score for the player */ private int mobPos(Player pl, int matrix[][], int boardWeight[][], int turnNum) { int playerUtil = 0, opponentUtil = 0; int playerMob = 0, opponentMob = 0; int mobweight = 3; // in the middle part of the game if (turnNum < 12) // early in the game mobweight = -2; else if (turnNum > 55) // late in the game mobweight = -15; for (int i = 0; i < boardSize; ++i) { for (int j = 0; j < boardSize; ++j) { if(matrix[i][j] == pl.getColor()) { playerUtil += boardWeight[i][j]; opponentMob += mobweight; } else if (matrix[i][j] == pl.getOtherColor()) { opponentUtil += boardWeight[i][j]; playerMob += mobweight; } } } // player's utility is sum of position score and mobility minus opponent's equivalent playerUtil = (playerUtil + playerMob) - (opponentUtil + opponentMob); return playerUtil; } /* * Calculates the player utility score by its position * @param pl the current player * @param matrix the board matrix * @param boardWeight the board weight matrix * @return the current utility score for the player */ private int position(Player pl, int matrix[][], int boardWeight[][]) { int playerUtil = 0, opponentUtil = 0; for (int i = 0; i < boardSize; ++i) { for (int j = 0; j < boardSize; ++j) { if(matrix[i][j] == pl.getColor()) { playerUtil += boardWeight[i][j]; } else if (matrix[i][j] == pl.getOtherColor()) { opponentUtil += boardWeight[i][j]; } } } playerUtil = playerUtil - opponentUtil; return playerUtil; } /* * Chooses a random move * @param possM the current possible moves matrix * @return a random position to play */ public Position randomMove(int[][] possM) { this.possM = possM; Random generator = new Random(); Position p = new Position(); int randomIndexX = generator.nextInt( boardSize ); int randomIndexY = generator.nextInt( boardSize ); if (possM[randomIndexX][randomIndexY] == POSSIBLE ) { p.x = randomIndexX; p.y = randomIndexY; return p; } else { return randomMove(possM); } } /* * Finds the move with the lowest sum of board weights of surrounding squares * @param possM the possible moves matrix * @return utility score */ public int lowSurroundings(int[][] possM) { this.possM = possM; Position pos = new Position(); Position best = new Position(); best.value = 1000; for (int i = 0; i != boardSize; i++) { for (int j = 0; j != boardSize; j++) { if (possM[i][j] == POSSIBLE) { // top left corner if (i == 0 && j == 0) { pos.value = boardWeight[i+1][j] + boardWeight[i][j+1] + boardWeight[i+1][j+1]; pos.x = i; pos.y = j; // top right corner }else if (i == 0 && j == boardSize - 1) { pos.value = boardWeight[i][j-1] + boardWeight[i+1][j] + boardWeight[i+1][j-1]; pos.x = i; pos.y = j; // lower left corner } else if (i == boardSize - 1 && j == 0) { pos.value = boardWeight[i-1][j] + boardWeight[i][j+1] + boardWeight[i-1][j+1]; pos.x = i; pos.y = j; // lower right corner }else if (i == boardSize - 1 && j == boardSize - 1) { pos.value = boardWeight[i][j-1] + boardWeight[i-1][j] + boardWeight[i-1][j-1]; pos.x = i; pos.y = j; // left edge excluding corners } else if (i == 0) { pos.value = boardWeight[i][j-1] + boardWeight[i+1][j-1] + boardWeight[i+1][j] + boardWeight[i+1][j+1] + boardWeight[i][j+1]; pos.x = i; pos.y = j; // top edge excluding corners } else if (j == 0) { pos.value = boardWeight[i-1][j] + boardWeight[i-1][j+1] + boardWeight[i][j+1] + boardWeight[i+1][j+1] + boardWeight[i+1][j]; pos.x = i; pos.y = j; // right edge excluding corners } else if (i == boardSize - 1) { pos.value = boardWeight[i][j-1] + boardWeight[i-1][j-1] + boardWeight[i-1][j] + boardWeight[i-1][j+1] + boardWeight[i][j+1]; pos.x = i; pos.y = j; // lower edge excluding corners } else if (j == boardSize - 1) { pos.value = boardWeight[i-1][j] + boardWeight[i-1][j-1] + boardWeight[i][j-1] + boardWeight[i+1][j-1] + boardWeight[i+1][j]; pos.x = i; pos.y = j; // square not on an edge or in a corner } else { pos.value = boardWeight[i-1][j-1] + boardWeight[i][j-1] + boardWeight[i+1][j-1] + boardWeight[i+1][j] + boardWeight[i+1][j+1] + boardWeight[i][j+1] + boardWeight[i-1][j+1] + boardWeight[i-1][j]; pos.x = i; pos.y = j; } if (pos.value < best.value) best = pos; } } } return best.value; } /* Increases the score of the boardMatrix in some special cases, i.e. * if there are only two different neighbouring pieces on first/last row/column * @param pl the current player requesting its utility * @param weightMatrix the current board weights * @param boardMatrix holds the current board matrix * @param val a value to alter the board weight matrix in a specific square * @return the updated board weight matrix */ private int[][] checkNeighbours(Player pl, int weightMatrix[][], int val, int boardMatrix[][]) { int n = 0; int p = 0; int m = 0; for (int i = 0; i != boardSize; i++) { for (int j = 0; j != boardSize; j++) { if (i == 0 || i == boardSize - 1) { if (boardMatrix[i][j] == pl.getColor()) { for (m = j + 1; m < boardSize; m++) { if (boardMatrix[i][m] == pl.getOtherColor() && p == 0) { n++; } else if (boardMatrix[i][m] == pl.getColor() && p == 0) { p = 1; } else if (boardMatrix[i][m] == EMPTY && p == 0) { p = 2; } } if (p == 1) { weightMatrix[i][j] += val*n; } for (m = j - 1; m >= 0; m--) { if (boardMatrix[i][m] == pl.getOtherColor() && p == 0) { n++; } else if (boardMatrix[i][m] == pl.getColor() && p == 0) { p = 1; } else if (boardMatrix[i][m] == EMPTY && p == 0) { p = 2; } } if (p == 1) { weightMatrix[i][j] += val*n; } } } if (j == 0 || j == boardSize - 1) { if (boardMatrix[i][j] == pl.getColor()) { for (m = i + 1; m < boardSize; m++) { if (boardMatrix[m][j] == pl.getOtherColor() && p == 0) { n++; } else if (boardMatrix[m][j] == pl.getColor() && p == 0) { p = 1; } else if (boardMatrix[m][j] == EMPTY && p == 0) { p = 2; } } if (p == 1) { weightMatrix[i][j] += val*n; } for (m = i - 1; m >= 0; m--) { if (boardMatrix[m][j] == pl.getOtherColor() && p == 0) { n++; } else if (boardMatrix[m][j] == pl.getColor() && p == 0) { p = 1; } else if (boardMatrix[m][j] == EMPTY && p == 0) { p = 2; } } if (p == 1) { weightMatrix[i][j] += val*n; } } } } } return weightMatrix; } /* If the player occupies a corner it is desirable to enlarge this whole area * @param pl the current player requesting its utility * @param boardMatrix holds the current board matrix * @param boardWeight holds the current board weight matrix * @param i the current x position * @param j the current y position * @param val the value to alter the board weight matrix * @return the updated board weight matrix */ private int[][] enlargeCornerArea(Player pl, int[][] boardMatrix, int[][] boardWeight, int i, int j, int val) { int m = 0, n = 0, p = 0; if (boardMatrix[i][j] == pl.getColor()) { // top left corner if (i == 0 && j == 0) { for (m = 1; m < boardSize; m++) { if (boardMatrix[i][m] == pl.getOtherColor() && p == 0) { n++; } else if (boardMatrix[i][m] == pl.getColor() && p == 0) { p = 1; } else if (boardMatrix[i][m] == EMPTY && p == 0) { p = 2; } } if (p == 1) { for (m = j; m <= j + n; m++) { boardWeight[i][m] = val; } } for (m = 1; m < boardSize; m++) { if (boardMatrix[m][j] == pl.getOtherColor() && p == 0) { n++; } else if (boardMatrix[m][j] == pl.getColor() && p == 0) { p = 1; } else if (boardMatrix[m][j] == EMPTY && p == 0) { p = 2; } } if (p == 1) { for (m = i; m <= i + n; m++) { boardWeight[m][j] = val; } } } // top right corner if (i == 0 && j == boardSize - 1) { for (m = j - 1; m >= 0; m--) { if (boardMatrix[i][m] == pl.getOtherColor() && p == 0) { n++; } else if (boardMatrix[i][m] == pl.getColor() && p == 0) { p = 1; } else if (boardMatrix[i][m] == EMPTY && p == 0) { p = 2; } } if (p == 1) { for (m = j - 1; m >= j - n; m--) { boardWeight[i][m] = val; } } for (m = 1; m < boardSize; m++) { if (boardMatrix[m][j] == pl.getOtherColor() && p == 0) { n++; } else if (boardMatrix[m][j] == pl.getColor() && p == 0) { p = 1; } else if (boardMatrix[m][j] == EMPTY && p == 0) { p = 2; } } if (p == 1) { for (m = i; m <= i + n; m++) { boardWeight[m][j] = val; } } } // bottom left corner if (i == boardSize - 1 && j == 0) { for (m = 1; m < boardSize; m++) { if (boardMatrix[i][m] == pl.getOtherColor() && p == 0) { n++; } else if (boardMatrix[i][m] == pl.getColor() && p == 0) { p = 1; } else if (boardMatrix[i][m] == EMPTY && p == 0) { p = 2; } } if (p == 1) { for (m = j; m <= j + n; m++) { boardWeight[i][m] = val; } } for (m = i - 1; m >= 0; m--) { if (boardMatrix[m][j] == pl.getOtherColor() && p == 0) { n++; } else if (boardMatrix[m][j] == pl.getColor() && p == 0) { p = 1; } else if (boardMatrix[m][j] == EMPTY && p == 0) { p = 2; } } if (p == 1) { for (m = i; m >= i - n; m--) { boardWeight[m][j] = val; } } } // bottom right corner if (i == boardSize - 1 && j == boardSize - 1) { for (m = j - 1; m >= 0; m--) { if (boardMatrix[i][m] == pl.getOtherColor() && p == 0) { n++; } else if (boardMatrix[i][m] == pl.getColor() && p == 0) { p = 1; } else if (boardMatrix[i][m] == EMPTY && p == 0) { p = 2; } } if (p == 1) { for (m = j - 1; m >= j - n; m--) { boardWeight[i][m] = val; } } for (m = i - 1; m >= 0; m--) { if (boardMatrix[m][j] == pl.getOtherColor() && p == 0) { n++; } else if (boardMatrix[m][j] == pl.getColor() && p == 0) { p = 1; } else if (boardMatrix[m][j] == EMPTY && p == 0) { p = 2; } } if (p == 1) { for (m = i; m >= i - n; m--) { boardWeight[m][j] = val; } } } } return boardWeight; } /* Take the move that flips most of the opponent's squares * @param pl the current player * @boardMatrix the current board matrix * @matrix the current possible moves matrix * @val value to multiply the number of possible moves with * @return the calculated utility score */ public int mostflipped(Player pl, int[][] boardMatrix, int[][] matrix, int val) { int playerUtil = 0; // newUtil holds the number of flips for the current move Position pos = new Position(); int m = 0, n = 0, p = 0, q = 0; // which click is the one with the most flips for (int i = 0; i != boardSize; i++) { for (int j = 0; j != boardSize; j++) { if (matrix[i][j] == POSSIBLE) { // checking and maybe changing horizontally from left to right if (i < boardSize - 1) { if (boardMatrix[i+1][j] == pl.getOtherColor()) { n = 0; p = 0; for (m = i+1; m != boardSize; m++) { if (boardMatrix[m][j] == pl.getOtherColor() && p == 0) { n++; playerUtil++; } else if (boardMatrix[m][j] == pl.getColor() && p == 0) { p = 1; } else if (boardMatrix[m][j] == EMPTY && p == 0) { p = 2; } } } } // checking and maybe changing horizontally from right to left if (i > 0) { if (boardMatrix[i-1][j] == pl.getOtherColor() && i > 0) { n = 0; p = 0; for (m = i-1; m >= 0; m--) { if (boardMatrix[m][j] == pl.getOtherColor() && p == 0) { n++; playerUtil++; } else if (boardMatrix[m][j] == pl.getColor() && p == 0) { p = 1; } else if (boardMatrix[m][j] == EMPTY && p == 0) { p = 2; } } } } // checking and maybe changing vertically from top to bottom if (j < boardSize - 1) { if (boardMatrix[i][j+1] == pl.getOtherColor()) { n = 0; p = 0; for (m = j+1; m != boardSize; m++) { if (boardMatrix[i][m] == pl.getOtherColor() && p == 0) { n++; playerUtil++; } else if (boardMatrix[i][m] == pl.getColor() && p == 0) { p = 1; } else if (boardMatrix[i][m] == EMPTY && p == 0) { p = 2; } } } } // checking and maybe changing vertically from bottom to top if (j > 0) { if (boardMatrix[i][j-1] == pl.getOtherColor()) { n = 0; p = 0; for (m = j-1; m >= 0; m--) { if (boardMatrix[i][m] == pl.getOtherColor() && p == 0) { n++; playerUtil++; } else if (boardMatrix[i][m] == pl.getColor() && p == 0) { p = 1; } else if (boardMatrix[i][m] == EMPTY && p == 0) { p = 2; } } } } // checking and maybe changing diagonally from upper left to lower right if (i < boardSize - 1 && j < boardSize - 1) { if (boardMatrix[i+1][j+1] == pl.getOtherColor()) { n = 0; p = 0; if (i >= j) { q = j + 1; for (m = i+1; m != boardSize; m++) { if (boardMatrix[m][q] == pl.getOtherColor() && p == 0) { n++; playerUtil++; } else if (boardMatrix[m][q] == pl.getColor() && p == 0) { p = 1; } else if (boardMatrix[m][q] == EMPTY && p == 0) { p = 2; } q++; } } else { m = i+1; for (q = j+1; q != boardSize; q++) { if (boardMatrix[m][q] == pl.getOtherColor() && p == 0) { n++; playerUtil++; } else if (boardMatrix[m][q] == pl.getColor() && p == 0) { p = 1; } else if (boardMatrix[m][q] == EMPTY && p == 0) { p = 2; } m++; } } } } // checking and maybe changing diagonally from lower right to upper left if (i > 0 && j > 0) { if (boardMatrix[i-1][j-1] == pl.getOtherColor()) { n = 0; p = 0; if (i >= j) { m = i - 1; for (q = j - 1; q >= 0; q--) { if (boardMatrix[m][q] == pl.getOtherColor() && p == 0) { n++; playerUtil++; } else if (boardMatrix[m][q] == pl.getColor() && p == 0) { p = 1; } else if (boardMatrix[m][q] == EMPTY && p == 0) { p = 2; } m--; } } else { q = j - 1; for (m = i - 1; m >= 0; m--) { if (boardMatrix[m][q] == pl.getOtherColor() && p == 0) { n++; playerUtil++; } else if (boardMatrix[m][q] == pl.getColor() && p == 0) { p = 1; } else if (boardMatrix[m][q] == EMPTY && p == 0) { p = 2; } q--; } } } } // checking and maybe changing diagonally from lower left to upper right if (i > 0 && j < boardSize - 1) { if (boardMatrix[i-1][j+1] == pl.getOtherColor()) { n = 0; p = 0; if (i + j >= 7) { m = i - 1; for (q = j + 1; q != boardSize; q++) { if (boardMatrix[m][q] == pl.getOtherColor() && p == 0) { n++; playerUtil++; } else if (boardMatrix[m][q] == pl.getColor() && p == 0) { p = 1; } else if (boardMatrix[m][q] == EMPTY && p == 0) { p = 2; } m--; } } else { q = j + 1; for (m = i - 1; m >= 0; m--) { if (boardMatrix[m][q] == pl.getOtherColor() && p == 0) { n++; playerUtil++; } else if (boardMatrix[m][q] == pl.getColor() && p == 0) { p = 1; } else if (boardMatrix[m][q] == EMPTY && p == 0) { p = 2; } q++; } } } } // checking and maybe changing diagonally from upper right to lower left if (i < boardSize -1 && j > 0) { if (boardMatrix[i+1][j-1] == pl.getOtherColor()) { n = 0; p = 0; if (i + j >= 7) { q = j - 1; for (m = i + 1; m != boardSize; m++) { if (boardMatrix[m][q] == pl.getOtherColor() && p == 0) { n++; playerUtil++; } else if (boardMatrix[m][q] == pl.getColor() && p == 0) { p = 1; } else if (boardMatrix[m][q] == EMPTY && p == 0) { p = 2; } q--; } } else { m = i + 1; for (q = j - 1; q >= 0; q--) { if (boardMatrix[m][q] == pl.getOtherColor() && p == 0) { n++; playerUtil++; } else if (boardMatrix[m][q] == pl.getColor() && p == 0) { p = 1; } else if (boardMatrix[m][q] == EMPTY && p == 0) { p = 2; } m++; } } } } } } } return playerUtil * val; } /* * Plays the perpendicular or the diagonal opening, avoiding the bad parallell one * @param first_x the x coordinate of the opponents first move * @param first_y the y coordinate of the opponents first move * @return position to play */ private Position noParallelOpening(int first_x, int first_y) { Position pos = new Position(); Random generator = new Random(); int rand = generator.nextInt( 1 ); if (first_x == 5 && first_y == 3) { // play 3,2 or 5,2 if (rand == 0) { pos.value = 0; pos.x = 3; pos.y = 2; } else { pos.value = 0; pos.x = 5; pos.y = 2; } } if (first_x == 2 && first_y == 4) { // play 2,5 or 4,5 if (rand == 0) { pos.value = 0; pos.x = 2; pos.y = 5; } else { pos.value = 0; pos.x = 4; pos.y = 5; } } if (first_x == 3 && first_y == 5) { // play 2,3 or 2,5 if (rand == 0) { pos.value = 0; pos.x = 2; pos.y = 3; } else { pos.value = 0; pos.x = 2; pos.y = 5; } } if (first_x == 4 && first_y == 2) { // play 5,2 or 5,4 if (rand == 0) { pos.value = 0; pos.x = 5; pos.y = 2; } else { pos.value = 0; pos.x = 5; pos.y = 4; } } return pos; } private int boardSize; private int heuristic; public int[][] possM; // a static matrix containing weights, representing the estimated // utility of having a square private int boardWeight[][] = { { 100, -10, 11, 6, 6, 11, -10, 100 }, { -10, -20, 1, 2, 2, 1, -20, -10 }, { 10, 1, 5, 4, 4, 5, 1, 10 }, { 6, 2, 4, 2, 2, 4, 2, 6 }, { 6, 2, 4, 2, 2, 4, 2, 6 }, { 10, 1, 5, 4, 4, 5, 1, 10 }, { -10, -20, 1, 2, 2, 1, -20, -10 }, { 100, -10, 11, 6, 6, 11, -10, 100 } }; private static final int BLACK = 0; private static final int WHITE = 1; private static final int EMPTY = 2; private static final int POSSIBLE = 3; }