Android Open Source - android-tic-tac-toe State






From Project

Back to project page android-tic-tac-toe.

License

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.

Java Source Code

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;
  }
}




Java Source Code List

org.shaon.android.tictactoe.TicTacToeApplication.java
org.shaon.android.tictactoe.activity.SettingsActivity.java
org.shaon.android.tictactoe.activity.TicTacToeActivity.java
org.shaon.android.tictactoe.board.Board.java
org.shaon.android.tictactoe.board.Cell.java
org.shaon.android.tictactoe.exception.InvalidTurn.java
org.shaon.android.tictactoe.model.ActionState.java
org.shaon.android.tictactoe.model.Action.java
org.shaon.android.tictactoe.model.AlphaBetaSearch.java
org.shaon.android.tictactoe.model.MinMax.java
org.shaon.android.tictactoe.model.PlayerConfig.java
org.shaon.android.tictactoe.model.SearchAlgorithm.java
org.shaon.android.tictactoe.model.State.java
org.shaon.android.tictactoe.model.TerminatingCondition.java
org.shaon.android.tictactoe.model.WinningCombination.java