/// <summary> /// 스도쿠 보드의 빈 셀을 스도쿠 기본 규칙에 따라 해결합니다. /// </summary> /// <param name="sudokuBoard">9*9 가변 배열</param> /// <returns>스도쿠가 해결이 가능한지를 반환합니다.</returns> public bool SolveSudoku(byte[][] sudokuBoard) { if (!SudokuUtils.IsSudokuBoardValid(sudokuBoard)) { throw new ArgumentException(InvalidSudokuBoardMessage); } return(SolveSudokuRec(sudokuBoard)); }
/// <summary> /// 섞으면서 유효한 스도쿠로 부터 다른 스도쿠를 생성합니다. /// </summary> /// <param name="sudokuBoard">9*9 가변 배열</param> public void ShuffleSudoku(byte[][] sudokuBoard) { if (!SudokuUtils.IsSudokuBoardValid(sudokuBoard)) { throw new ArgumentException(InvalidSudokuBoardMessage); } // 최소 20번, 최대 31번 중의 값만큼 스도쿠를 변환 int transformationsToPerform = random.Next(20, 31); // 시스템 Random() 함수로 선택된 값만큼 0부터 1씩 증가하며 For문을 돌린다. for (int transformationsCount = 0; transformationsCount < transformationsToPerform; transformationsCount++) { var transformationType = (SudokuBoardTransformationType)random.Next(0, 6); TransformSudokuBoard(sudokuBoard, transformationType); } }
/// <summary> /// 새로운 셀이 스도쿠 기본 규칙을 따르는지, 유효한지를 검사합니다. /// </summary> /// <param name="sudokuBoard">9x9 가변 배열</param> /// <param name="row">새로운 셀의 행</param> /// <param name="column">새로운 셀의 행</param> /// <param name="value">새로운 셀의 행</param> /// <returns>새로운 셀이 유효한지를 반환합니다.</returns> public bool IsNewCellValid(byte[][] sudokuBoard, byte row, byte column, byte value) { if (!SudokuUtils.IsSudokuBoardValid(sudokuBoard)) { throw new ArgumentException(InvalidSudokuBoardMessage); } if ((row < 0 || row > 8) || (column < 0 || column > 8)) { throw new IndexOutOfRangeException("행과 열의 값은 반드시 0부터 8사이 이여야 합니다!"); } for (int i = 0; i < 9; i++) { // 행 검사 if (sudokuBoard[row][i] == value && i != column) { return(false); } // 열 검사 if (sudokuBoard[i][column] == value && i != row) { return(false); } // 3*3 보드 검사 int groupRow = row / 3 * 3 + i / 3; int groupCol = column / 3 * 3 + i % 3; if (sudokuBoard[groupRow][groupCol] == value && (groupRow != row || groupCol != column)) { return(false); } } // 유효하다면 return(true); }
/// <summary> /// 유효한 스도쿠에서 난이도에 알맞게 셀을 삭제하여 플레이어가 해결할 수 있도록 합니다. /// </summary> /// <param name="sudokuBoard">9*9 가변 배열</param> public void EraseCells(byte[][] sudokuBoard, SudokuDifficultyType sudokuDifficulty) { if (!SudokuUtils.IsSudokuBoardValid(sudokuBoard)) { throw new ArgumentException(InvalidSudokuBoardMessage); } // 지울 셀의 개수를 0으로 초기화 int cellsToErase = 0; // 지울 셀의 개수를 난이도에 따라 지정 if (sudokuDifficulty == SudokuDifficultyType.데모) { cellsToErase = CellsToEraseOnDemo; } if (sudokuDifficulty == SudokuDifficultyType.Easy) { cellsToErase = CellsToEraseOnEasyDifficulty; } else if (sudokuDifficulty == SudokuDifficultyType.Medium) { cellsToErase = CellsToEraseOnMediumDifficulty; } else if (sudokuDifficulty == SudokuDifficultyType.Hard) { cellsToErase = CellsToEraseOnHardDifficulty; } else if (sudokuDifficulty == SudokuDifficultyType.Expert) { cellsToErase = CellsToEraseOnImpossibleDifficulty; } else if (sudokuDifficulty == SudokuDifficultyType.Custom) { cellsToErase = CustomMode; } else { cellsToErase = 20; // 오류 발생시 빈칸 20개 뚫기 (Demo 와 Easy 사이 난이도) } // 셀 지우는 방법: // 1. 행에서 시스템의 Random() 함수로 선택된 셀을 지운다. // 2. 반 대각선 (Minor Diagonal) 에 있는 셀을 지운다. // 3. 반복한다. while (cellsToErase > 0) { // 0 부터 8 까지의 행, 1씩 증가 for (int row = 0; row < 9; row++) { // 최소 0, 최대 9 의 열 중 하나를 선택 (시스탬이 Random() 함수로 선택) int col = random.Next(0, 9); if (sudokuBoard[row][col] != 0) // 선택받은 (?) sudokuBoard[행][열] 이 0이 아니라면 (빈칸이 아니라면) { sudokuBoard[row][col] = 0; // 빈칸으로 전환 cellsToErase--; // 지울 셀의 개수 - 1 } if (cellsToErase <= 0) // 지울 셀의 개수가 0 이하가 되면 { return; // 멈춤 } int oppositeRow = 9 - col - 1; // 반대편 행 선택 int oppositeCol = 9 - row - 1; // 반대편 열 선택 if (sudokuBoard[oppositeRow][oppositeCol] != 0) // sudokuBoard[반대편 행][반대편 열] 이 0이 아니라면 (빈칸이 아니라면) { sudokuBoard[oppositeRow][oppositeCol] = 0; // 빈칸으로 전환 cellsToErase--; // 지울 셀의 개수 - 1 } if (cellsToErase <= 0) // 지울 셀의 개수가 0 이하가 되면 { return; // 멈춤 } } } }