├── .gitattributes
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── README.md
├── src
├── test
│ ├── resources
│ │ └── com
│ │ │ └── abhyudayasharma
│ │ │ └── sudoku
│ │ │ └── sudoku1.csv
│ └── java
│ │ └── com
│ │ └── abhyudayasharma
│ │ └── sudoku
│ │ ├── AppTest.java
│ │ └── SudokuBoardTest.java
└── main
│ └── java
│ └── com
│ └── abhyudayasharma
│ └── sudoku
│ ├── core
│ ├── MoveType.java
│ ├── AbstractMove.java
│ ├── Result.java
│ ├── BacktrackingMove.java
│ ├── AssignmentMove.java
│ └── SudokuSolver.java
│ ├── Main.java
│ ├── ui
│ ├── SudokuTableCellRenderer.java
│ ├── SudokuTable.java
│ ├── SudokuCellEditor.java
│ └── SudokuTableModel.java
│ ├── SudokuBoard.java
│ └── Sudoku.java
├── .gitignore
├── .editorconfig
├── .github
└── workflows
│ └── gradle.yml
├── LICENSE
├── settings.gradle
├── gradlew.bat
└── gradlew
/.gitattributes:
--------------------------------------------------------------------------------
1 | *.bat eol=crlf
2 | *.csv eol=crlf # RFC4180
3 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AbhyudayaSharma/sudoku/master/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Sudoku
2 |
3 | A Sudoku solver for a college project.
4 |
5 |
6 |
7 | To run the application:
8 |
9 | ```bash
10 | ./gradlew run
11 | ```
12 |
--------------------------------------------------------------------------------
/src/test/resources/com/abhyudayasharma/sudoku/sudoku1.csv:
--------------------------------------------------------------------------------
1 | 1,,3,4,5,6,7,8,9
2 | 1,,3,4,5,6,7,8,9
3 | 1,,3,4,5,6,7,8,9
4 | 1,,3,4,5,6,7,8,9
5 | 1,,3,4,5,6,7,8,9
6 | 1,,3,4,5,6,7,8,9
7 | 1,,3,4,5,6,7,8,9
8 | 1,,3,4,5,6,7,8,9
9 | 1,,3,4,5,6,7,8,9
10 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .idea
2 | .gradle
3 |
4 | /build/
5 |
6 | # Ignore Gradle GUI config
7 | gradle-app.setting
8 |
9 | # Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored)
10 | !gradle-wrapper.jar
11 |
12 | # Cache of project
13 | .gradletasknamecache
14 |
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | root = true
2 |
3 | [*]
4 | end_of_line = lf
5 | indent_style = space
6 | indent_size = 4
7 | charset = utf-8
8 | trim_trailing_whitespace = true
9 | max_line_length = 120
10 | insert_final_newline = true
11 | tab_width = 4
12 |
13 | [*.bat]
14 | end_of_line = crlf
15 |
16 | [*.csv] # RFC4180
17 | end_of_line = crlf
18 |
19 | [*.properties]
20 | charset = latin1
21 |
22 | [*.{yml, yaml}]
23 | indent_size = 2
24 |
--------------------------------------------------------------------------------
/.github/workflows/gradle.yml:
--------------------------------------------------------------------------------
1 | name: Java CI
2 |
3 | on: [push]
4 |
5 | jobs:
6 | build:
7 | runs-on: ${{ matrix.os }}
8 | strategy:
9 | matrix:
10 | os: [ubuntu-latest, windows-latest, macOS-latest]
11 |
12 | steps:
13 | - uses: actions/checkout@v1
14 | - name: Set up JDK 11
15 | uses: actions/setup-java@v1
16 | with:
17 | java-version: 11
18 | - name: Build with Gradle
19 | run: ./gradlew build
20 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2019 Abhyudaya Sharma
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | /*
2 | * MIT License
3 | *
4 | * Copyright (c) 2019 Abhyudaya Sharma
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in all
14 | * copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | * SOFTWARE.
23 | */
24 |
25 | rootProject.name = 'sudoku'
26 |
--------------------------------------------------------------------------------
/src/main/java/com/abhyudayasharma/sudoku/core/MoveType.java:
--------------------------------------------------------------------------------
1 | /*
2 | * MIT License
3 | *
4 | * Copyright (c) 2019 Abhyudaya Sharma
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in all
14 | * copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | * SOFTWARE.
23 | */
24 |
25 | package com.abhyudayasharma.sudoku.core;
26 |
27 | public enum MoveType {
28 | ASSIGNMENT,
29 | BACKTRACK
30 | }
31 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #
2 | # MIT License
3 | #
4 | # Copyright (c) 2019 Abhyudaya Sharma
5 | #
6 | # Permission is hereby granted, free of charge, to any person obtaining a copy
7 | # of this software and associated documentation files (the "Software"), to deal
8 | # in the Software without restriction, including without limitation the rights
9 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | # copies of the Software, and to permit persons to whom the Software is
11 | # furnished to do so, subject to the following conditions:
12 | #
13 | # The above copyright notice and this permission notice shall be included in all
14 | # copies or substantial portions of the Software.
15 | #
16 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | # SOFTWARE.
23 | #Wed Aug 28 17:23:11 IST 2019
24 | distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.1-all.zip
25 | distributionBase=GRADLE_USER_HOME
26 | distributionPath=wrapper/dists
27 | zipStorePath=wrapper/dists
28 | zipStoreBase=GRADLE_USER_HOME
29 |
--------------------------------------------------------------------------------
/src/main/java/com/abhyudayasharma/sudoku/core/AbstractMove.java:
--------------------------------------------------------------------------------
1 | /*
2 | * MIT License
3 | *
4 | * Copyright (c) 2019 Abhyudaya Sharma
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in all
14 | * copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | * SOFTWARE.
23 | */
24 |
25 | package com.abhyudayasharma.sudoku.core;
26 |
27 | import lombok.AllArgsConstructor;
28 | import lombok.Getter;
29 |
30 | @AllArgsConstructor
31 | public abstract class AbstractMove {
32 | @Getter
33 | final MoveType moveType;
34 | }
35 |
--------------------------------------------------------------------------------
/src/main/java/com/abhyudayasharma/sudoku/core/Result.java:
--------------------------------------------------------------------------------
1 | /*
2 | * MIT License
3 | *
4 | * Copyright (c) 2019 Abhyudaya Sharma
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in all
14 | * copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | * SOFTWARE.
23 | */
24 |
25 | package com.abhyudayasharma.sudoku.core;
26 |
27 | import com.abhyudayasharma.sudoku.SudokuBoard;
28 | import lombok.NonNull;
29 | import lombok.Value;
30 |
31 | @Value
32 | @SuppressWarnings("WeakerAccess")
33 | public class Result {
34 | @NonNull
35 | final SudokuBoard board;
36 | final int backTrackCount;
37 | }
38 |
--------------------------------------------------------------------------------
/src/test/java/com/abhyudayasharma/sudoku/AppTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * MIT License
3 | *
4 | * Copyright (c) 2019 Abhyudaya Sharma
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in all
14 | * copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | * SOFTWARE.
23 | */
24 |
25 | package com.abhyudayasharma.sudoku;
26 |
27 | import org.junit.jupiter.api.Test;
28 |
29 | import static org.junit.jupiter.api.Assertions.assertTrue;
30 |
31 | class AppTest {
32 | /**
33 | * Sample test for the application.
34 | */
35 | @Test
36 | void test() {
37 | assertTrue(true);
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/src/main/java/com/abhyudayasharma/sudoku/Main.java:
--------------------------------------------------------------------------------
1 | /*
2 | * MIT License
3 | *
4 | * Copyright (c) 2019 Abhyudaya Sharma
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in all
14 | * copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | * SOFTWARE.
23 | */
24 |
25 | package com.abhyudayasharma.sudoku;
26 |
27 | import lombok.extern.slf4j.Slf4j;
28 |
29 | import javax.swing.SwingUtilities;
30 | import javax.swing.UIManager;
31 | import javax.swing.UnsupportedLookAndFeelException;
32 | import javax.swing.plaf.nimbus.NimbusLookAndFeel;
33 |
34 | @Slf4j
35 | public class Main {
36 | public static void main(String[] args) {
37 | try {
38 | UIManager.setLookAndFeel(new NimbusLookAndFeel());
39 | } catch (UnsupportedLookAndFeelException e) {
40 | log.warn("Unable to set Nimbus Look and Feel for the application.", e);
41 | }
42 |
43 | SwingUtilities.invokeLater(() -> new Sudoku().start());
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/src/main/java/com/abhyudayasharma/sudoku/core/BacktrackingMove.java:
--------------------------------------------------------------------------------
1 | /*
2 | * MIT License
3 | *
4 | * Copyright (c) 2019 Abhyudaya Sharma
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in all
14 | * copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | * SOFTWARE.
23 | */
24 |
25 | package com.abhyudayasharma.sudoku.core;
26 |
27 | import lombok.Getter;
28 | import lombok.ToString;
29 | import lombok.experimental.FieldDefaults;
30 |
31 | @Getter
32 | @ToString
33 | @FieldDefaults(makeFinal = true)
34 | class BacktrackingMove extends AbstractMove {
35 | private final int fromRow;
36 | private final int fromCol;
37 | private final int toRow;
38 | private final int toCol;
39 |
40 | BacktrackingMove(int fromRow, int fromCol, int toRow, int toCol) {
41 | super(MoveType.BACKTRACK);
42 | this.fromRow = fromRow;
43 | this.fromCol = fromCol;
44 | this.toRow = toRow;
45 | this.toCol = toCol;
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/src/main/java/com/abhyudayasharma/sudoku/core/AssignmentMove.java:
--------------------------------------------------------------------------------
1 | /*
2 | * MIT License
3 | *
4 | * Copyright (c) 2019 Abhyudaya Sharma
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in all
14 | * copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | * SOFTWARE.
23 | */
24 |
25 | package com.abhyudayasharma.sudoku.core;
26 |
27 | import lombok.EqualsAndHashCode;
28 | import lombok.Getter;
29 | import lombok.ToString;
30 |
31 | @ToString
32 | @EqualsAndHashCode(callSuper = false)
33 | public
34 | class AssignmentMove extends AbstractMove {
35 | @Getter
36 | private final int row;
37 | @Getter
38 | private final int col;
39 | @Getter
40 | private final int oldValue;
41 | @Getter
42 | private final int newValue;
43 |
44 | AssignmentMove(int row, int col, int oldValue, int newValue) {
45 | super(MoveType.ASSIGNMENT);
46 | this.row = row;
47 | this.col = col;
48 | this.oldValue = oldValue;
49 | this.newValue = newValue;
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | set DIRNAME=%~dp0
12 | if "%DIRNAME%" == "" set DIRNAME=.
13 | set APP_BASE_NAME=%~n0
14 | set APP_HOME=%DIRNAME%
15 |
16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
17 | set DEFAULT_JVM_OPTS="-Xmx64m"
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windows variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 |
53 | :win9xME_args
54 | @rem Slurp the command line arguments.
55 | set CMD_LINE_ARGS=
56 | set _SKIP=2
57 |
58 | :win9xME_args_slurp
59 | if "x%~1" == "x" goto execute
60 |
61 | set CMD_LINE_ARGS=%*
62 |
63 | :execute
64 | @rem Setup the command line
65 |
66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
67 |
68 | @rem Execute Gradle
69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
70 |
71 | :end
72 | @rem End local scope for the variables with windows NT shell
73 | if "%ERRORLEVEL%"=="0" goto mainEnd
74 |
75 | :fail
76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
77 | rem the _cmd.exe /c_ return code!
78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
79 | exit /b 1
80 |
81 | :mainEnd
82 | if "%OS%"=="Windows_NT" endlocal
83 |
84 | :omega
85 |
--------------------------------------------------------------------------------
/src/test/java/com/abhyudayasharma/sudoku/SudokuBoardTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * MIT License
3 | *
4 | * Copyright (c) 2019 Abhyudaya Sharma
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in all
14 | * copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | * SOFTWARE.
23 | */
24 |
25 | package com.abhyudayasharma.sudoku;
26 |
27 | import org.junit.jupiter.api.Test;
28 |
29 | import static org.junit.jupiter.api.Assertions.assertEquals;
30 | import static org.junit.jupiter.api.Assertions.assertTrue;
31 |
32 | class SudokuBoardTest {
33 | @Test
34 | void sizeTest() {
35 | assertEquals(9, SudokuBoard.SIZE);
36 | var sqrt = Math.sqrt(SudokuBoard.SIZE);
37 |
38 | // should be a perfect square
39 | assertTrue(sqrt == Math.floor(sqrt) && !Double.isInfinite(sqrt));
40 | }
41 |
42 | @Test
43 | void csvLoadTest1() throws Exception {
44 | final int[][] expected = new int[][]{
45 | {1, 0, 3, 4, 5, 6, 7, 8, 9},
46 | {1, 0, 3, 4, 5, 6, 7, 8, 9},
47 | {1, 0, 3, 4, 5, 6, 7, 8, 9},
48 | {1, 0, 3, 4, 5, 6, 7, 8, 9},
49 | {1, 0, 3, 4, 5, 6, 7, 8, 9},
50 | {1, 0, 3, 4, 5, 6, 7, 8, 9},
51 | {1, 0, 3, 4, 5, 6, 7, 8, 9},
52 | {1, 0, 3, 4, 5, 6, 7, 8, 9},
53 | {1, 0, 3, 4, 5, 6, 7, 8, 9},
54 | };
55 |
56 | SudokuBoard board = SudokuBoard.load(getClass().getResource("sudoku1.csv").toURI());
57 | for (int i = 0; i < SudokuBoard.SIZE; i++) {
58 | for (int j = 0; j < SudokuBoard.SIZE; j++) {
59 | assertEquals(expected[i][j], board.get(i, j).orElse(0));
60 | }
61 | }
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/src/main/java/com/abhyudayasharma/sudoku/ui/SudokuTableCellRenderer.java:
--------------------------------------------------------------------------------
1 | /*
2 | * MIT License
3 | *
4 | * Copyright (c) 2019 Abhyudaya Sharma
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in all
14 | * copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | * SOFTWARE.
23 | */
24 |
25 | package com.abhyudayasharma.sudoku.ui;
26 |
27 | import com.abhyudayasharma.sudoku.SudokuBoard;
28 |
29 | import javax.swing.BorderFactory;
30 | import javax.swing.JComponent;
31 | import javax.swing.JTable;
32 | import javax.swing.SwingConstants;
33 | import javax.swing.table.DefaultTableCellRenderer;
34 | import java.awt.Color;
35 | import java.awt.Component;
36 |
37 | public class SudokuTableCellRenderer extends DefaultTableCellRenderer {
38 | private final int sqrt = (int) Math.rint(Math.sqrt(SudokuBoard.SIZE));
39 | private final Color borderColor = Color.BLACK;
40 |
41 | @Override
42 | public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected,
43 | boolean hasFocus, int row, int column) {
44 | final var component = super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
45 | var border = BorderFactory.createEmptyBorder();
46 |
47 | final var borderThickness = 3;
48 | if (row % sqrt == sqrt - 1 && row != SudokuBoard.SIZE - 1) {
49 | border = BorderFactory.createCompoundBorder(border,
50 | BorderFactory.createMatteBorder(0, 0, borderThickness, 0, borderColor));
51 | }
52 |
53 | if (column % sqrt == sqrt - 1 && column != SudokuBoard.SIZE - 1) {
54 | border = BorderFactory.createCompoundBorder(border,
55 | BorderFactory.createMatteBorder(0, 0, 0, borderThickness, borderColor));
56 | }
57 |
58 | if (component instanceof JComponent) {
59 | ((JComponent) component).setBorder(border);
60 | } else {
61 | throw new IllegalArgumentException("component should be a JComponent");
62 | }
63 |
64 | return component;
65 | }
66 |
67 | @Override
68 | public int getHorizontalAlignment() {
69 | return SwingConstants.CENTER;
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/src/main/java/com/abhyudayasharma/sudoku/ui/SudokuTable.java:
--------------------------------------------------------------------------------
1 | /*
2 | * MIT License
3 | *
4 | * Copyright (c) 2019 Abhyudaya Sharma
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in all
14 | * copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | * SOFTWARE.
23 | */
24 |
25 | package com.abhyudayasharma.sudoku.ui;
26 |
27 | import com.abhyudayasharma.sudoku.Sudoku;
28 | import com.abhyudayasharma.sudoku.SudokuBoard;
29 |
30 | import javax.swing.BorderFactory;
31 | import javax.swing.JTable;
32 | import javax.swing.ListSelectionModel;
33 | import javax.swing.table.DefaultTableCellRenderer;
34 | import javax.swing.table.TableCellEditor;
35 | import javax.swing.table.TableCellRenderer;
36 | import java.awt.Color;
37 | import java.net.URI;
38 |
39 | public class SudokuTable extends JTable {
40 | private static final int CELL_SIZE = 60;
41 |
42 | private static final DefaultTableCellRenderer defaultRenderer = new SudokuTableCellRenderer();
43 |
44 | @Override
45 | public SudokuTableModel getModel() {
46 | return (SudokuTableModel) super.getModel();
47 | }
48 |
49 | @Override
50 | public TableCellEditor getCellEditor(int row, int column) {
51 | return new SudokuCellEditor();
52 | }
53 |
54 | public SudokuTable() {
55 | super(new SudokuTableModel());
56 | cellSelectionEnabled = rowSelectionAllowed = false;
57 | selectionModel.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
58 | showVerticalLines = true;
59 | showHorizontalLines = true;
60 | autoResizeMode = JTable.AUTO_RESIZE_OFF;
61 | rowHeight = CELL_SIZE;
62 | tableHeader = null;
63 |
64 | setColumnCellEditors();
65 | setFont(Sudoku.BOARD_FONT);
66 | setBorder(BorderFactory.createLineBorder(Color.BLACK, 2, false));
67 | }
68 |
69 | @Override
70 | public TableCellRenderer getCellRenderer(int row, int column) {
71 | return defaultRenderer;
72 | }
73 |
74 | public SudokuBoard getBoard() {
75 | return getModel().asBoard();
76 | }
77 |
78 | private void setColumnCellEditors() {
79 | for (var it = columnModel.getColumns().asIterator(); it.hasNext(); ) {
80 | var column = it.next();
81 | column.setPreferredWidth(CELL_SIZE);
82 | column.setCellEditor(new SudokuCellEditor());
83 | }
84 | }
85 |
86 | /**
87 | * Load the table from a CSV file
88 | *
89 | * @param uri uri to a CSV fil
90 | * @throws Exception if unable to load the file
91 | */
92 | public void load(URI uri) throws Exception {
93 | setModel(new SudokuTableModel(uri));
94 | setColumnCellEditors();
95 | }
96 |
97 | public void clear() {
98 | getModel().clear();
99 | repaint();
100 | }
101 | }
102 |
--------------------------------------------------------------------------------
/src/main/java/com/abhyudayasharma/sudoku/ui/SudokuCellEditor.java:
--------------------------------------------------------------------------------
1 | /*
2 | * MIT License
3 | *
4 | * Copyright (c) 2019 Abhyudaya Sharma
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in all
14 | * copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | * SOFTWARE.
23 | */
24 |
25 | package com.abhyudayasharma.sudoku.ui;
26 |
27 | import com.abhyudayasharma.sudoku.Sudoku;
28 | import com.abhyudayasharma.sudoku.SudokuBoard;
29 |
30 | import javax.swing.DefaultCellEditor;
31 | import javax.swing.JOptionPane;
32 | import javax.swing.JTextField;
33 | import javax.swing.SwingUtilities;
34 | import javax.swing.event.DocumentEvent;
35 | import javax.swing.event.DocumentListener;
36 |
37 | /**
38 | * A {@link javax.swing.CellEditor} that validates input for a sudoku cell and sets the font specified by
39 | * {@link Sudoku#BOARD_FONT}.
40 | *
41 | * @author Abhyudaya Sharma
42 | */
43 | class SudokuCellEditor extends DefaultCellEditor {
44 | SudokuCellEditor() {
45 | super(new SudokuTextField());
46 | }
47 |
48 | private static class SudokuTextField extends JTextField {
49 | SudokuTextField() {
50 | setFont(Sudoku.BOARD_FONT);
51 | setHorizontalAlignment(CENTER);
52 |
53 | getDocument().addDocumentListener(new DocumentListener() {
54 | @Override
55 | public void insertUpdate(DocumentEvent documentEvent) {
56 | checkAndWarn();
57 | }
58 |
59 | @Override
60 | public void removeUpdate(DocumentEvent documentEvent) {
61 | checkAndWarn();
62 | }
63 |
64 | @Override
65 | public void changedUpdate(DocumentEvent documentEvent) {
66 | checkAndWarn();
67 | }
68 |
69 | /**
70 | * Validates the input as a possible number for a sudoku square.
71 | *
72 | * If the integer parsed from the text of the {@link JTextField} is valid, the text is left unmodified.
73 | * Otherwise, the text is set to an empty string. If the parsed number was not in range for the puzzle,
74 | * a message box is generated.
75 | */
76 | private void checkAndWarn() {
77 | final var text = SudokuTextField.this.getText();
78 |
79 | // blank input is invalid; empty is fine
80 | if (text.isEmpty()) {
81 | return;
82 | }
83 |
84 | var parsedInt = 0;
85 | var doClearTextField = false;
86 | try {
87 | parsedInt = Integer.parseInt(text);
88 | } catch (NumberFormatException e) {
89 | doClearTextField = true;
90 | }
91 |
92 | if (!doClearTextField && (parsedInt > SudokuBoard.SIZE || parsedInt <= 0)) {
93 | SwingUtilities.invokeLater(() -> JOptionPane.showMessageDialog(
94 | SudokuTextField.this.getTopLevelAncestor(),
95 | String.format("Please enter an integer between %d and %d", 1, SudokuBoard.SIZE),
96 | "Invalid input", JOptionPane.WARNING_MESSAGE));
97 |
98 | doClearTextField = true;
99 | }
100 |
101 | if (doClearTextField) {
102 | SwingUtilities.invokeLater(() -> SudokuTextField.this.setText(""));
103 | }
104 | }
105 | });
106 | }
107 | }
108 | }
109 |
--------------------------------------------------------------------------------
/src/main/java/com/abhyudayasharma/sudoku/ui/SudokuTableModel.java:
--------------------------------------------------------------------------------
1 | /*
2 | * MIT License
3 | *
4 | * Copyright (c) 2019 Abhyudaya Sharma
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in all
14 | * copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | * SOFTWARE.
23 | */
24 |
25 | package com.abhyudayasharma.sudoku.ui;
26 |
27 | import com.abhyudayasharma.sudoku.SudokuBoard;
28 | import lombok.Getter;
29 | import lombok.Setter;
30 | import org.apache.commons.csv.CSVFormat;
31 | import org.apache.commons.csv.CSVPrinter;
32 | import org.apache.commons.io.FilenameUtils;
33 |
34 | import javax.swing.event.TableModelEvent;
35 | import javax.swing.event.TableModelListener;
36 | import javax.swing.table.TableModel;
37 | import java.io.BufferedWriter;
38 | import java.io.File;
39 | import java.io.FileWriter;
40 | import java.io.IOException;
41 | import java.net.URI;
42 | import java.nio.charset.StandardCharsets;
43 | import java.util.ArrayList;
44 | import java.util.Collections;
45 | import java.util.List;
46 | import java.util.Vector;
47 |
48 | public class SudokuTableModel implements TableModel {
49 | private final List
45 | * Internally, {@code 0} values are considered empty values. Values less than {@code 0} or greater than
46 | * {@link SudokuBoard#SIZE} are not valid.
47 | *
48 | * @author Abhyudaya Sharma
49 | */
50 | @Slf4j
51 | public class SudokuBoard {
52 | public static final int SIZE = 9;
53 | private final int[][] matrix;
54 |
55 | /**
56 | * Creates a sudoku board from a list of list os {@link String}s.
57 | * Empty strings are considered as empty sudoku cells.
58 | *
59 | * @param strings raw strings
60 | * @throws IllegalArgumentException if any of the {@link String} values is not valid in the Sudoku.
61 | */
62 | public SudokuBoard(List
183 | * The returned list is modifiable and a new list is generated on every call.
184 | *
185 | * @return the sudoku as a list of list of strings
186 | */
187 | public List> data;
50 | private final List
> strings) {
63 | matrix = new int[SIZE][SIZE];
64 | for (int i = 0; i < SIZE; i++) {
65 | for (int j = 0; j < SIZE; j++) {
66 | matrix[i][j] = parseValue(strings.get(i).get(j));
67 | }
68 | }
69 | }
70 |
71 | /**
72 | * Creates a SudokuBoard from the given matrix.
73 | *
74 | * @param matrix initialize the sudoku board from the given matrix
75 | */
76 | private SudokuBoard(int[][] matrix) {
77 | var isInvalid = false;
78 | if (matrix.length != SIZE) {
79 | isInvalid = true;
80 | }
81 |
82 | isInvalid = isInvalid || !Arrays.stream(matrix).mapToInt(row -> row.length).allMatch(length -> length == SIZE);
83 | isInvalid = isInvalid || !Arrays.stream(matrix).allMatch(
84 | row -> Arrays.stream(row).allMatch(x -> x >= 0 && x <= SIZE));
85 |
86 | if (isInvalid) {
87 | throw new IllegalArgumentException(String.format("The size of the matrix should be %d x %d", SIZE, SIZE));
88 | }
89 |
90 | this.matrix = matrix;
91 | }
92 |
93 | /**
94 | * Creates a {@link SudokuBoard} from the CSV file.
95 | *
96 | * @param uri the {@link URI} to the CSV file that will be used to initialize the sudoku board.
97 | * @return A {@link SudokuBoard} with values read from the CSV file
98 | * @throws IOException if an I/O error takes place when trying to read the file
99 | * @throws IllegalArgumentException if any entry of the CSV is not a positive integer
100 | */
101 | public static SudokuBoard load(URI uri) throws IOException {
102 | var parser = CSVParser.parse(uri.toURL(), StandardCharsets.UTF_8, CSVFormat.RFC4180);
103 | int[][] matrix = new int[SIZE][SIZE];
104 |
105 | List
> asList() {
188 | var ret = new ArrayList
>();
189 | for (int[] ints : matrix) {
190 | ret.add(Arrays.stream(ints).mapToObj(x -> x == 0 ? "" : String.valueOf(x)).collect(Collectors.toList()));
191 | }
192 | return ret;
193 | }
194 |
195 | /**
196 | * Return true if the {@link SudokuBoard} is valid.
197 | *
198 | * @return true if the {@link SudokuBoard} is valid.
199 | */
200 | public boolean isValid() {
201 | final var rowInts = new HashSet