init commit

This commit is contained in:
Ulf Gebhardt 2016-02-27 10:22:48 +01:00
commit 08008df617
16 changed files with 2306 additions and 0 deletions

8
.classpath Normal file
View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="src" path="src"/>
<classpathentry kind="con" path="org.eclipse.jdt.junit.JUNIT_CONTAINER/4"/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
<classpathentry kind="con" path="org.eclipse.jdt.USER_LIBRARY/acm"/>
<classpathentry kind="output" path="bin"/>
</classpath>

17
.project Normal file
View File

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>Sudoku</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.jdt.core.javanature</nature>
</natures>
</projectDescription>

View File

@ -0,0 +1,12 @@
#Tue Jan 19 13:27:34 CET 2010
eclipse.preferences.version=1
org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6
org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
org.eclipse.jdt.core.compiler.compliance=1.6
org.eclipse.jdt.core.compiler.debug.lineNumber=generate
org.eclipse.jdt.core.compiler.debug.localVariable=generate
org.eclipse.jdt.core.compiler.debug.sourceFile=generate
org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
org.eclipse.jdt.core.compiler.source=1.6

73
build.xml Normal file
View File

@ -0,0 +1,73 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- You may freely edit this file. See commented blocks below for -->
<!-- some examples of how to customize the build. -->
<!-- (If you delete it and reopen the project it will be recreated.) -->
<!-- By default, only the Clean and Build commands use this build script. -->
<!-- Commands such as Run, Debug, and Test only use this build script if -->
<!-- the Compile on Save feature is turned off for the project. -->
<!-- You can turn off the Compile on Save (or Deploy on Save) setting -->
<!-- in the project's Project Properties dialog box.-->
<project name="Sudoku" default="default" basedir=".">
<description>Builds, tests, and runs the project Sudoku.</description>
<import file="nbproject/build-impl.xml"/>
<!--
There exist several targets which are by default empty and which can be
used for execution of your tasks. These targets are usually executed
before and after some main targets. They are:
-pre-init: called before initialization of project properties
-post-init: called after initialization of project properties
-pre-compile: called before javac compilation
-post-compile: called after javac compilation
-pre-compile-single: called before javac compilation of single file
-post-compile-single: called after javac compilation of single file
-pre-compile-test: called before javac compilation of JUnit tests
-post-compile-test: called after javac compilation of JUnit tests
-pre-compile-test-single: called before javac compilation of single JUnit test
-post-compile-test-single: called after javac compilation of single JUunit test
-pre-jar: called before JAR building
-post-jar: called after JAR building
-post-clean: called after cleaning build products
(Targets beginning with '-' are not intended to be called on their own.)
Example of inserting an obfuscator after compilation could look like this:
<target name="-post-compile">
<obfuscate>
<fileset dir="${build.classes.dir}"/>
</obfuscate>
</target>
For list of available properties check the imported
nbproject/build-impl.xml file.
Another way to customize the build is by overriding existing main targets.
The targets of interest are:
-init-macrodef-javac: defines macro for javac compilation
-init-macrodef-junit: defines macro for junit execution
-init-macrodef-debug: defines macro for class debugging
-init-macrodef-java: defines macro for class execution
-do-jar: JAR building
run: execution of project
-javadoc-build: Javadoc generation
test-report: JUnit report generation
An example of overriding the target for project execution could look like this:
<target name="run" depends="Sudoku-impl.jar">
<exec dir="bin" executable="launcher.exe">
<arg file="${dist.jar}"/>
</exec>
</target>
Notice that the overridden target depends on the jar target and not only on
the compile target as the regular run target does. Again, for a list of available
properties which you can use, check the target you are overriding in the
nbproject/build-impl.xml file.
-->
</project>

Binary file not shown.

BIN
build/classes/Sudoku.class Normal file

Binary file not shown.

Binary file not shown.

BIN
libs/acm.jar Normal file

Binary file not shown.

3
manifest.mf Normal file
View File

@ -0,0 +1,3 @@
Manifest-Version: 1.0
X-COMMENT: Main-Class will be added automatically by build

