semi-functionning console interface
All checks were successful
Linux arm64 / Build (push) Successful in 38s

This commit is contained in:
Janet-Doe
2025-01-30 11:51:17 +01:00
parent d4beaec8a8
commit f1d963e546
7 changed files with 191 additions and 951 deletions

1
app/save/.gitignore vendored
View File

@@ -1 +0,0 @@
save-*.json

View File

@@ -1,913 +0,0 @@
{
"cells": [
{
"blockID": 0,
"symbolIndex": -1
},
{
"blockID": 0,
"symbolIndex": -1
},
{
"blockID": 0,
"symbolIndex": -1
},
{
"blockID": 0,
"symbolIndex": -1
},
{
"blockID": 1,
"symbolIndex": -1
},
{
"blockID": 1,
"symbolIndex": -1
},
{
"blockID": 1,
"symbolIndex": -1
},
{
"blockID": 1,
"symbolIndex": -1
},
{
"blockID": 2,
"symbolIndex": -1
},
{
"blockID": 2,
"symbolIndex": -1
},
{
"blockID": 2,
"symbolIndex": -1
},
{
"blockID": 2,
"symbolIndex": -1
},
{
"blockID": 0,
"symbolIndex": -1
},
{
"blockID": 0,
"symbolIndex": -1
},
{
"blockID": 0,
"symbolIndex": -1
},
{
"blockID": 0,
"symbolIndex": -1
},
{
"blockID": 1,
"symbolIndex": -1
},
{
"blockID": 1,
"symbolIndex": -1
},
{
"blockID": 1,
"symbolIndex": -1
},
{
"blockID": 1,
"symbolIndex": -1
},
{
"blockID": 2,
"symbolIndex": -1
},
{
"blockID": 2,
"symbolIndex": -1
},
{
"blockID": 2,
"symbolIndex": -1
},
{
"blockID": 2,
"symbolIndex": -1
},
{
"blockID": 0,
"symbolIndex": -1
},
{
"blockID": 0,
"symbolIndex": -1
},
{
"blockID": 0,
"symbolIndex": -1
},
{
"blockID": 0,
"symbolIndex": -1
},
{
"blockID": 1,
"symbolIndex": -1
},
{
"blockID": 1,
"symbolIndex": -1
},
{
"blockID": 1,
"symbolIndex": -1
},
{
"blockID": 1,
"symbolIndex": -1
},
{
"blockID": 2,
"symbolIndex": -1
},
{
"blockID": 2,
"symbolIndex": -1
},
{
"blockID": 2,
"symbolIndex": -1
},
{
"blockID": 2,
"symbolIndex": -1
},
{
"blockID": 3,
"symbolIndex": -1
},
{
"blockID": 3,
"symbolIndex": -1
},
{
"blockID": 3,
"symbolIndex": -1
},
{
"blockID": 3,
"symbolIndex": -1
},
{
"blockID": 4,
"symbolIndex": -1
},
{
"blockID": 4,
"symbolIndex": -1
},
{
"blockID": 4,
"symbolIndex": -1
},
{
"blockID": 4,
"symbolIndex": -1
},
{
"blockID": 5,
"symbolIndex": -1
},
{
"blockID": 5,
"symbolIndex": -1
},
{
"blockID": 5,
"symbolIndex": -1
},
{
"blockID": 5,
"symbolIndex": -1
},
{
"blockID": 3,
"symbolIndex": -1
},
{
"blockID": 3,
"symbolIndex": -1
},
{
"blockID": 3,
"symbolIndex": -1
},
{
"blockID": 3,
"symbolIndex": -1
},
{
"blockID": 4,
"symbolIndex": -1
},
{
"blockID": 4,
"symbolIndex": -1
},
{
"blockID": 4,
"symbolIndex": -1
},
{
"blockID": 4,
"symbolIndex": -1
},
{
"blockID": 5,
"symbolIndex": -1
},
{
"blockID": 5,
"symbolIndex": -1
},
{
"blockID": 5,
"symbolIndex": -1
},
{
"blockID": 5,
"symbolIndex": -1
},
{
"blockID": 3,
"symbolIndex": -1
},
{
"blockID": 3,
"symbolIndex": -1
},
{
"blockID": 3,
"symbolIndex": -1
},
{
"blockID": 3,
"symbolIndex": -1
},
{
"blockID": 4,
"symbolIndex": -1
},
{
"blockID": 4,
"symbolIndex": -1
},
{
"blockID": 4,
"symbolIndex": -1
},
{
"blockID": 4,
"symbolIndex": -1
},
{
"blockID": 5,
"symbolIndex": -1
},
{
"blockID": 5,
"symbolIndex": -1
},
{
"blockID": 5,
"symbolIndex": -1
},
{
"blockID": 5,
"symbolIndex": -1
},
{
"blockID": 6,
"symbolIndex": -1
},
{
"blockID": 6,
"symbolIndex": -1
},
{
"blockID": 6,
"symbolIndex": -1
},
{
"blockID": 6,
"symbolIndex": -1
},
{
"blockID": 7,
"symbolIndex": -1
},
{
"blockID": 7,
"symbolIndex": -1
},
{
"blockID": 7,
"symbolIndex": -1
},
{
"blockID": 7,
"symbolIndex": -1
},
{
"blockID": 8,
"symbolIndex": -1
},
{
"blockID": 8,
"symbolIndex": -1
},
{
"blockID": 8,
"symbolIndex": -1
},
{
"blockID": 8,
"symbolIndex": -1
},
{
"blockID": 6,
"symbolIndex": -1
},
{
"blockID": 6,
"symbolIndex": -1
},
{
"blockID": 6,
"symbolIndex": -1
},
{
"blockID": 6,
"symbolIndex": -1
},
{
"blockID": 7,
"symbolIndex": -1
},
{
"blockID": 7,
"symbolIndex": -1
},
{
"blockID": 7,
"symbolIndex": -1
},
{
"blockID": 7,
"symbolIndex": -1
},
{
"blockID": 8,
"symbolIndex": -1
},
{
"blockID": 8,
"symbolIndex": -1
},
{
"blockID": 8,
"symbolIndex": -1
},
{
"blockID": 8,
"symbolIndex": -1
},
{
"blockID": 6,
"symbolIndex": -1
},
{
"blockID": 6,
"symbolIndex": -1
},
{
"blockID": 6,
"symbolIndex": -1
},
{
"blockID": 6,
"symbolIndex": -1
},
{
"blockID": 7,
"symbolIndex": -1
},
{
"blockID": 7,
"symbolIndex": -1
},
{
"blockID": 7,
"symbolIndex": -1
},
{
"blockID": 7,
"symbolIndex": -1
},
{
"blockID": 8,
"symbolIndex": -1
},
{
"blockID": 8,
"symbolIndex": -1
},
{
"blockID": 8,
"symbolIndex": -1
},
{
"blockID": 8,
"symbolIndex": -1
},
{
"blockID": 9,
"symbolIndex": -1
},
{
"blockID": 9,
"symbolIndex": -1
},
{
"blockID": 9,
"symbolIndex": -1
},
{
"blockID": 9,
"symbolIndex": -1
},
{
"blockID": 10,
"symbolIndex": -1
},
{
"blockID": 10,
"symbolIndex": -1
},
{
"blockID": 10,
"symbolIndex": -1
},
{
"blockID": 10,
"symbolIndex": -1
},
{
"blockID": 11,
"symbolIndex": -1
},
{
"blockID": 11,
"symbolIndex": -1
},
{
"blockID": 11,
"symbolIndex": -1
},
{
"blockID": 11,
"symbolIndex": -1
},
{
"blockID": 9,
"symbolIndex": -1
},
{
"blockID": 9,
"symbolIndex": -1
},
{
"blockID": 9,
"symbolIndex": -1
},
{
"blockID": 9,
"symbolIndex": -1
},
{
"blockID": 10,
"symbolIndex": -1
},
{
"blockID": 10,
"symbolIndex": -1
},
{
"blockID": 10,
"symbolIndex": -1
},
{
"blockID": 10,
"symbolIndex": -1
},
{
"blockID": 11,
"symbolIndex": -1
},
{
"blockID": 11,
"symbolIndex": -1
},
{
"blockID": 11,
"symbolIndex": -1
},
{
"blockID": 11,
"symbolIndex": -1
},
{
"blockID": 9,
"symbolIndex": -1
},
{
"blockID": 9,
"symbolIndex": -1
},
{
"blockID": 9,
"symbolIndex": -1
},
{
"blockID": 9,
"symbolIndex": -1
},
{
"blockID": 10,
"symbolIndex": -1
},
{
"blockID": 10,
"symbolIndex": -1
},
{
"blockID": 10,
"symbolIndex": -1
},
{
"blockID": 10,
"symbolIndex": -1
},
{
"blockID": 11,
"symbolIndex": -1
},
{
"blockID": 11,
"symbolIndex": -1
},
{
"blockID": 11,
"symbolIndex": -1
},
{
"blockID": 11,
"symbolIndex": -1
}
],
"blocks": [
{"cellIDs": [
0,
1,
2,
3,
12,
13,
14,
15,
24,
25,
26,
27
]},
{"cellIDs": [
4,
5,
6,
7,
16,
17,
18,
19,
28,
29,
30,
31
]},
{"cellIDs": [
8,
9,
10,
11,
20,
21,
22,
23,
32,
33,
34,
35
]},
{"cellIDs": [
36,
37,
38,
39,
48,
49,
50,
51,
60,
61,
62,
63
]},
{"cellIDs": [
40,
41,
42,
43,
52,
53,
54,
55,
64,
65,
66,
67
]},
{"cellIDs": [
44,
45,
46,
47,
56,
57,
58,
59,
68,
69,
70,
71
]},
{"cellIDs": [
72,
73,
74,
75,
84,
85,
86,
87,
96,
97,
98,
99
]},
{"cellIDs": [
76,
77,
78,
79,
88,
89,
90,
91,
100,
101,
102,
103
]},
{"cellIDs": [
80,
81,
82,
83,
92,
93,
94,
95,
104,
105,
106,
107
]},
{"cellIDs": [
108,
109,
110,
111,
120,
121,
122,
123,
132,
133,
134,
135
]},
{"cellIDs": [
112,
113,
114,
115,
124,
125,
126,
127,
136,
137,
138,
139
]},
{"cellIDs": [
116,
117,
118,
119,
128,
129,
130,
131,
140,
141,
142,
143
]}
],
"multidoku": [{
"blockWidth": 4,
"cells": [
0,
1,
2,
3,
4,
5,
6,
7,
8,
9,
10,
11,
12,
13,
14,
15,
16,
17,
18,
19,
20,
21,
22,
23,
24,
25,
26,
27,
28,
29,
30,
31,
32,
33,
34,
35,
36,
37,
38,
39,
40,
41,
42,
43,
44,
45,
46,
47,
48,
49,
50,
51,
52,
53,
54,
55,
56,
57,
58,
59,
60,
61,
62,
63,
64,
65,
66,
67,
68,
69,
70,
71,
72,
73,
74,
75,
76,
77,
78,
79,
80,
81,
82,
83,
84,
85,
86,
87,
88,
89,
90,
91,
92,
93,
94,
95,
96,
97,
98,
99,
100,
101,
102,
103,
104,
105,
106,
107,
108,
109,
110,
111,
112,
113,
114,
115,
116,
117,
118,
119,
120,
121,
122,
123,
124,
125,
126,
127,
128,
129,
130,
131,
132,
133,
134,
135,
136,
137,
138,
139,
140,
141,
142,
143
],
"blocks": [
0,
1,
2,
3,
4,
5,
6,
7,
8,
9,
10,
11
]
}]
}

View File

@@ -3,10 +3,7 @@
*/ */
package sudoku; package sudoku;
import sudoku.io.SudokuPrinter; import sudoku.io.ConsoleInterface;
import sudoku.structure.SudokuFactory;
import java.util.Arrays;
public class Main { public class Main {
public String getGreeting() { public String getGreeting() {
@@ -14,33 +11,7 @@ public class Main {
} }
public static void main(String[] args) { public static void main(String[] args) {
System.out.println(new Main().getGreeting()); ConsoleInterface console = new ConsoleInterface();
console.start();
int blockWidth = 2;
int blockHeight = 2;
var multidoku = SudokuFactory.createBasicEmptyRectangleDoku(blockWidth, blockHeight,
SudokuFactory.DEFAULT_CONSTRAINTS);
var sudoku = multidoku.getSubGrid(0);
if (!sudoku.setCellsSymbol(Arrays.asList(0, 1, 2, 3, 2, 3, 1, 1, 1, 0, 3, 2, 3, 2, 1, 1))) {
System.out.println("At least one of those values does not respect the constraints.");
}
// sudoku.setCellSymbol(8,3,0);
SudokuPrinter.printRectangleSudoku(multidoku.getSubGrid(0), blockWidth, blockHeight);
/*
* Solver solver = new Solver();
* ArrayList<IConstraint> constraints = new ArrayList<>();
* constraints.add(new LineConstraint());
* constraints.add(new ColumnConstraint());
* constraints.add(new BlockConstraint());
* try {
* solver.solve(multidoku, constraints);
* } catch (Exception e) {
* System.out.println(e);
* }
*/
} }
} }

View File

@@ -0,0 +1,139 @@
package sudoku.io;
import sudoku.constraint.*;
import sudoku.solver.Solver;
import sudoku.structure.Difficulty;
import sudoku.structure.MultiDoku;
import sudoku.structure.Sudoku;
import sudoku.structure.SudokuFactory;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.Scanner;
public class ConsoleInterface {
public Scanner reader = new Scanner(System.in);
public void start(){
welcome();
System.out.println("First of all, you need to tell me the size of the sudoku you want to generate.");
int width = getBlockWidth();
int height = getBlockHeight();
System.out.println("Your sudoku will have blocks of a " + width + " x " + height + " format.");
int numberOfSymbols = width * height;
System.out.println("Would you like to pick the " + numberOfSymbols + " symbols from the sudoku? (y/n, default 'no' will use numbers)" );
List<String> listSymbols = new ArrayList<>();
if(reader.next().equalsIgnoreCase("y")){
pickSymbols(listSymbols, numberOfSymbols);
}
else {
// TODO
System.out.println("Simon doit finir sa partie.");
assert false;
}
List<Constraint> listConstraints = getListConstraints();
System.out.println("Now that we have the size of our sudoku, would you rather have a single grid ('one', default), " +
"or a a multidoku composed of 5 subgrids ('multi') ?");
List<Sudoku> subGrids = new ArrayList<>();
MultiDoku doku;
if (reader.next().equalsIgnoreCase("multi")) {
doku = SudokuFactory.createBasicEmptyRectangleDoku(width, height, listConstraints);
}
else {
doku = SudokuFactory.createBasicXShapedMultidoku(width, height, listConstraints);
}
System.out.println("Your sudoku will look like this:");
// TODO printMultiDoku method not yet implemented
SudokuPrinter.printMultiDoku(doku, width, height);
System.out.println("We now will fill this sudoku.");
System.out.println("What level of difficulty would you like? ('very easy', 'easy', 'medium' (default), 'hard', 'full' (sudoku fully completed))");
String difficulty = reader.next().toLowerCase();
if (difficulty.equals("full")) {
generateFullDoku(doku);
}
else {
generatePartialDoku(doku, difficulty);
}
System.out.println("Here's your sudoku !");
SudokuPrinter.printMultiDoku(doku, width, height);
}
public void welcome(){
System.out.println("Welcome to our Sudoku Solver!");
System.out.println("This is the project of Melvyn Bauvent, Lilas Grenier and Simon Priblyski.");
}
public int getBlockWidth() {
System.out.println("Width of a block: ");
int widthBlock = reader.nextInt();
checkValidSize(widthBlock);
while (!checkValidSize(widthBlock)) {
System.out.println("That is not a valid width for a block. Try again:");
widthBlock = reader.nextInt();
}
System.out.println("You have chose a width of " + widthBlock + ".");
return widthBlock;
}
public int getBlockHeight() {
System.out.println("Height of a block: ");
int heightBlock = reader.nextInt();
checkValidSize(heightBlock);
while (!checkValidSize(heightBlock)) {
System.out.println("That is not a valid height for a block. Try again:");
heightBlock = reader.nextInt();
}
System.out.println("You have chose a height of " + heightBlock + ".");
return heightBlock;
}
private Boolean checkValidSize(int size) {
return (size > 0);
}
private void pickSymbols(List<String> listSymbols, int numberOfSymbols) {
System.out.println("You have chosen to pick your own symbols.");
for (int i = 0; i < numberOfSymbols; i++) {
System.out.println("Choose for the symbol number " + i + ": ");
String newSymbol = reader.next();
while (listSymbols.contains(newSymbol)) {
System.out.println("This symbol has already been given. Try again:");
newSymbol = reader.next();
}
listSymbols.add(newSymbol);
}
System.out.println("You chose the symbols: " + listSymbols.toString());
}
private List<Constraint> getListConstraints() {
List<Constraint> listConstraints = SudokuFactory.DEFAULT_CONSTRAINTS;
System.out.println("The sudoku have constraints of blocks, lines and columns. Would you like to add the diagonal constraints ? (y/n, default 'no')");
if(reader.next().equalsIgnoreCase("y")){
listConstraints.add(Constraint.Diagonal);
}
return listConstraints;
}
private void generatePartialDoku(MultiDoku doku, String difficultyName) {
Difficulty difficulty;
switch (difficultyName){
case "very easy": difficulty = Difficulty.VeryEasy;
case "easy": difficulty = Difficulty.Easy;
case "hard": difficulty = Difficulty.Hard;
default: difficulty = Difficulty.Medium;
}
try {
SudokuFactory.fillDoku(doku, difficulty);
} catch (Exception e) {
System.out.println("There seems to be a problem with those settings. Let's start again.");
}
}
private void generateFullDoku(MultiDoku doku) {
Solver.solveRandom(doku, new Random());
}
}

View File

@@ -1,5 +1,6 @@
package sudoku.io; package sudoku.io;
import sudoku.structure.MultiDoku;
import sudoku.structure.Sudoku; import sudoku.structure.Sudoku;
public class SudokuPrinter { public class SudokuPrinter {
@@ -43,4 +44,8 @@ public class SudokuPrinter {
} }
return result.toString(); return result.toString();
} }
public static void printMultiDoku(final MultiDoku doku, int blockWidth, int blockHeight){
// TODO
}
} }

View File

@@ -246,6 +246,38 @@ public class SudokuFactory {
return new MultiDoku(Arrays.asList(sudoku1, sudoku2, sudoku3, sudoku4, sudoku5)); return new MultiDoku(Arrays.asList(sudoku1, sudoku2, sudoku3, sudoku4, sudoku5));
} }
/**
* Créée un MultiDoku de Blocks rectangulaires de forme width par height composé de cinq Sudokus,
* dont un central qui partage chacun de ses Blocks d'angle avec un autre
* Sudoku.
*
* @param width int, largeur des Blocks unitraires des Sudokus à crééer.
* @param height int, hauteur des Blocks unitraires des Sudokus à crééer.
* @return MultiDoku, MultiDoku de forme X.
*/
public static MultiDoku createBasicXShapedMultidoku(int width, int height, List<Constraint> constraints) {
assert (width > 1 && height > 1);
/*
* 2 3
* 1
* 4 5
*/
Sudoku sudoku1 = createRectangleSudoku(width, height, constraints);
Sudoku sudoku2 = createRectangleSudoku(width, height, constraints);
Sudoku sudoku3 = createRectangleSudoku(width, height, constraints);
Sudoku sudoku4 = createRectangleSudoku(width, height, constraints);
Sudoku sudoku5 = createRectangleSudoku(width, height, constraints);
linkSquareSudokus(sudoku1, sudoku2, new Coordinate(1 - width, 1 - height));
linkSquareSudokus(sudoku1, sudoku3, new Coordinate(width - 1, 1 - height));
linkSquareSudokus(sudoku1, sudoku4, new Coordinate(1 - width, height - 1));
linkSquareSudokus(sudoku1, sudoku5, new Coordinate(width - 1, height - 1));
return new MultiDoku(Arrays.asList(sudoku1, sudoku2, sudoku3, sudoku4, sudoku5));
}
public static void fillDoku(MultiDoku doku, Difficulty difficulty) throws Exception { public static void fillDoku(MultiDoku doku, Difficulty difficulty) throws Exception {
Solver.solveRandom(doku, random); Solver.solveRandom(doku, random);
int nbCellsToEmpty = (int) (difficulty.getFactor() * doku.getNbCells()); int nbCellsToEmpty = (int) (difficulty.getFactor() * doku.getNbCells());

View File

@@ -7,22 +7,25 @@ import org.json.JSONObject;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import sudoku.io.SudokuSerializer; import sudoku.io.SudokuSerializer;
import sudoku.solver.Solver;
import sudoku.structure.MultiDoku; import sudoku.structure.MultiDoku;
import sudoku.structure.SudokuFactory; import sudoku.structure.SudokuFactory;
public class SudokuSerializerTest { public class SudokuSerializerTest {
void testSerializeWithSize(int blockWidth, int blockHeight) { void testSerializeWithSize(int blockWidth, int blockHeight, Random r) {
var sudoku = SudokuFactory.createBasicEmptyRectangleDoku(blockWidth, blockHeight, MultiDoku sudoku = SudokuFactory.createBasicEmptyRectangleDoku(blockWidth, blockHeight,
SudokuFactory.DEFAULT_CONSTRAINTS); SudokuFactory.DEFAULT_CONSTRAINTS);
Solver.solveRandom(sudoku, r);
JSONObject data = SudokuSerializer.serializeSudoku(sudoku); JSONObject data = SudokuSerializer.serializeSudoku(sudoku);
MultiDoku multiDoku = SudokuSerializer.deserializeSudoku(data); MultiDoku multiDoku = SudokuSerializer.deserializeSudoku(data);
assert (data.toString().equals(SudokuSerializer.serializeSudoku(multiDoku).toString())); assert (data.toString().equals(SudokuSerializer.serializeSudoku(multiDoku).toString()));
} }
void testSaveWithSize(int blockWidth, int blockHeight) { void testSaveWithSize(int blockWidth, int blockHeight, Random r) {
MultiDoku doku = SudokuFactory.createBasicEmptyRectangleDoku(blockWidth, blockHeight, MultiDoku doku = SudokuFactory.createBasicEmptyRectangleDoku(blockWidth, blockHeight,
SudokuFactory.DEFAULT_CONSTRAINTS); SudokuFactory.DEFAULT_CONSTRAINTS);
Solver.solveRandom(doku, r);
String savePath = SudokuSerializer.saveMultiDoku(doku); String savePath = SudokuSerializer.saveMultiDoku(doku);
MultiDoku otherDoku = null; MultiDoku otherDoku = null;
try { try {
@@ -41,17 +44,21 @@ public class SudokuSerializerTest {
@Test @Test
void testSerialize() { void testSerialize() {
Random r = new Random(); Random r = new Random();
testSerializeWithSize(3, 3, r);
/**
int testCount = 5; int testCount = 5;
for (int i = 0; i < testCount; i++) { for (int i = 0; i < testCount; i++) {
int blockWidth = r.nextInt(10) + 1; int blockWidth = r.nextInt(10) + 1;
int blockHeight = r.nextInt(10) + 1; int blockHeight = r.nextInt(10) + 1;
testSerializeWithSize(blockWidth, blockHeight); testSerializeWithSize(blockWidth, blockHeight, r);
} }
for (int i = 0; i < testCount; i++) { for (int i = 0; i < testCount; i++) {
int blockWidth = r.nextInt(10) + 1; int blockWidth = r.nextInt(10) + 1;
int blockHeight = r.nextInt(10) + 1; int blockHeight = r.nextInt(10) + 1;
testSaveWithSize(blockWidth, blockHeight); testSaveWithSize(blockWidth, blockHeight, r);
} }
*/
} }
} }