package edu.ics211.h09;

/**
 * Test a Sudoku solver
 * 
 * @author Biagioni, Edoardo and Cam Moore
 * @date October 23, 2013
 * @bugs none
 */
public class SudokuTest {

  /**
   * Checks the sudoku returning true if all cells are filled. Does not check validity.
   * 
   * @return true if all cells are filled, false otherwise.
   */
  private static boolean isFilled(int[][] sudoku) {
    for (int i = 0; i < 9; i++) {
      for (int j = 0; j < 9; j++) {
        if (sudoku[i][j] == 0) {
          return false;
        }
      }
    }
    return true;
  }


  /**
   * Test whether two sudoku are equal. If not, return a new sudoku that is blank where the two sudoku differ.
   * 
   * @param the sudoku to be checked
   * @param the solution checked
   * @return null if the two match, and otherwise a sudoku with 0 in every cell that differs.
   */
  private static int[][] sameSudoku(int[][] sudoku, int[][] solution) {
    int[][] result = new int[9][9];
    for (int i = 0; i < 9; i++) {
      for (int j = 0; j < 9; j++) {
        result[i][j] = sudoku[i][j];
      }
    }
    boolean same = true;
    for (int i = 0; i < 9; i++) {
      for (int j = 0; j < 9; j++) {
        if (result[i][j] != solution[i][j]) {
          same = false;
          result[i][j] = 0;
        }
      }
    }
    if (same) {
      return null;
    }
    return result;
  }


  /**
   * Try to solve a sudoku. If a solution is provided, also check against the solution. Print the results.
   * 
   * @param the name of this sudoku
   * @param the sudoku to be solved
   * @param the given solution, or null
   */
  private static void testSudoku(String name, int[][] sudoku, int[][] solution) {
    System.out.println("solving " + name + "\n" + Sudoku.toString(sudoku, true));
    if (Sudoku.solveSudoku(sudoku)) {
      if (isFilled(sudoku) && Sudoku.checkSudoku(sudoku, true)) {
        System.out.println("success!\n" + Sudoku.toString(sudoku, true));
        if (solution != null) {
          int[][] diff = sameSudoku(sudoku, solution);
          if (diff != null) {
            System.out.println("given solution:\n" + Sudoku.toString(solution, true));
            System.out.println("difference between solutions:\n" + Sudoku.toString(diff, true));
          }
        }
      } else { /* the supposed solution is not a complete or valid sudoku */
        if (!isFilled(sudoku)) {
          System.out.println("sudoku was not completely filled:\n" + Sudoku.toString(sudoku, false));
        }
        if (!Sudoku.checkSudoku(sudoku, false)) {
          System.out.println("sudoku is not a valid solution:\n" + Sudoku.toString(sudoku, false));
        }
      }
    } else {
      System.out.println("unable to complete sudoku " + name + "\n" + Sudoku.toString(sudoku, true));
    }
  }


  public static void main(String[] arg) {
    int[][] example = { { 7, 8, 0, 0, 9, 0, 0, 2, 0 }, { 1, 0, 0, 0, 0, 0, 9, 6, 4 }, { 0, 0, 0, 2, 5, 1, 0, 0, 0 },
        { 0, 0, 6, 1, 8, 5, 0, 0, 0 }, { 5, 0, 4, 0, 0, 0, 3, 0, 2 }, { 0, 0, 0, 3, 4, 2, 5, 0, 0 },
        { 0, 0, 0, 9, 6, 3, 0, 0, 0 }, { 6, 4, 1, 0, 0, 0, 0, 0, 3 }, { 0, 9, 0, 0, 1, 0, 0, 5, 7 } };

    int[][] solution = { { 7, 8, 3, 4, 9, 6, 1, 2, 5 }, { 1, 2, 5, 7, 3, 8, 9, 6, 4 }, { 4, 6, 9, 2, 5, 1, 7, 3, 8 },
        { 2, 3, 6, 1, 8, 5, 4, 7, 9 }, { 5, 1, 4, 6, 7, 9, 3, 8, 2 }, { 9, 7, 8, 3, 4, 2, 5, 1, 6 },
        { 8, 5, 7, 9, 6, 3, 2, 4, 1 }, { 6, 4, 1, 5, 2, 7, 8, 9, 3 }, { 3, 9, 2, 8, 1, 4, 6, 5, 7 } };

    int[][] example2 = { { 0, 6, 0, 9, 0, 8, 0, 1, 0 }, { 0, 0, 4, 0, 0, 0, 0, 0, 0 }, { 8, 0, 3, 0, 0, 0, 4, 5, 0 },
        { 2, 0, 0, 0, 6, 0, 0, 0, 8 }, { 9, 0, 0, 0, 0, 0, 0, 0, 4 }, { 5, 0, 0, 0, 7, 0, 0, 0, 2 },
        { 0, 7, 8, 0, 0, 0, 9, 0, 5 }, { 0, 0, 0, 0, 0, 0, 6, 0, 0 }, { 0, 1, 0, 3, 0, 2, 0, 4, 0 } };

    int[][] solution2 = { { 7, 6, 5, 9, 4, 8, 2, 1, 3 }, { 1, 2, 4, 5, 3, 6, 7, 8, 9 }, { 8, 9, 3, 7, 2, 1, 4, 5, 6 },
        { 2, 4, 7, 1, 6, 3, 5, 9, 8 }, { 9, 3, 6, 2, 8, 5, 1, 7, 4 }, { 5, 8, 1, 4, 7, 9, 3, 6, 2 },
        { 3, 7, 8, 6, 1, 4, 9, 2, 5 }, { 4, 5, 2, 8, 9, 7, 6, 3, 1 }, { 6, 1, 9, 3, 5, 2, 8, 4, 7 } };

    /* a hard sudoku known as AI Escargot */
    int[][] example3 = { { 1, 0, 0, 0, 0, 7, 0, 9, 0 }, { 0, 3, 0, 0, 2, 0, 0, 0, 8 }, { 0, 0, 9, 6, 0, 0, 5, 0, 0 },
        { 0, 0, 5, 3, 0, 0, 9, 0, 0 }, { 0, 1, 0, 0, 8, 0, 0, 0, 2 }, { 6, 0, 0, 0, 0, 4, 0, 0, 0 },
        { 3, 0, 0, 0, 0, 0, 0, 1, 0 }, { 0, 4, 0, 0, 0, 0, 0, 0, 7 }, { 0, 0, 7, 0, 0, 0, 3, 0, 0 } };

    testSudoku("example 1", example, solution);
    testSudoku("example 2", example2, solution2);
    testSudoku("AI Escargot", example3, null);

  }
}
