Permalink
Browse files

Added calculation of difficulty rating

  • Loading branch information...
mariuszgromada committed Mar 17, 2016
1 parent 612e889 commit c2602b4fe173361eaec4cf3d60b647806043698e
@@ -140,6 +140,34 @@
* @see SudokuSolver
*/
public static final int SUDOKUSOLVER_BOARD_ERROR = -110;
/**
* Obvious puzzle error.
*
* @see SudokuStore
* @see SudokuStore#calculatePuzzleRating(int[][])
*/
public static final int SUDOKUSTORE_CALCULATEPUZZLERATING_PUZZLE_ERROR = -111;
/**
* Puzzle solution does not exist.
*
* @see SudokuStore
* @see SudokuStore#calculatePuzzleRating(int[][])
*/
public static final int SUDOKUSTORE_CALCULATEPUZZLERATING_NO_SOLUTION = -112;
/**
* Puzzle has non-unique solution.
*
* @see SudokuStore
* @see SudokuStore#calculatePuzzleRating(int[][])
*/
public static final int SUDOKUSTORE_CALCULATEPUZZLERATING_NON_UNIQUE_SOLUTION = -113;
/**
* Threads join failed.
*
* @see SudokuStore
* @see SudokuStore#calculatePuzzleRating(int[][])
*/
public static final int SUDOKUSTORE_CALCULATEPUZZLERATING_THREADS_JOIN_FAILED = -114;
/**
* Sudoku board loading failed.
*
@@ -215,6 +243,35 @@
* @see SudokuSolver
*/
public static final String SUDOKUSOLVER_BOARD_ERROR_MSG = "Sudoku board contains an error.";
/**
* Puzzle contains obvious puzzle error.
*
* @see SudokuStore
* @see SudokuStore#calculatePuzzleRating(int[][])
*/
public static final String SUDOKUSTORE_CALCULATEPUZZLERATING_PUZZLE_ERROR_MSG = "Puzzle contains obvious puzzle error.";
/**
* Puzzle solution does not exist.
*
* @see SudokuStore
* @see SudokuStore#calculatePuzzleRating(int[][])
*/
public static final String SUDOKUSTORE_CALCULATEPUZZLERATING_NO_SOLUTION_MSG = "Puzzle solution does not exist.";
/**
* Puzzle has non-unique solution.
*
* @see SudokuStore
* @see SudokuStore#calculatePuzzleRating(int[][])
*/
public static final String SUDOKUSTORE_CALCULATEPUZZLERATING_NON_UNIQUE_SOLUTION_MSG = "Puzzle has non-unique solution.";
/**
* Threads join failed.
*
* @see SudokuStore
* @see SudokuStore#calculatePuzzleRating(int[][])
*/
public static final String SUDOKUSTORE_CALCULATEPUZZLERATING_THREADS_JOIN_FAILED_MSG = "Threads join failed.";
/**
* Error code unknown
@@ -241,6 +298,10 @@ public static final String getErrorDescription(int errorCode) {
case SUDOKUSTORE_RANDOMINDEX_INCORRECT_PARAMETER: return SUDOKUSTORE_RANDOMINDEX_INCORRECT_PARAMETER_MSG;
case SUDOKUSTORE_RANDOMNUMBER_INCORRECT_PARAMETER: return SUDOKUSTORE_RANDOMNUMBER_INCORRECT_PARAMETER_MSG;
case SUDOKUSOLVER_BOARD_ERROR: return SUDOKUSOLVER_BOARD_ERROR_MSG;
case SUDOKUSTORE_CALCULATEPUZZLERATING_PUZZLE_ERROR: return SUDOKUSTORE_CALCULATEPUZZLERATING_PUZZLE_ERROR_MSG;
case SUDOKUSTORE_CALCULATEPUZZLERATING_NO_SOLUTION: return SUDOKUSTORE_CALCULATEPUZZLERATING_NO_SOLUTION_MSG;
case SUDOKUSTORE_CALCULATEPUZZLERATING_NON_UNIQUE_SOLUTION: return SUDOKUSTORE_CALCULATEPUZZLERATING_NON_UNIQUE_SOLUTION_MSG;
case SUDOKUSTORE_CALCULATEPUZZLERATING_THREADS_JOIN_FAILED: return SUDOKUSTORE_CALCULATEPUZZLERATING_THREADS_JOIN_FAILED_MSG;
}
return ERROR_CODE_UNKNOWN_MSG;
}
@@ -2922,6 +2922,7 @@
*/
public static final double getPuzzleExampleRating(int exampleNumber) {
switch(exampleNumber) {
case 0: return 16508.0;
case 1: return 0.4883;
case 2: return 51.2331;
case 3: return 55.591;
@@ -87,7 +87,7 @@
* Solution does not exist.
* @see #checkIfUniqueSolution()
*/
public static final int SOLUTION_NOT_EXISTS = 1;
public static final int SOLUTION_NOT_EXISTS = -1;
/**
* Solution exists and is unique.
* @see #checkIfUniqueSolution()
@@ -1032,7 +1032,7 @@ public int getSolvingState() {
* Gets array representing Sudoku board.
* @return Array representing Sudoku board.
*/
public int[][] getSudokuBoard() {
public int[][] getBoard() {
return sudokuBoard;
}
/**
@@ -114,6 +114,15 @@
* @see SudokuStore#seqOfRandomBoardTransf(int[][], int);
*/
public static final int DEFAULT_RND_TRANSF_SEQ_LENGTH = 1000;
/**
* Threads number.
*/
private static final int THREADS_NUMBER = Runtime.getRuntime().availableProcessors();
/**
* Default number of iterations while calculating
* puzzle rating.
*/
private static final int RATING_DEF_NUM_OF_ITERATIONS = 1000;
/*
* ======================================================
* Loading / getting board methods
@@ -140,6 +149,92 @@
public static final double getPuzzleExampleRating(int exampleNumber) {
return SudokuPuzzles.getPuzzleExampleRating(exampleNumber);
}
/**
* Calculates difficulty of Sudoku puzzle. Returned difficulty level is an average
* of number of closed routes while performing recursive steps in order to find solution.
* This is multi-threading procedure.
*
* @param sudokuPuzzle Sudoku puzzle to be rated.
* @return If puzzle does not contain an error then difficulty rating is returned.
* If puzzle contains obvious error then {@link ErrorCodes#SUDOKUSTORE_CALCULATEPUZZLERATING_PUZZLE_ERROR}.
* If puzzle has no solutions then {@link ErrorCodes#SUDOKUSTORE_CALCULATEPUZZLERATING_NO_SOLUTION}.
* If solution is non-unique then {@link ErrorCodes#SUDOKUSTORE_CALCULATEPUZZLERATING_NON_UNIQUE_SOLUTION}.
*/
public static final int calculatePuzzleRating(int[][] sudokuPuzzle) {
if (checkPuzzle(sudokuPuzzle) == false)
return ErrorCodes.SUDOKUSTORE_CALCULATEPUZZLERATING_PUZZLE_ERROR;
SudokuSolver s = new SudokuSolver(sudokuPuzzle);
int solType = s.checkIfUniqueSolution();
if (solType == SudokuSolver.SOLUTION_NOT_EXISTS)
return ErrorCodes.SUDOKUSTORE_CALCULATEPUZZLERATING_NO_SOLUTION;
if (solType == SudokuSolver.SOLUTION_NON_UNIQUE)
return ErrorCodes.SUDOKUSTORE_CALCULATEPUZZLERATING_NON_UNIQUE_SOLUTION;
/*
* Multi-threading implementation
*/
int threadIterNum = RATING_DEF_NUM_OF_ITERATIONS / THREADS_NUMBER;
int[][] results = new int[THREADS_NUMBER][threadIterNum];
/**
* Runner implementation.
*/
class Runner implements Runnable {
/**
* Thread id.
*/
int threadId;
/**
* Number of iterations.
*/
int iterNum;
/**
* Default constructor.
* @param threadId Thread id.
* @param assigments Test assigned to that thread.
*/
Runner(int threadId, int iterNum) {
this.threadId = threadId;
this.iterNum = iterNum;
}
/**
* Synchronized method to store test results.
* @param t Test id.
* @param result TEst result.
*/
private void setTestResult(int i, int result) {
synchronized(results) {
results[threadId][i] = result;
}
}
@Override
public void run() {
for (int i = 0; i < iterNum; i++) {
SudokuSolver s = new SudokuSolver(sudokuPuzzle);
s.solve();
setTestResult(i, s.getClosedRoutesNumber());
}
}
}
Runner[] runners = new Runner[THREADS_NUMBER];
Thread[] threads = new Thread[THREADS_NUMBER];
for (int t = 0; t < THREADS_NUMBER; t++) {
runners[t] = new Runner(t, threadIterNum);
threads[t] = new Thread(runners[t]);
}
for (int t = 0; t < THREADS_NUMBER; t++)
threads[t].start();
for (int t = 0; t < THREADS_NUMBER; t++)
try {
threads[t].join();
} catch (InterruptedException e) {
e.printStackTrace();
return ErrorCodes.SUDOKUSTORE_CALCULATEPUZZLERATING_THREADS_JOIN_FAILED;
}
int sum = 0;
for (int t = 0; t < THREADS_NUMBER; t++)
for (int i = 0; i < threadIterNum; i++)
sum+=results[t][i];
return sum / (THREADS_NUMBER * threadIterNum);
}
/**
* Loads Sudoku board from text file.
*
@@ -135,7 +135,7 @@ public static void main(String[] args) {
/**
* Workers and threads.
*/
private TestThread[] workers;
private TestRunner[] runners;
private Thread[] threads;
/**
* Table containing test results.
@@ -148,7 +148,7 @@ public static void main(String[] args) {
ApiTests(int threadsNumber) {
THREADS_NUMBER = threadsNumber;
threads = new Thread[THREADS_NUMBER];
workers = new TestThread[THREADS_NUMBER];
runners = new TestRunner[THREADS_NUMBER];
testsResults = new boolean[NUMBER_OF_TESTS];
int[] testsIds = new int[NUMBER_OF_TESTS];
for (int i = 0; i < NUMBER_OF_TESTS; i++)
@@ -180,8 +180,8 @@ public static void main(String[] args) {
assigments[j] = testsIds[t];
t++;
}
workers[i] = new TestThread(i, assigments);
threads[i] = new Thread(workers[i]);
runners[i] = new TestRunner(i, assigments);
threads[i] = new Thread(runners[i]);
}
}
/**
@@ -200,7 +200,7 @@ public void start() {
/**
* Runner implementation.
*/
class TestThread implements Runnable {
class TestRunner implements Runnable {
/**
* Thread id.
*/
@@ -214,7 +214,7 @@ public void start() {
* @param threadId Thread id.
* @param assigments Test assigned to that thread.
*/
TestThread(int threadId, int[] assigments) {
TestRunner(int threadId, int[] assigments) {
this.assigments = assigments;
this.threadId = threadId;
}
@@ -340,7 +340,7 @@ static boolean runTest(int testId, int threadId) {
s.setCell(6,8,0);
s.setCell(7,8,1);
s.setCell(8,8,0);
int[][] b = s.getSudokuBoard();
int[][] b = s.getBoard();
if ( (SudokuStore.boardsAreEqual(a, b) == true) ) {
resultDesc = "Expecting equal - are equal.";
@@ -361,7 +361,7 @@ static boolean runTest(int testId, int threadId) {
int d = s1.getCellDigit(i, j);
s2.setCell(i, j, d);
}
int[][] b = s2.getSudokuBoard();
int[][] b = s2.getBoard();
if ( (SudokuStore.boardsAreEqual(a, b) == true) ) {
resultDesc = "Expecting equal - are equal.";
} else {
@@ -370,6 +370,20 @@ static boolean runTest(int testId, int threadId) {
}
}
break;
case 2:
testDesc = "SudokuSolver.getBoardCopy()";
{
SudokuSolver s = new SudokuSolver(a);
int[][] b = s.getBoard();
int[][] c = s.getBoardCopy();
if ( (SudokuStore.boardsAreEqual(b, c) == true) ) {
resultDesc = "Expecting equal - are equal.";
} else {
resultDesc = "Expecting equal - are not equal.";
testResult = false;
}
}
break;
}
if (testResult == true)
SudokuStore.consolePrintln("(Thread: " + threadId + ") " + "Test: " + testId + " " + testDesc + " " + resultDesc + " >>> ApiTests, result: OK");
@@ -380,5 +394,5 @@ static boolean runTest(int testId, int threadId) {
/**
* Number of regression tests;
*/
static final int NUMBER_OF_TESTS = 2;
static final int NUMBER_OF_TESTS = 3;
}
@@ -138,7 +138,7 @@ public static void main(String[] args) {
/**
* Workers and threads.
*/
private TestThread[] workers;
private TestRunner[] runners;
private Thread[] threads;
/**
* Table containing test results.
@@ -151,7 +151,7 @@ public static void main(String[] args) {
GeneratorTests(int threadsNumber) {
THREADS_NUMBER = threadsNumber;
threads = new Thread[THREADS_NUMBER];
workers = new TestThread[THREADS_NUMBER];
runners = new TestRunner[THREADS_NUMBER];
testsResults = new boolean[NUMBER_OF_TESTS];
int[] testsIds = new int[NUMBER_OF_TESTS];
for (int i = 0; i < NUMBER_OF_TESTS; i++)
@@ -183,8 +183,8 @@ public static void main(String[] args) {
assigments[j] = testsIds[t];
t++;
}
workers[i] = new TestThread(i, assigments);
threads[i] = new Thread(workers[i]);
runners[i] = new TestRunner(i, assigments);
threads[i] = new Thread(runners[i]);
}
}
/**
@@ -203,7 +203,7 @@ public void start() {
/**
* Runner implementation.
*/
class TestThread implements Runnable {
class TestRunner implements Runnable {
/**
* Thread id.
*/
@@ -217,7 +217,7 @@ public void start() {
* @param threadId Thread id.
* @param assigments Test assigned to that thread.
*/
TestThread(int threadId, int[] assigments) {
TestRunner(int threadId, int[] assigments) {
this.assigments = assigments;
this.threadId = threadId;
}
Oops, something went wrong.

0 comments on commit c2602b4

Please sign in to comment.