/** 
 * Class containing the internal representation of a HiQ game.
 * Provides public methods for moving pegs and for retrieving 
 * information about board positions.
 */

public class HiQBoard {
 
  /** The HiQ board. */
  private char[][] board;
 
  /** The visual representation of a peg. */
  public static final char PEG = 'X';

  /** The visual representation of an empty cell. */
  public static final char EMPTY = '.';
  
  /** 
   * Create a new HiQBoard with a given map.
   * @param b The map - two dimensional array of char - 
   * representing the new board.
   */
  public HiQBoard(char[][] b) {
    board = b;
  }
  
  /**
   * Move a peg from position (r,c) to (newR, newC), if it is a valid move.
   * @param r The row of the starting position.
   * @param c The column of the starting position.
   * @param newR The row of the new position.
   * @param newC The column of the new position.
   */ 
  public void move(int r, int c, int newR, int newC) {
    if (r - 2 == newR && isValid(r, c, r - 1, newC, newR, newC)) {
      board[r - 1][newC] = EMPTY;
      board[r][c] =  EMPTY;
      board[newR][newC] = PEG; 
    } else if (r + 2 == newR && isValid(r, c, r + 1, newC, newR, newC)) {
      board[r + 1][newC] = EMPTY;
      board[r][c] =  EMPTY;
      board[newR][newC] = PEG; 
    } else if (c - 2 == newC && isValid(r, c, r, c - 1, newR, newC)) {
      board[newR][c - 1] = EMPTY; 
      board[r][c] =  EMPTY;
      board[newR][newC] = PEG; 
    } else if (c + 2 == newC && isValid(r, c, r, c + 1, newR, newC)) {
      board[newR][c + 1] = EMPTY; 
      board[r][c] =  EMPTY;
      board[newR][newC] = PEG; 
    }
  }
  
  /**
   * Return true if there is a peg at position (r,c).
   * @param r A row on the board.
   * @param c A column on the board.
   * @return whether there is a peg at this position
   */ 
  public boolean isPeg(int r, int c) {
   return board[r][c] == PEG; 
  }
  
  /**
   * Return true if the give move is valid, 
   * and false otherwise.
   * @param r row in which the move starts
   * @param c column in which the move starts
   * @param midR row that the move jumps over
   * @param midC column that the move jumps over
   * @param newR row where the move ends
   * @param newC column where the move ends
   * @return whether the move involving the positions specified in its
   * parameters is valid
   */ 
  public boolean isValid(int r, int c, int midR, int midC, int newR, int newC){ 
    // since diagonal moves are not allowed, at least one of the new positions 
    // ( row or column) must be the same as the old one - if both are not,
    // the move can't be valid.
    if (r !=newR  && c != newC) {
      return false;
    }
    // make sure the move does not jump over the edge of the board
    if ((0 > midR || midR > board.length - 1
           || 0 > midC || midC > board[0].length - 1
           || 0 > newR || newR > board.length - 1
           || 0 > newC || newC > board[0].length - 1)) {
      return false;
    } else {
      // will return true if the move is from a peg to an empty square 
      // over a peg.
      return (isPeg(r,c) && isPeg(midR, midC) && !isPeg(newR, newC));
    }
  }
  
  /**
   * Return the number of pegs currently on the board.
   * @return The number of pegs on the board.
   */ 
  public int getNumPegs() {
    int numPegs = 0;
    for(int r = 0; r < board.length; r++) { 
      for(int c = 0; c < board[r].length; c++) {
        if (board[r][c] == PEG) {
          numPegs++;
        }
      }
    }
    return numPegs;
  }
   
  /**
   * Return true if the game is over (i.e., there are no more 
   * valid moves) and return false otherwise.
   * @return whether any moves are left 
   */ 
  public boolean gameOver() {
   
   // check for any remaining valid moves
   for (int r = 0; r < board.length; r++) { 
     for (int c = 0; c < board[r].length; c++) {
       if (isValid(r, c, r + 1, c, r + 2, c) 
             || isValid(r, c, r - 1, c, r - 2, c)
             || isValid(r, c, r, c + 1, r, c + 2)
             || isValid(r, c, r, c - 1, r, c - 2)) {
         return false;
       }  
     }
   }
   return true;
  }
  
  /**
   * Return the number of rows of the board.
   * @return the number of rows in the board
   */ 
  public int numRows() {
    return board.length; 
  }

  /**
   * Return the number of columns of the board.
   * @return the number of columns on the board
   */ 
  public int numCols() {
    return board[0].length; 
  }
  
  /** 
   * Return the mark that is at position (r, c).
   * @param r the row number
   * @param c the column number
   * @return the character value at this position
   */ 
  public char getMark(int r, int c) {
    return board[r][c];
  }
}