1401
nbproject/build-impl.xml Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,8 @@
build.xml.data.CRC32=43255cb9
build.xml.script.CRC32=501d6b1d
build.xml.stylesheet.CRC32=8064a381@1.78.1.48
# This file is used by a NetBeans-based IDE to track changes in generated files such as build-impl.xml.
# Do not edit this file. You may delete it but then the IDE will never regenerate such files for you.
nbproject/build-impl.xml.data.CRC32=43255cb9
nbproject/build-impl.xml.script.CRC32=0975d34f
nbproject/build-impl.xml.stylesheet.CRC32=2d327b5d@1.78.1.48

1
nbproject/private/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
/private.properties

View File

@ -0,0 +1,77 @@
annotation.processing.enabled=true
annotation.processing.enabled.in.editor=false
annotation.processing.processor.options=
annotation.processing.processors.list=
annotation.processing.run.all.processors=true
annotation.processing.source.output=${build.generated.sources.dir}/ap-source-output
build.classes.dir=${build.dir}/classes
build.classes.excludes=**/*.java,**/*.form
# This directory is removed when the project is cleaned:
build.dir=build
build.generated.dir=${build.dir}/generated
build.generated.sources.dir=${build.dir}/generated-sources
# Only compile against the classpath explicitly listed here:
build.sysclasspath=ignore
build.test.classes.dir=${build.dir}/test/classes
build.test.results.dir=${build.dir}/test/results
# Uncomment to specify the preferred debugger connection transport:
#debug.transport=dt_socket
debug.classpath=\
${run.classpath}
debug.test.classpath=\
${run.test.classpath}
# Files in build.classes.dir which should be excluded from distribution jar
dist.archive.excludes=
# This directory is removed when the project is cleaned:
dist.dir=dist
dist.jar=${dist.dir}/Sudoku.jar
dist.javadoc.dir=${dist.dir}/javadoc
excludes=
file.reference.acm.jar=libs\\acm.jar
file.reference.Sudoku-src=src
includes=**
jar.compress=false
javac.classpath=\
${file.reference.acm.jar}:\
${libs.junit_4.classpath}
# Space-separated list of extra javac options
javac.compilerargs=
javac.deprecation=false
javac.external.vm=true
javac.processorpath=\
${javac.classpath}
javac.source=1.8
javac.target=1.8
javac.test.classpath=\
${javac.classpath}:\
${build.classes.dir}
javac.test.processorpath=\
${javac.test.classpath}
javadoc.additionalparam=
javadoc.author=false
javadoc.encoding=${source.encoding}
javadoc.noindex=false
javadoc.nonavbar=false
javadoc.notree=false
javadoc.private=false
javadoc.splitindex=true
javadoc.use=true
javadoc.version=false
javadoc.windowtitle=
main.class=Sudoku
manifest.file=manifest.mf
meta.inf.dir=${src.dir}/META-INF
mkdist.disabled=false
platform.active=default_platform
run.classpath=\
${javac.classpath}:\
${build.classes.dir}
# Space-separated list of JVM arguments used when running the project.
# You may also define separate properties like run-sys-prop.name=value instead of -Dname=value.
# To set system properties for unit tests define test-sys-prop.name=value:
run.jvmargs=
run.test.classpath=\
${javac.test.classpath}:\
${build.test.classes.dir}
source.encoding=UTF-8
src.dir=${file.reference.Sudoku-src}

13
nbproject/project.xml Normal file
View File

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://www.netbeans.org/ns/project/1">
<type>org.netbeans.modules.java.j2seproject</type>
<configuration>
<data xmlns="http://www.netbeans.org/ns/j2se-project/3">
<name>Sudoku</name>
<source-roots>
<root id="src.dir"/>
</source-roots>
<test-roots/>
</data>
</configuration>
</project>

465
src/Sudoku.java Normal file
View File

