From f5aa725b72dc8fe3722ec2ebb9df06220a740aec Mon Sep 17 00:00:00 2001 From: Lothar Buchholz Date: Fri, 28 Feb 2020 00:14:24 +0100 Subject: [PATCH] added README and testdata --- README.md | 37 ++++++++++++++++++++++++++++++++ settings.gradle | 2 +- src/test/java/SolutionTest.java | 13 ++++++++++- src/test/resources/sudoku1.txt | 9 ++++++++ src/test/resources/sudoku2.txt | 9 ++++++++ src/test/resources/sudoku3.txt | 9 ++++++++ src/test/resources/sudoku4.txt | 9 ++++++++ src/test/resources/sudoku5.txt | 9 ++++++++ src/test/resources/testdata.csv | 5 +++++ sudoku.gif | Bin 0 -> 18445 bytes 10 files changed, 100 insertions(+), 2 deletions(-) create mode 100644 src/test/resources/sudoku1.txt create mode 100644 src/test/resources/sudoku2.txt create mode 100644 src/test/resources/sudoku3.txt create mode 100644 src/test/resources/sudoku4.txt create mode 100644 src/test/resources/sudoku5.txt create mode 100644 sudoku.gif diff --git a/README.md b/README.md index e69de29..29d796a 100644 --- a/README.md +++ b/README.md @@ -0,0 +1,37 @@ +# Sudoku verifier + +## Definition +Sudokus are logic number puzzles in which cells in a 9×9 grid must be populated with +the digits 1 to 9 in a way that each digit occurrs only once in each unit (that is column, +row or block = 3×3 sub grid). + +![a solved simple sudoku](sudoku.gif) + +## Goal +Validate if a given solution for a Sudoku is valid, by checking that the digit +1 to 9 appear only once in column, in each row and in each of the 9 sub grids. + +### Input +a sequence of 81 digits, organized in 9 columns and 9 rows + +### Output +A boolean value, if the grid is valid. + +### Constraints +1 <= `digit` <= 9 + +### Examples +**Input:** +``` +9 8 1 5 2 3 6 4 7 +6 3 4 8 7 9 2 5 1 +2 7 5 1 4 6 9 8 3 +1 9 6 4 8 7 5 3 2 +5 4 8 3 1 2 7 6 9 +7 2 3 6 9 5 4 1 8 +3 1 2 7 5 4 8 9 6 +4 6 9 2 3 8 1 7 5 +8 5 7 9 6 1 3 2 4 +``` +**Output:** +`true` diff --git a/settings.gradle b/settings.gradle index d5271ef..bb693f7 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1 +1 @@ -rootProject.name = 'template' +rootProject.name = 'sudoku-verifier' diff --git a/src/test/java/SolutionTest.java b/src/test/java/SolutionTest.java index c8470db..c5912a4 100644 --- a/src/test/java/SolutionTest.java +++ b/src/test/java/SolutionTest.java @@ -1,8 +1,10 @@ import java.io.*; +import java.util.stream.Collectors; import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.converter.*; import org.junit.jupiter.params.provider.CsvFileSource; import static java.nio.charset.StandardCharsets.UTF_8; @@ -10,6 +12,15 @@ import static org.junit.jupiter.api.Assertions.*; class SolutionTest { + static class SudokuConverter extends SimpleArgumentConverter { + @Override + protected Object convert( Object source, Class targetType ) throws ArgumentConversionException { + assertEquals(String.class, targetType, "Can only convert to String"); + BufferedReader in = new BufferedReader( new InputStreamReader( SolutionTest.class.getResourceAsStream( String.valueOf( source )))); + return in.lines().collect( Collectors.joining( System.lineSeparator() )); + } + } + static long totalDuration; @BeforeAll @@ -24,7 +35,7 @@ class SolutionTest { @ParameterizedTest @CsvFileSource( resources = "testdata.csv" ) - void main( final String input, final String expected ) throws IOException { + void main( @ConvertWith( SudokuConverter.class ) final String input, final String expected ) throws IOException { // keep original streams InputStream oldIn = System.in; PrintStream oldOut = System.out; diff --git a/src/test/resources/sudoku1.txt b/src/test/resources/sudoku1.txt new file mode 100644 index 0000000..520ae33 --- /dev/null +++ b/src/test/resources/sudoku1.txt @@ -0,0 +1,9 @@ +9 8 1 5 2 3 6 4 7 +6 3 4 8 7 9 2 5 1 +2 7 5 1 4 6 9 8 3 +1 9 6 4 8 7 5 3 2 +5 4 8 3 1 2 7 6 9 +7 2 3 6 9 5 4 1 8 +3 1 2 7 5 4 8 9 6 +4 6 9 2 3 8 1 7 5 +8 5 7 9 6 1 3 2 4 diff --git a/src/test/resources/sudoku2.txt b/src/test/resources/sudoku2.txt new file mode 100644 index 0000000..efa9df5 --- /dev/null +++ b/src/test/resources/sudoku2.txt @@ -0,0 +1,9 @@ +2 4 6 8 9 3 7 5 1 +5 9 8 6 7 1 4 2 3 +1 7 3 5 2 4 6 9 8 +7 5 1 2 3 6 8 4 9 +9 8 2 1 4 5 3 7 6 +6 3 4 7 8 9 5 1 2 +4 1 9 3 5 8 2 6 7 +8 2 5 9 6 7 1 3 4 +3 6 7 4 1 2 9 8 5 diff --git a/src/test/resources/sudoku3.txt b/src/test/resources/sudoku3.txt new file mode 100644 index 0000000..778e7e0 --- /dev/null +++ b/src/test/resources/sudoku3.txt @@ -0,0 +1,9 @@ +8 4 2 9 6 7 5 3 1 +7 9 3 5 1 8 4 6 2 +6 1 5 2 4 3 8 7 9 +2 7 9 8 7 6 3 1 4 +1 6 7 4 3 2 9 5 8 +4 3 8 1 9 5 6 2 7 +9 2 6 3 8 1 7 4 5 +3 8 1 7 5 4 2 9 6 +5 7 4 6 2 9 1 8 3 diff --git a/src/test/resources/sudoku4.txt b/src/test/resources/sudoku4.txt new file mode 100644 index 0000000..18658cf --- /dev/null +++ b/src/test/resources/sudoku4.txt @@ -0,0 +1,9 @@ +8 9 4 7 1 3 5 2 6 +7 1 2 6 5 8 4 3 9 +6 3 5 4 9 2 1 8 7 +2 4 1 5 3 6 7 9 8 +9 8 6 1 2 7 3 5 4 +3 5 7 9 8 4 2 6 1 +1 6 9 3 4 5 8 7 2 +4 2 3 8 7 9 6 1 5 +5 7 8 2 6 1 9 4 3 diff --git a/src/test/resources/sudoku5.txt b/src/test/resources/sudoku5.txt new file mode 100644 index 0000000..355c41a --- /dev/null +++ b/src/test/resources/sudoku5.txt @@ -0,0 +1,9 @@ +3 2 7 6 9 5 1 8 4 +8 1 5 4 7 3 6 2 9 +9 4 6 1 2 8 7 5 3 +6 5 1 8 4 2 3 9 7 +4 3 9 7 5 6 8 1 2 +2 7 8 3 1 9 5 6 4 +5 6 3 2 8 4 9 7 1 +7 8 4 9 3 1 2 6 5 +1 9 2 5 6 7 4 3 8 diff --git a/src/test/resources/testdata.csv b/src/test/resources/testdata.csv index e69de29..788cdbd 100644 --- a/src/test/resources/testdata.csv +++ b/src/test/resources/testdata.csv @@ -0,0 +1,5 @@ +sudoku1.txt, true +sudoku2.txt, true +sudoku3.txt, false +sudoku4.txt, true +sudoku5.txt, false diff --git a/sudoku.gif b/sudoku.gif new file mode 100644 index 0000000000000000000000000000000000000000..0c45a004b3abcaedea173985a9fef59a0f2a47aa GIT binary patch literal 18445 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