Back to project page android-tic-tac-toe.
The source code is released under:
MIT License
If you think the Android project android-tic-tac-toe listed in this page is inappropriate, such as containing malicious code/tools or violating the copyright, please email info at java2s dot com, thanks.
package org.shaon.android.tictactoe.model; //from w ww . j ava 2 s . c o m import java.util.ArrayList; import java.util.List; /** * State class encapsulates state of the game. It has a 2D array of {@link Player} * enum to save the state. * * @author fahad */ public class State { /** * Number of rows in the board */ public static final int ROWS = 3; /** * Number of columns in the board */ public static final int COLUMNS = 3; /** * Board array */ private Player[][] board; /** * An integer that represents Player.X 's bit vector of assignments */ private int bitVectorX = 0; /** * An integer that represents Player.X 's bit vector of assignments */ private int bitVectorO = 0; /** * Value of the state that is calculated during the Min-Max algorithm */ private int sateValue = Integer.MAX_VALUE; /** * List of successor state with corresponding action. */ private List<ActionState> successorList; /** * Enumerator of player * * @author fahad */ public enum Player { X, O }; /** * Enumerator of Combination that represents way of finishing a game. * * @author fahad */ public enum Combination { TIE, ROW_1, ROW_2, ROW_3, COLUMN_1, COLUMN_2, COLUMN_3, DIAGONAL_1, DIAGONAL_2, }; /** * List of winning combinations. */ private static WinningCombination winningCombinationList[] = { new WinningCombination(0x07, Combination.ROW_1), new WinningCombination(0x038, Combination.ROW_2), new WinningCombination(0x1C0, Combination.ROW_3), new WinningCombination(0x049, Combination.COLUMN_1), new WinningCombination(0x092, Combination.COLUMN_2), new WinningCombination(0x124, Combination.COLUMN_3), new WinningCombination(0x111, Combination.DIAGONAL_1), new WinningCombination(0x54, Combination.DIAGONAL_2), }; /** * Constructor of <code>State</code> */ public State() { board = new Player[ROWS][COLUMNS]; } /** * Assign {@link Player#X} to corresponding row column. * * @param row Row number of assignment * @param column Column number of assignment */ public void assignX(int row, int column) { bitVectorX |= 1 << (COLUMNS * row + column); board[row][column] = Player.X; removeSuccessorListCache(); } /** * Assign {@link Player#O} to corresponding row column. * * @param row Row number of assignment * @param column Column number of assignment */ public void assignO(int row, int column) { bitVectorO |= 1 << (COLUMNS * row + column); board[row][column] = Player.O; removeSuccessorListCache(); } /** * Assign <code>player</code> to corresponding row column. * * @param player Player to assign * @param row Row number of assignment * @param column Column number of assignment * @throws RuntimeException if invalid player. */ public void assign(Player player, int row, int column){ if(player.equals(Player.X)) { assignX(row, column); }else if (player.equals(Player.O)) { assignO(row, column); }else { throw new RuntimeException("Invalid Player!"); } } /** * Get the player in a particular cell. * * @param row Row index of cell * @param column Column index of cell * @return Player assigned to that cell. */ public Player getPlayer(int row, int column) { return board[row][column]; } /** * Get the bit vector of {@link Player#X} * * @return Bit vector of {@link Player#X} */ public int getBitVectorX(){ return bitVectorX; } /** * Get the bit vector of {@link Player#O} * * @return Bit vector of {@link Player#O} */ public int getBitVectorO(){ return bitVectorO; } /** * Left pad a binary string with 0 * * @param s Binary string to left pad * @param n Number of length to pad * @return Left padded string */ private static String padLeft(String s, int n) { return String.format("%1$#" + n + "s", s).replace(' ', '0'); } /** * 9 character long bit vector in binary of {@link Player#X} in string * * @return Bit vector of {@link Player#X} in binary string */ public String getBitVectorXString(){ return padLeft(Integer.toBinaryString(bitVectorX),9); } /** * 9 character long bit vector in binary of {@link Player#O} in string * * @return Bit vector of {@link Player#O} in binary string */ public String getBitVectorOString(){ return padLeft(Integer.toBinaryString(bitVectorO),9); } /** * Checks if the cell at row column is empty or not. * * @param row Row number of cell * @param column Column number of cell * @return True if corresponding cell is empty otherwise false */ public boolean isEmpty(int row, int column){ return board[row][column] == null; } /** * Checks if the game is finished or not. if yes then it returns * proper object to terminating condition otherwise it returns null. * * @return TerminatingCondtion with correct winning combination and player * If game is not finished yet then returns null */ public TerminatingCondition checkFinished(){ //check for win for (WinningCombination wc : winningCombinationList) { int winCase = wc.getWinningCase(); if ((bitVectorX & winCase) == winCase ) { return new TerminatingCondition(Player.X, wc.getCombination()); } if((bitVectorO & winCase) == winCase ){ return new TerminatingCondition(Player.O, wc.getCombination()); } } //check for tie for (int i = 0; i < ROWS; i++) { for (int j = 0; j < COLUMNS; j++) { if(isEmpty(i, j)) { return null; } } } return new TerminatingCondition(null, Combination.TIE); } /** * Copy current state * <b>Note</b> avoiding overriding clone method for cumbersome * exception handling. * * @return another copy of current state */ public State copy(){ State s = new State(); for (int i = 0; i < ROWS; i++) { for (int j = 0; j < COLUMNS; j++) { s.board[i][j] = this.board[i][j]; } } s.bitVectorO = this.bitVectorO; s.bitVectorX = this.bitVectorX; return s; } /** * Generates list of successors * * @param player * @return */ public List<ActionState> successorList(Player player){ if(successorList == null){ successorList = new ArrayList<ActionState>(); for (int i = 0; i < ROWS; i++) { for (int j = 0; j < COLUMNS; j++) { if(isEmpty(i, j)){ State cloneState = copy(); cloneState.assign(player, i, j); successorList.add(new ActionState(cloneState, new Action(player, i, j))); } } } } return successorList; } /** * Get current state value. * * @return Current state value */ public int getSateValue() { return sateValue; } /** * Set state value * * @param sateValue Value to set */ public void setSateValue(int sateValue) { this.sateValue = sateValue; } /** * Remove cached list of successor. */ private void removeSuccessorListCache(){ this.successorList = null; } /** * Convert <code>Player</code> to correct string for {@link #toString()} method. * * @param player Player on test * @return String representation of the player */ private static String convertToIcon(Player player) { if (player == null) { return "."; } return player.toString(); } @Override public String toString() { StringBuilder stringBuilder = new StringBuilder(); for (int i = 0; i < ROWS; i++) { for (int j = 0; j < COLUMNS; j++) { stringBuilder.append(convertToIcon(board[i][j]) + " "); } stringBuilder.append("\n"); } stringBuilder.append("BitVector X: "); stringBuilder.append(getBitVectorXString()); stringBuilder.append("\n"); stringBuilder.append("BitVector O: "); stringBuilder.append(getBitVectorOString()); stringBuilder.append("\n"); return stringBuilder.toString(); } /** * Check if the board is fully empty or not. * * @return True if the board is fully empty otherwise false */ public boolean isFullyEmpty(){ return bitVectorX == 0 && bitVectorO == 0; } }