@ -0,0 +1,465 @@
import java.awt.Color;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.Arrays;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import acm.gui.IntField;
import acm.gui.TableLayout;
import acm.gui.TablePanel;
import acm.program.Program;
public class Sudoku extends Program {
/**
* Fixed boardsize - alter this if you want to make smaller/bigger boards
* Not tested! (is this possible?^^)
*/
public static int boardsize = 9;
/**
* Simple avoiding some warnings
*/
private static final long serialVersionUID = 1L;
// the model of the game board
IntField[][] board;
/**
* Construct a new game of Sudoku.
*
* Initializes the game board with all zeroes.
*/
public Sudoku() {
super();
board = new IntField[9][9];
for (int i = 0; i < 9; i++) {
for (int j = 0; j < 9; j++) {
board[i][j] = new IntField(0);
}
}
}
/**
* Initialize a new game of Sudoku with a given configuration.
*
* @param values
* The configuration of the game board.
*/
public Sudoku(int[][] values) {
this();
setConfiguration(values);
}
/**
* Initialize the view component.
*/
@Override
public void init() {
setTitle("Sudoku");
setLayout(new TableLayout(4, 3));
for (int i = 0; i < 9; i++) {
add(assembleInnerTable(i));
}
add(new JButton("Solve"));
addActionListeners();
}
/**
* Assemble a single 3x3 field.
*
* @param n
* The number of the 3x3 field to assemble a table component for.
* @return The TablePanel containing a 3x3 field.
*/
private TablePanel assembleInnerTable(int n) {
TablePanel tp = new TablePanel(3, 3);
for (int i = 0; i < 9; i++) {
// we assemble 3x3 field-wise and have to adjust array indices
// accordingly
int row = 3 * (n / 3) + i / 3;
int col = 3 * (n % 3) + i % 3;
// The constructor made sure these are instantiated IntFields
IntField intField = board[row][col];
// Register a KeyListener to suppress non-digit entries
intField.addKeyListener(new KeyListener() {
@Override
public void keyPressed(KeyEvent e) {
// don't care
}
@Override
public void keyReleased(KeyEvent e) {
// don't care
}
@Override
public void keyTyped(KeyEvent e) {
try {
// try to parse the pressed keys value into an Integer
Integer.parseInt(String.valueOf(e.getKeyChar()));
} catch (NumberFormatException nfe) {
// consume the event and stop it from propagating
e.consume();
}
}
});
tp.add(intField);
}
// draw a solid black border around every 3x3 field
tp.setBorder(BorderFactory.createLineBorder(Color.black));
return tp;
}
/**
* Initialize the game board with the given arrays of ints.
*
* @param init The 9x9 two-dimensional array with int values from 0..9
*/
public void setConfiguration(int[][] init) {
for (int i = 0; i < 9; i++) {
for (int j = 0; j < 9; j++) {
if (init[i][j] > 0 && init[i][j] <= 9) {
board[i][j].setValue(init[i][j]);
} else {
board[i][j].setValue(0);
}
}
}
}
/**
* Return the current configuration of the game board.
*
* @return The current configuration.
*/
public int[][] getConfiguration() {
int[][] tmp = new int[9][9];
for (int i = 0; i < 9; i++) {
for (int j = 0; j < 9; j++) {
tmp[i][j] = board[i][j].getValue();
}
}
return tmp;
}
// if no solution was found, color every field red
public void colorForFailure() {
for (int i = 0; i < 9; i++) {
for (int j = 0; j < 9; j++) {
board[i][j].setBackground(new Color(255, 0, 0));
}
}
}
// if there was a solution, color the new values fields green
public void colorForSuccess(int[][] solution) {
int[][] actual = getConfiguration();
for (int i = 0; i < 9; i++) {
for (int j = 0; j < 9; j++) {
if (solution[i][j] != actual[i][j]) {
board[i][j].setBackground(new Color(0, 255, 0));
board[i][j].setValue(solution[i][j]);
} else {
board[i][j].setBackground(new Color(255, 255, 255));
}
}
}
}
/**
* The ActionListeners method to process pressed buttons.
*/
@Override
public void actionPerformed(ActionEvent e) {
if (e.getActionCommand().equals("Solve")) {
// The solve button was pressed, find a solution
int[][] solution = solve(getConfiguration());
if (solution != null) {
colorForSuccess(solution);
} else {
colorForFailure();
}
}
}
/**
* Checks if board is valid. Returns false if it is valid, else true.
*
* public because requested
*
* @param board Sudoku Configuration
* @return false if valid, true if not.
*/
public boolean reject(int[][] board)
{
//Check input
if(board == null)
{
return true;
}
{ //Check if 1-9 is max 1x in every row & line
//Helper-Vars - Start with false
boolean[] row = new boolean[boardsize];
boolean[] line = new boolean[boardsize];
for(int i=0; i < boardsize;i++) //rows
{
for(int j=0; j < boardsize; j++) //lines
{
{ //row
int t = board[i][j]; //value @ act pos //row
if( t > 0 && //skip 0 and wrong input!
t <= boardsize)
{
if(row[t-1]) //already seen?
{
//Number already found in row
return true;
} else
{
//Set to true - do not accept this number a second time.
row[t-1] = true;
}
}
} //row
{ //line
int t = board[j][i]; //value @ act pos //line
if( t > 0 && //skip 0 and wrong input!
t <= boardsize)
{
if(line[t-1]) //already seen?
{
//Number already found in line
return true;
} else
{
//Set to true - do not accept this number a second time.
line[t-1] = true;
}
}
} //line
}
//Reset helper-vars, new line/row
Arrays.fill(row, false);
Arrays.fill(line, false);
}
} //Check if 1-9 is max 1x in every row&line
{ //Check board-3x3-blocks
//Helper-Var - Starts with false
boolean[] block = new boolean[boardsize];
for(int n=0; n < 3; n++) //Count block-lines
{
for(int m=0; m < 3; m++) //Count block-rows
{
for(int i=0; i < (boardsize/3); i++) //Count line within block
{
for(int j=0; j < (boardsize/3); j++) //Count row within block
{
int t = board[n*3+i][m*3+j]; //Value @ act pos
if( t > 0 && //skip 0 and wrong input!
t <= boardsize)
{
if(block[t-1]) //Number already seen?
{
//Number already found in Block
return true;
} else
{
//Set to true - do not accept this number a second time.
block[t-1] = true;
}
}
}
}
//Reset - new block
Arrays.fill(block, false);
}
}
} //Check board-3x3-blocks
//All Checked & OK
return false;
}
/**
* Returns position of the next field which is 0 (free field).
*
* Position-Encoding: row*boardsize + line
* row and line starting by 0.
* first item is 0,
* last item is boardsize*boardsize -1
*
* public because assumed it is requested
*
* @param board
* @return Position of next free field or -1 if no free field was found.
*/
public int getNextFreeField(int[][] board)
{
//Just Checking - should never happen, but method is public... you know...
if(board == null)
{
return -1;
}
//Search
for(int i=0; i < boardsize; i++) //row
{
for(int j=0; j < boardsize; j++) //line
{
if(board[i][j] == 0) //Is act pos 0 ?
{
return i*boardsize + j; //Position Calculation
}
}
}
//Field has no empty fields
return -1;
}
/**
* Returns new Sudoku configuration with altered (incremented by 1)
* value at given position pos.
*
* public because assumed it is requested
*
* @param board Given Sudoku configuration
* @param pos position to be altered
* @return Sudoku configuration or null
*/
public int[][] getNextExtension(int[][] board, int pos)
{
//Decrypt 1-dim-pos to 2-dim-pos
int i = pos/boardsize;
int j = pos-i*boardsize;
if( board != null && //Board ok?
i < boardsize && //row ok?
j < boardsize && //line ok?
board[i][j] < boardsize) //value @ pos < boardsize?
{
int[][] newboard = new int[boardsize][boardsize];
{ //clone board -> newboard
for(int k = 0; k < boardsize; k++)
{
System.arraycopy(board[k], 0, newboard[k], 0, board[k].length);
}
} //clone board -> newboard
newboard[i][j] += 1; // inc value @ pos -> +1
return newboard; //return the new board
}
return null; //Something was wrong - see if clause
}
/**
* Solve the given Sudoku configuration and return the result.
*
* @param configuration A 9x9 two-dimensional array, columns first.
* @return The solution for this game of Sudoku or null if not solvable.
*/
public int[][] solve(int[][] configuration)
{
return solve(configuration,getNextFreeField(configuration));
}
/**
* Solve the given Sudoku configuration and return the result.
*
* @param configuration A 9x9 two-dimensional array, columns first.
* @param position to be altered (start with getNextFreeField(configuration))
* @return The solution for this game of Sudoku or null if not solvable.
*/
public int[][] solve(int[][] configuration, int pos)
{
//Recursion-anchor
if(pos == -1) //all fields are done, or startcall was wrong
{
return configuration;
}
//Recursion
while(true) //Always do^^
{
configuration = getNextExtension(configuration,pos); //getNextExt checks if pos/config is valid!
if(configuration == null)
{
return null; //Could not alter act pos any further, not solvable, try alter fields before filled in
}
if(!reject(configuration)) //is generated config ok?
{
int[][] tboard = solve(configuration,getNextFreeField(configuration)); //Fill in empty fields recursivly.
if(tboard != null) // was solvable
{
return tboard;
} //else config was not solvable - alter fields filled in before.
}
}
}
/**
* Main-Method
*
* some start-soduko-defs
*
* @param args
*/
public static void main(final String[] args) {
@SuppressWarnings("unused")
final int[][] emptyField = new int[][] { { 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0 } };
@SuppressWarnings("unused")
final int[][] fullField = new int[][] { { 5, 3, 4, 6, 7, 8, 9, 1, 2 },
{ 6, 7, 2, 1, 9, 5, 3, 4, 8 }, { 1, 9, 8, 3, 4, 2, 5, 6, 7 },
{ 8, 5, 9, 7, 6, 1, 4, 2, 3 }, { 4, 2, 6, 8, 5, 3, 7, 9, 1 },
{ 7, 1, 3, 9, 2, 4, 8, 5, 6 }, { 9, 6, 1, 5, 3, 7, 2, 8, 4 },
{ 2, 8, 7, 4, 1, 9, 6, 3, 5 }, { 3, 4, 5, 2, 8, 6, 1, 7, 9 } };
final int[][] actualField1 = new int[][] {
{ 5, 3, 0, 0, 7, 0, 0, 0, 0 }, { 6, 0, 0, 1, 9, 5, 0, 0, 0 },
{ 0, 9, 8, 0, 0, 0, 0, 6, 0 }, { 8, 0, 0, 0, 6, 0, 0, 0, 3 },
{ 4, 0, 0, 8, 0, 3, 0, 0, 1 }, { 7, 0, 0, 0, 2, 0, 0, 0, 6 },
{ 0, 6, 0, 0, 0, 0, 2, 8, 0 }, { 0, 0, 0, 4, 1, 9, 0, 0, 5 },
{ 0, 0, 0, 0, 8, 0, 0, 7, 9 } };
@SuppressWarnings("unused")
final int[][] actualField2 = new int[][] {
{ 1, 0, 2, 0, 0, 0, 0, 0, 0 }, { 0, 0, 3, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 4 }, { 0, 4, 0, 0, 5, 0, 0, 0, 0 },
{ 0, 6, 0, 0, 7, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 2, 0 },
{ 0, 8, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 8, 0, 0 } };
new Sudoku(actualField1).start();
}
}

