public class Grid{
  private Square[][] grid = new Square[9][9];

  Grid(int[][] nums) {
    //grids are always 9*9
    for (int i = 0; i < 9; i++) {
      for (int j = 0; j < 9; j++) {
        Square s;
        if (nums[i][j] == 0) {
          s = new Square();
        } else {
          s = new Square(nums[i][j]);
        }
        grid[i][j] = s;
      }

    }
    removeSurplusPMarks();
  }

  void print() {
    for (int i = 0; i < 9; i++) {
      for (int j = 0; j < 9; j++) {
        grid[i][j].print();
      }
      System.out.println();
    }
  }

  private int startIndex(int n) {
    assert (0 <= n) && (n < 9) : "a number in the range 0-8";
    switch (n) {
      case 0:
      case 1:
      case 2:
        return 0;
      case 3:
      case 4:
      case 5:
        return 3;
      default:
        return 6; //for 6,7,8
    }

  }

  boolean hasFreeSpace() {
    for (int i = 0; i < 9; i++) {
      for (int j = 0; j < 9; j++) {
        if (grid[i][j].isEmpty()) {
          return true;
        }
      }
    }
    return false;
  }

  boolean isGoodMove(int row, int col) {
    return grid[row][col].hasUniquePMark();
  }

  void makeMove(int row, int col) {
    assert isGoodMove(row, col) : "not a legal move";
    grid[row][col] = new Square(grid[row][col].uniquePMark());
  }

  //current algorithm very simplistic and only solves very easy games
  //adding more strategies will improve the power of the solver
  private void removeSurplusPMarks() {
    for (int i = 0; i < 9; i++) {
      for (int j = 0; j < 9; j++) {
        removePMarks(i, j);
      }
    }
  }

  void removePMarks(int row, int col) {
    //pre makeMove has been called before this method
    //this method removes the pencil marks that are no longer
    //correct because of the value at grid[row][col]
    int num = grid[row][col].value();
    removeInRow(num, row);
    removeInCol(num, col);
    removeInBlock(num, row, col);
  }

  private void removeInRow(int num, int row) {
    for (int i = 0; i < 9; i++) {
      //has no effect if the given pencil mark isn't in the square
      grid[row][i].removePMarkIfThere(num);
    }
  }

  private void removeInCol(int num, int col) {
    for (int i = 0; i < 9; i++) {
      //has no effect if the given pencil mark isn't in the square
      grid[i][col].removePMarkIfThere(num);
    }
  }

  private void removeInBlock(int num, int row, int col) {
    int startRow = startIndex(row);
    int startCol = startIndex(col);
    for (int i = startRow; i <= startRow + 2; i++) {
      for (int j = startCol; j <= startCol + 2; j++) {
        //has no effect if the given pencil mark isn't in the square
        grid[i][j].removePMarkIfThere(num);
      }
    }
  }
}
