/** * Sub-square identification on the Sudoku board * based on the cell position * @param emptyCell Cell object, including cell position * @return Sub-square left-top and right-bottom indexes. */ internal static SubSquare getSubSqare(BoardCell boardCell) { return getSubSqare(boardCell.rowIndex, boardCell.colIndex); }
/** * Get all current board cells. * @return Array of current board cells. */ public BoardCell[] getAllBoardCells() { BoardCell[] boardCells = new BoardCell[BOARD_CELLS_NUMBER]; int cellIndex = 0; for (int i = 0; i < BOARD_SIZE; i++) for (int j = 0; j < BOARD_SIZE; j++) { boardCells[cellIndex] = new BoardCell(i, j, sudokuBoard[i, j]); cellIndex++; } return boardCells; }
/** * Returns string representation of the 'path' leading to the solution. * @param solutionBoardCells Array representing sequence of board cells. * @return String representation of sequence of board cells. */ public static String solutionPathToString(BoardCell[] solutionBoardCells) { String solutionPath = ""; solutionPath = solutionPath + " --------------- " + NEW_LINE_SEPARATOR; solutionPath = solutionPath + "| id | i, j | d |" + NEW_LINE_SEPARATOR; solutionPath = solutionPath + "|----|----- |---|" + NEW_LINE_SEPARATOR; if (solutionBoardCells != null) for (int i = 0; i < solutionBoardCells.Length; i++) { BoardCell b = solutionBoardCells[i]; if (i + 1 < 10) solutionPath = solutionPath + "| "; else solutionPath = solutionPath + "| "; solutionPath = solutionPath + (i+1) + " | " + (b.rowIndex+1) + ", " + (b.colIndex + 1) + " | " + b.digit + " |" + NEW_LINE_SEPARATOR; } solutionPath = solutionPath + " --------------- " + NEW_LINE_SEPARATOR; return solutionPath; }
/** * Counts number of digits still free * for a specific cell. * * @param boardCell */ private void countDigitsStillFree(BoardCell boardCell) { int[] digitsStillFree = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; int emptyCellsNumber = 0; for (int j = 0; j < BOARD_SIZE; j++) { int boardDigit = sudokuBoard[boardCell.rowIndex, j]; if (boardDigit != CELL_EMPTY) digitsStillFree[boardDigit] = DIGIT_IN_USE; else if (j != boardCell.colIndex) emptyCellsNumber++; } for (int i = 0; i < BOARD_SIZE; i++) { int boardDigit = sudokuBoard[i, boardCell.colIndex]; if (boardDigit != CELL_EMPTY) digitsStillFree[boardDigit] = DIGIT_IN_USE; else if (i != boardCell.rowIndex) emptyCellsNumber++; } SubSquare sub = SubSquare.getSubSqare(boardCell); /* * Mark digits used in a sub-square. */ for (int i = sub.rowMin; i < sub.rowMax; i++) for (int j = sub.colMin; j < sub.colMax; j++) { int boardDigit = sudokuBoard[i, j]; if (boardDigit != CELL_EMPTY) digitsStillFree[boardDigit] = DIGIT_IN_USE; else if ((i != boardCell.rowIndex) && (j != boardCell.colIndex)) emptyCellsNumber++; } /* * Find number of still free digits to use. */ digitsStillFree[boardCell.digit] = 0; boardCell.digitsStillFreeNumber = emptyCellsNumber; for (int digit = 1; digit < 10; digit++) if (digitsStillFree[digit] == DIGIT_STILL_FREE) boardCell.digitsStillFreeNumber++; }
/** * Sudoku puzzle generator. * * @return Sudoku puzzle if process finished correctly, otherwise null. */ public int[,] generate() { if (generatorState != GENERATOR_INIT_FINISHED) { generatorState = GENERATOR_GEN_NOT_STARTED; addMessage("(SudokuGenerator) Generation process not started due to incorrect initialization.", MSG_ERROR); return null; } long solvingStartTime = DateTimeX.currentTimeMillis(); generatorState = GENERATOR_GEN_STARTED; addMessage("(SudokuGenerator) Generation process started.", MSG_INFO); if (randomizeFilledCells == true) addMessage("(SudokuGenerator) >>> Will randomize filled cells within cells with the same impact.", MSG_INFO); boardCells = new BoardCell[BOARD_CELLS_NUMBER]; int cellIndex = 0; for (int i = 0; i < BOARD_SIZE; i++) for (int j = 0; j < BOARD_SIZE; j++) { int d = sudokuBoard[i, j]; if (d != CELL_EMPTY) { boardCells[cellIndex] = new BoardCell(i, j, d); cellIndex++; } } int filledCells = cellIndex; for (int i = 0; i < BOARD_SIZE; i++) for (int j = 0; j < BOARD_SIZE; j++) { int d = sudokuBoard[i, j]; if (d == CELL_EMPTY) { boardCells[cellIndex] = new BoardCell(i, j, d); cellIndex++; } } updateDigitsStillFreeCounts(); sortBoardCells(0, filledCells - 1); do { int r = 0; int i = boardCells[r].rowIndex; int j = boardCells[r].colIndex; int d = sudokuBoard[i, j]; sudokuBoard[i, j] = CELL_EMPTY; SudokuSolver s = new SudokuSolver(sudokuBoard); if (s.checkIfUniqueSolution() != SudokuSolver.SOLUTION_UNIQUE) sudokuBoard[i, j] = d; int lastIndex = filledCells - 1; if (r < lastIndex) { BoardCell b1 = boardCells[r]; BoardCell b2 = boardCells[lastIndex]; boardCells[lastIndex] = b1; boardCells[r] = b2; } filledCells--; updateDigitsStillFreeCounts(); if (filledCells > 0) sortBoardCells(0, filledCells - 1); } while (filledCells > 0); long solvingEndTime = DateTimeX.currentTimeMillis(); computingTime = (solvingEndTime - solvingStartTime) / 1000.0; generatorState = GENERATOR_GEN_FINISHED; addMessage("(SudokuGenerator) Generation process finished, computing time: " + computingTime + " s.", MSG_INFO); return sudokuBoard; }
/** * Counts number of digits still free * for a specific cell. * * @param boardCell */ private void countDigitsStillFree(BoardCell boardCell) { int[] digitsStillFree = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; int emptyCellsNumber = 0; for (int j = 0; j < BOARD_SIZE; j++) { int boardDigit = sudokuBoard[boardCell.rowIndex, j]; if (boardDigit != CELL_EMPTY) { digitsStillFree[boardDigit] = DIGIT_IN_USE; } else if (j != boardCell.colIndex) { emptyCellsNumber++; } } for (int i = 0; i < BOARD_SIZE; i++) { int boardDigit = sudokuBoard[i, boardCell.colIndex]; if (boardDigit != CELL_EMPTY) { digitsStillFree[boardDigit] = DIGIT_IN_USE; } else if (i != boardCell.rowIndex) { emptyCellsNumber++; } } SubSquare sub = SubSquare.getSubSqare(boardCell); /* * Mark digits used in a sub-square. */ for (int i = sub.rowMin; i < sub.rowMax; i++) { for (int j = sub.colMin; j < sub.colMax; j++) { int boardDigit = sudokuBoard[i, j]; if (boardDigit != CELL_EMPTY) { digitsStillFree[boardDigit] = DIGIT_IN_USE; } else if ((i != boardCell.rowIndex) && (j != boardCell.colIndex)) { emptyCellsNumber++; } } } /* * Find number of still free digits to use. */ digitsStillFree[boardCell.digit] = 0; boardCell.digitsStillFreeNumber = emptyCellsNumber; for (int digit = 1; digit < 10; digit++) { if (digitsStillFree[digit] == DIGIT_STILL_FREE) { boardCell.digitsStillFreeNumber++; } } }
/** * Sudoku puzzle generator. * * @return Sudoku puzzle if process finished correctly, otherwise null. */ public int[,] generate() { if (generatorState != GENERATOR_INIT_FINISHED) { generatorState = GENERATOR_GEN_NOT_STARTED; addMessage("(SudokuGenerator) Generation process not started due to incorrect initialization.", MSG_ERROR); return(null); } long solvingStartTime = DateTimeX.currentTimeMillis(); generatorState = GENERATOR_GEN_STARTED; addMessage("(SudokuGenerator) Generation process started.", MSG_INFO); if (randomizeFilledCells == true) { addMessage("(SudokuGenerator) >>> Will randomize filled cells within cells with the same impact.", MSG_INFO); } boardCells = new BoardCell[BOARD_CELLS_NUMBER]; int cellIndex = 0; for (int i = 0; i < BOARD_SIZE; i++) { for (int j = 0; j < BOARD_SIZE; j++) { int d = sudokuBoard[i, j]; if (d != CELL_EMPTY) { boardCells[cellIndex] = new BoardCell(i, j, d); cellIndex++; } } } int filledCells = cellIndex; for (int i = 0; i < BOARD_SIZE; i++) { for (int j = 0; j < BOARD_SIZE; j++) { int d = sudokuBoard[i, j]; if (d == CELL_EMPTY) { boardCells[cellIndex] = new BoardCell(i, j, d); cellIndex++; } } } updateDigitsStillFreeCounts(); sortBoardCells(0, filledCells - 1); do { int r = 0; int i = boardCells[r].rowIndex; int j = boardCells[r].colIndex; int d = sudokuBoard[i, j]; sudokuBoard[i, j] = CELL_EMPTY; SudokuSolver s = new SudokuSolver(sudokuBoard); if (s.checkIfUniqueSolution() != SudokuSolver.SOLUTION_UNIQUE) { sudokuBoard[i, j] = d; } int lastIndex = filledCells - 1; if (r < lastIndex) { BoardCell b1 = boardCells[r]; BoardCell b2 = boardCells[lastIndex]; boardCells[lastIndex] = b1; boardCells[r] = b2; } filledCells--; updateDigitsStillFreeCounts(); if (filledCells > 0) { sortBoardCells(0, filledCells - 1); } } while (filledCells > 0); long solvingEndTime = DateTimeX.currentTimeMillis(); computingTime = (solvingEndTime - solvingStartTime) / 1000.0; generatorState = GENERATOR_GEN_FINISHED; addMessage("(SudokuGenerator) Generation process finished, computing time: " + computingTime + " s.", MSG_INFO); return(sudokuBoard); }