228
src/SudokuTest.java Normal file
View File

@ -0,0 +1,228 @@
import java.util.Arrays;
import junit.framework.Assert;
import org.junit.Before;
import org.junit.Test;
public class SudokuTest {
/**
* Test cases for the solver. Public, because you can also use them to use
* them for game initialization!
*/
public final static int[][] testCase1 = new int[][] {
{ 5, 3, 0, 0, 7, 0, 0, 0, 0 }, { 6, 0, 0, 1, 9, 5, 0, 0, 0 },
{ 0, 9, 8, 0, 0, 0, 0, 6, 0 }, { 8, 0, 0, 0, 6, 0, 0, 0, 3 },
{ 4, 0, 0, 8, 0, 3, 0, 0, 1 }, { 7, 0, 0, 0, 2, 0, 0, 0, 6 },
{ 0, 6, 0, 0, 0, 0, 2, 8, 0 }, { 0, 0, 0, 4, 1, 9, 0, 0, 5 },
{ 0, 0, 0, 0, 8, 0, 0, 7, 9 } };
public final static int[][] testCase1Result = new int[][] {
{ 5, 3, 4, 6, 7, 8, 9, 1, 2 }, { 6, 7, 2, 1, 9, 5, 3, 4, 8 },
{ 1, 9, 8, 3, 4, 2, 5, 6, 7 }, { 8, 5, 9, 7, 6, 1, 4, 2, 3 },
{ 4, 2, 6, 8, 5, 3, 7, 9, 1 }, { 7, 1, 3, 9, 2, 4, 8, 5, 6 },
{ 9, 6, 1, 5, 3, 7, 2, 8, 4 }, { 2, 8, 7, 4, 1, 9, 6, 3, 5 },
{ 3, 4, 5, 2, 8, 6, 1, 7, 9 } };
public final static int[][] testCase2 = new int[][] {
{ 1, 0, 2, 0, 0, 0, 0, 0, 0 }, { 0, 0, 3, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 4 }, { 0, 4, 0, 0, 5, 0, 0, 0, 0 },
{ 0, 6, 0, 0, 7, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 2, 0 },
{ 0, 8, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 8, 0, 0 } };
public final static int[][] testCase2Result = new int[][] {
{ 1, 5, 2, 3, 4, 6, 7, 8, 9 }, { 4, 7, 3, 1, 8, 9, 2, 5, 6 },
{ 6, 9, 8, 5, 2, 7, 1, 3, 4 }, { 2, 4, 1, 6, 5, 3, 9, 7, 8 },
{ 5, 6, 9, 2, 7, 8, 3, 4, 1 }, { 8, 3, 7, 4, 9, 1, 6, 2, 5 },
{ 3, 8, 4, 9, 1, 2, 5, 6, 7 }, { 7, 1, 6, 8, 3, 5, 4, 9, 2 },
{ 9, 2, 5, 7, 6, 4, 8, 1, 3 } };
final int[][] testField3 = new int[][] { { 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 1, 2, 0, 4, 5, 6, 7 },
{ 0, 0, 2, 0, 0, 0, 4, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 4, 0, 0, 0, 2, 0, 0 }, { 0, 0, 5, 4, 0, 2, 1, 0, 0 },
{ 0, 0, 6, 0, 0, 0, 0, 0, 0 }, { 0, 0, 7, 0, 0, 0, 0, 0, 0 } };
//From template
public final int[][] fullField = new int[][] { { 5, 3, 4, 6, 7, 8, 9, 1, 2 },
{ 6, 7, 2, 1, 9, 5, 3, 4, 8 }, { 1, 9, 8, 3, 4, 2, 5, 6, 7 },
{ 8, 5, 9, 7, 6, 1, 4, 2, 3 }, { 4, 2, 6, 8, 5, 3, 7, 9, 1 },
{ 7, 1, 3, 9, 2, 4, 8, 5, 6 }, { 9, 6, 1, 5, 3, 7, 2, 8, 4 },
{ 2, 8, 7, 4, 1, 9, 6, 3, 5 }, { 3, 4, 5, 2, 8, 6, 1, 7, 9 } };
final int[][] sudoku17_1 = new int[][] {
{0, 0, 0, 0, 0, 0, 0, 1, 0}, { 0, 6, 0, 3, 0, 0, 0, 0, 0},
{9, 0, 0, 0, 0, 0, 0, 7, 0}, { 1, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 4, 0, 0, 6, 0, 0}, { 0, 0, 6, 0, 0, 0, 5, 0, 3},
{0, 0, 0, 0, 9, 0, 0, 0, 0}, { 0, 2, 0, 0, 0, 0, 4, 0, 0},
{0, 0, 8, 0, 1, 7, 0, 0, 0}
};
/**
* The test instance.
*/
private Sudoku sudoku;
/**
* Sets up the test environment.
*/
@Before
public void setUp() {
sudoku = new Sudoku();
}
/**
* Timing check
*/
/*
//This one is quite nasty
@Test
public void testTimingField17()
{
Assert.assertNull(sudoku.solve(sudoku17_1));
}*/
/**
* Timing check2
*/
@Test
public void testTimingField3()
{
Assert.assertNull(sudoku.solve(testField3));
}
/**
* Test if predefined fullfield is ok.
*/
@Test
public void testFullField()
{
//Question was raised - so i do the test
Assert.assertFalse(sudoku.reject(fullField));
}
/**
* Tests the {@link Sudoku#reject(int[][])} method.
*/
@Test
public void testReject() {
int[][] config = new int[9][9];
// Empty field is always valid!
Assert.assertFalse("reject false negative: rejected empty field!",
sudoku.reject(config));
// Check rows
config = new int[9][9];
config[5][1] = 9;
config[5][7] = 9;
Assert.assertTrue("reject false negative: row check failed!", sudoku
.reject(config));
config[5][7] = 6;
Assert.assertFalse("reject false positive: row check failed!", sudoku
.reject(config));
// Check columns
config = new int[9][9];
config[5][1] = 9;
config[8][1] = 9;
Assert.assertTrue("reject false negative: column check failed!", sudoku
.reject(config));
config[8][1] = 3;
Assert.assertFalse("reject false positive: column check failed!",
sudoku.reject(config));
// Check 3x3 fields
config = new int[9][9];
config[0][0] = 7;
config[2][2] = 7;
Assert.assertTrue("reject false negative: 3x3 field check failed!",
sudoku.reject(config));
config[2][2] = 4;
Assert.assertFalse("reject false positive: 3x3 field check failed!",
sudoku.reject(config));
config[2][3] = 7; // out of top-left field
Assert.assertFalse("reject false positive: 3x3 field check failed!",
sudoku.reject(config));
// Check with real-world example
Assert.assertFalse("reject false positive: real world example", sudoku
.reject(testCase1Result));
}
/**
* Tests the {@link Sudoku#getNextFreeField(int[][])} method.
*/
@Test
public void testNextFreeField() {
int[][] config = new int[9][9];
// Full & empty field
Assert.assertEquals(
"getNextFreeField failed: should return 0 if field is empty!",
0, sudoku.getNextFreeField(config));
Assert.assertEquals(
"getNextFreeField failed: should return -1 if field is full!",
-1, sudoku.getNextFreeField(testCase1Result));
// Normal fields
config[0][0] = 5;
Assert.assertEquals("getNextFreeField failed!", 1, sudoku
.getNextFreeField(config));
config[0][1] = 5;
Assert.assertEquals("getNextFreeField failed!", 2, sudoku
.getNextFreeField(config));
config[0] = new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
Assert.assertEquals("getNextFreeField failed for second row!", 9,
sudoku.getNextFreeField(config));
}
/**
* Tests the {@link Sudoku#getNextExtension(int[][], int)} method.
*/
@Test
public void testNextExtension() {
int[][] config = new int[9][9];
config[4][6] = 8; // Field 42
int[][] newConfig = sudoku.getNextExtension(config, 42);
Assert.assertEquals(
"getNextExtension failed: did not increment (correct) field!",
9, newConfig[4][6]);
Assert.assertNotSame(
"getNextExtension failed: did not create a new array!", config,
newConfig);
Assert.assertNotSame(
"getNextExtension failed: did not clone sub-arrays!",
config[0], newConfig[0]);
newConfig = sudoku.getNextExtension(newConfig, 42);
Assert
.assertEquals(
"getNextExtension failed: did not return null if field already is 9",
null, newConfig);
}
/**
* Tests the {@link Sudoku#solve(int[][])} method.
*/
@Test
public void testSolve() {
// Test cases
Assert.assertTrue("solve failed for test case 1", Arrays.deepEquals(
sudoku.solve(testCase1), testCase1Result));
Assert.assertTrue("solve failed for test case 2", Arrays.deepEquals(
sudoku.solve(testCase2), testCase2Result));
// Finished field should not be modified
Assert.assertTrue("solve failed for finished field", Arrays.deepEquals(
sudoku.solve(testCase1Result), testCase1Result));
}
}