--- /dev/null
+package de.android.reversi;
+
+import java.util.List;
+
+
+
+public class AI {
+ private Player max;
+ private Player min;
+
+ /**
+ * Disk-square table.
+ */
+ private final int[][] values = new int[][] {
+ { 50, -1, 5, 2, 2, 5, -1, 50 },
+ { -1, -10, 1, 1, 1, 1, -10, -1 },
+ { 5, 1, 1, 1, 1, 1, 1, 5 },
+ { 2, 1, 1, 0, 0, 1, 1, 2 },
+ { 2, 1, 1, 0, 0, 1, 1, 2 },
+ { 5, 1, 1, 1, 1, 1, 1, 5 },
+ { -1, -10, 1, 1, 1, 1, -10, -1 },
+ { 50, -1, 5, 2, 2, 5, -1, 50 } };
+
+
+ private static final int depth = 2;
+
+
+ public AI(final Player currentPlayer) {
+
+ //TODO: This sucks. Re implementation without Enum and with MVC pattern :(
+ if (currentPlayer == Player.PLAYER1) {
+ max = Player.PLAYER1;
+ min = Player.PLAYER2;
+ }
+ else {
+ max = Player.PLAYER2;
+ min = Player.PLAYER1;
+ }
+ }
+
+ /**
+ * Alpha-beta pruning
+ * @param node
+ * @param depth
+ * @param alpha
+ * @param beta
+ * @param player
+ */
+ private int minimaxAB (final Board board, final Position node, final int depth, int alpha, int beta,
+ final boolean max) {
+ Player player;
+ //TODO: This sucks. I must re design this program. :(
+ if (max) {
+ player = this.max;
+ } else {
+ player = this.min;
+ }
+
+ List<Position> allowedPositions;
+ if (depth == 0 || (allowedPositions = board.allowedPositions(player)).isEmpty()) {
+ return 10; //the heuristic value of node
+ }
+ if (max) {
+ for (final Position child : allowedPositions) {
+ //TODO: This clone sucks. I must re design this program. :( I should just need the array :(
+ final Board newBoard = board.clone();
+ newBoard.makeMove(player, child.getColumn(), child.getRow());
+ newBoard.flipOpponentDiscs(child, player);
+ final int val = minimaxAB (newBoard, child, depth -1, alpha, beta, false);
+ if (val > alpha) {
+ alpha = val;
+ }
+ if (beta <= alpha) {
+ break;
+ }
+ }
+
+ return alpha;
+ }
+ else {
+ for (final Position child : allowedPositions) {
+ //TODO: This clone sucks. I must re design this program. :( I should just need the array :(
+ final Board newBoard = board.clone();
+ newBoard.makeMove(player, child.getColumn(), child.getRow());
+ newBoard.flipOpponentDiscs(child, player);
+ final int val = minimaxAB (newBoard, child, depth -1, alpha, beta, false);
+ if (val < beta) {
+ beta = val;
+ }
+ if (beta <= alpha) {
+ break;
+ }
+ }
+
+ return beta;
+ }
+ }
+
+ public Position getBestMove(final Board board) {
+ final List<Position> allowedPositions = board.allowedPositions(this.max);
+ int alpha = -10;
+ Position bestMove = null;
+
+ for (final Position child : allowedPositions) {
+ //TODO: This clone sucks. I must re design this program. :( I should just need the array :(
+ final Board newBoard = board.clone();
+ newBoard.makeMove(this.max, child.getColumn(), child.getRow());
+ newBoard.flipOpponentDiscs(child, this.max);
+ final int val = this.minimaxAB(newBoard, child, depth, -10, 10, true);
+ if (val > alpha) {
+ alpha = val;
+ bestMove = child;
+ }
+ }
+
+ return bestMove;
+ }
+}
import java.util.ArrayList;
import java.util.List;
-public class Board {
+public class Board implements Cloneable {
private final static short [][] directions = { { 0, 1 }, { 1, 1 }, { 1, 0 }, { 1, -1 },
{ 0, -1 }, { -1, -1 }, { -1, 0 }, { -1, -1 } };
public static final short TOP_MARGIN = 0;
public static final short LEFT_MARGIN = 0;
- private final Square gameBoard[][] = new Square[NUMBER_OF_ROWS][NUMBER_OF_COLUMNS];
+ //TODO: I am using clone but it could be interesting to use a copy factory.
+ private Square gameBoard[][] = new Square[NUMBER_OF_ROWS][NUMBER_OF_COLUMNS];
//Just one dimension because it is a square.
private int squareWidth;
}
- public void flipOpponentDiscs(final Position movement, final Player currentPlayer) {
- final List<Position> flippedDiscs = flippedDiscs(currentPlayer, movement.getRow(),
- movement.getColumn());
+ public void flipOpponentDiscs(final Position position, final Player currentPlayer) {
+ final List<Position> flippedDiscs = flippedDiscs(currentPlayer, position.getRow(),
+ position.getColumn());
for (final Position flippedDisc : flippedDiscs) {
this.makeMove(currentPlayer, flippedDisc.getColumn(), flippedDisc.getRow());
}
squareWidth = (width - Board.LEFT_MARGIN * 2) / Board.NUMBER_OF_COLUMNS;
}
- public final boolean empty(final short column, final short row) {
+
+ public final List<Position> allowedPositions(final Player player) {
+ final List<Position> list = new ArrayList<Position>();
+
+ for (short column = 0; column < Board.NUMBER_OF_COLUMNS; column++) {
+ for (short row = 0; row < Board.NUMBER_OF_ROWS; row++) {
+ if (empty(column, row)) {
+ if (isValidMove(player, row, column)) {
+ list.add(new Position(row, column));
+ }
+ }
+ }
+ }
+
+ return list;
+ }
+
+ private final boolean empty(final short column, final short row) {
if (gameBoard[column][row].getPlayer() == Player.NOPLAYER) {
return true;
}
return false;
}
- public final boolean isValidMove (final Player player, final short row, final short column) {
+ private final boolean isValidMove (final Player player, final short row, final short column) {
for (int i = 0; i < directions.length; i++) {
if (isValidMove (directions[i][0], directions[i][1], player,
(short)(row + directions[i][1]), (short)(column + directions[i][0])) > 0) {
return false;
}
- public final List<Position> flippedDiscs (final Player player, final short row, final short column) {
+ private final List<Position> flippedDiscs (final Player player, final short row, final short column) {
final List<Position> flippedDiscs = new ArrayList<Position>();
List<Position> aux;
return flippedDiscs;
}
- public final List<Position> allowedPositions(final Player player) {
- final List<Position> list = new ArrayList<Position>();
-
- for (short column = 0; column < Board.NUMBER_OF_COLUMNS; column++) {
- for (short row = 0; row < Board.NUMBER_OF_ROWS; row++) {
- if (empty(column, row)) {
- if (isValidMove(player, row, column)) {
- list.add(new Position(row, column));
- }
- }
- }
- }
-
- return list;
- }
-
private final int isValidMove (final short moveX, final short moveY, final Player player,
short row, short column) {
int flippedDiscs = 0;
public Square[][] getGameBoard() {
return gameBoard;
}
+
+ @Override
+ public Board clone() {
+ try {
+ final Board result = (Board) super.clone();
+ //If this was not a matrix (a simple array) I could use gameBoard.clone();
+ result.gameBoard = new Square[NUMBER_OF_ROWS][NUMBER_OF_COLUMNS];
+ for (short column = 0; column < NUMBER_OF_COLUMNS; column++) {
+ for (short row = 0; row < NUMBER_OF_ROWS; row++) {
+ result.gameBoard[column][row] = gameBoard[column][row].clone();
+ }
+ }
+ return result;
+ } catch (final CloneNotSupportedException e) {
+ throw new AssertionError(e);
+ }
+ }
}
import android.graphics.Color;
+//TODO: better a linked list
public enum Player {
NOPLAYER {
@Override
//AllowedPositions for player.
listAllowedPositions = board.allowedPositions(currentPlayer);
+ final AI prueba = new AI(this.currentPlayer);
+
+ prueba.getBestMove(board);
+
//UpdateBoard with suggestions
for (final Position suggestedPosition : listAllowedPositions) {
board.makeMove(currentPlayer, suggestedPosition.getColumn(), suggestedPosition.getRow(), true);
this.isEnableUserTouch = true;
+
+
//Going to wait for touch event from human player.
}
else {
package de.android.reversi;
-public class Square {
+public class Square implements Cloneable {
private Player player;
private boolean suggestion;
private int squareMediumX;
return suggestion;
}
- public void setSuggestion(boolean suggestion) {
+ public void setSuggestion(final boolean suggestion) {
this.suggestion = suggestion;
}
return squareMediumX;
}
- public void setSquareMediumX(int squareMediumX) {
+ public void setSquareMediumX(final int squareMediumX) {
this.squareMediumX = squareMediumX;
}
return squareMediumY;
}
- public void setSquareMediumY(int squareMediumY) {
+ public void setSquareMediumY(final int squareMediumY) {
this.squareMediumY = squareMediumY;
}
- public void setPlayer (Player player) {
+ public void setPlayer (final Player player) {
this.player = player;
}
return player;
}
- public void setRadius (int radius) {
+ public void setRadius (final int radius) {
this.radius = radius;
}
public int getRadius() {
return radius;
}
+ @Override
+ public Square clone() {
+ try {
+ final Square result = (Square) super.clone();
+ return result;
+ } catch (final CloneNotSupportedException e) {
+ throw new AssertionError(e);
+ }
+ }
}
return null;
}
+ //TODO: With a linked list this is not needed
public static Player opponent(final Player currentPlayer) {
switch (currentPlayer){
case PLAYER1: