diff --git a/.gitignore b/.gitignore index 2054c98..cb290e3 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,2 @@ *.class -*.jar -saves/*.yaml \ No newline at end of file +*.jar \ No newline at end of file diff --git a/AppLaser.java b/AppLaser.java index 4e0e775..4ef30f9 100644 --- a/AppLaser.java +++ b/AppLaser.java @@ -1,198 +1,323 @@ // Antoine CRETUAL, Lukian LEIZOUR, 14/02/2024 import java.util.Scanner; +import java.time.Instant; +import java.io.FileReader; +import java.io.BufferedReader; +import java.io.File; +import java.util.Set; +import java.util.stream.Stream; +import java.util.stream.Collectors; + +import userInterface.UserInterface; +import universe.Universe; +import universe.Stack; +import universe.Situation; public class AppLaser { - public static void main(String [] args) { + public static void main(String [] args) { - boolean cli = false; + boolean cli = false, optimize_duration = false; - for (int i = 0; i < args.length; i++) { - switch (args[i]) { - case "-cli": - cli = true; - break; + for (int i = 0; i < args.length; i++) { + switch (args[i]) { + case "-cli": + cli = true; + break; - default: - System.out.println("Unknown argument " + args[i]); - System.exit(0); - } - } + case "--optimize-duration": + optimize_duration = true; + break; - int universe_width = 3; - int universe_height = 3; - int start_i = 0; - int start_j = 0; - int start_dir = 11; - int firstState_i = start_i; - int firstState_j = start_j; + default: + System.out.println("Unknown argument " + args[i]); + System.exit(0); + } + } - if (start_dir == 10) firstState_i = start_i - 1; - else if (start_dir == 11) firstState_i = start_i + 1; - else if (start_dir == 12) firstState_j = start_j + 1; - else if (start_dir == 13) firstState_j = start_j - 1; + int universe_width = 3; + int universe_height = 3; + int start_i = 0; + int start_j = 0; + int start_dir = 11; + int firstState_i = start_i; + int firstState_j = start_j; - if (cli == true) { + if (start_dir == 10) firstState_i = start_i - 1; + else if (start_dir == 11) firstState_i = start_i + 1; + else if (start_dir == 12) firstState_j = start_j + 1; + else if (start_dir == 13) firstState_j = start_j - 1; - Stack stack = new Stack (); - Universe universe = new Universe(universe_width + 2, universe_height + 2, start_i + 1, start_j + 1, start_dir); - Situation currentState = new Situation(firstState_i + 1, firstState_j + 1, start_dir, 0); + if (cli == true) { + Stack stack = new Stack (); + Universe universe = new Universe(universe_width + 2, universe_height + 2, start_i + 1, start_j + 1, start_dir); + Situation currentState = new Situation(firstState_i + 1, firstState_j + 1, start_dir, 0); + Scanner scanner = new Scanner(System.in); - Scanner scanner = new Scanner(System.in); + int choice; - int choice; + do { + // clear screen - do { - // clear screen + System.out.print("\033[H\033[2J"); + System.out.flush(); + System.out.print("\033[?25h"); - System.out.print("\033[H\033[2J"); - System.out.flush(); - System.out.print("\033[?25h"); + // print the universe - // print the universe + Universe.print(universe.getGrid(), universe_width + 2, universe_height + 2, 2, 4); - universe.print(2, 4); + // print the menu - // print the menu + System.out.println("\n1 - Resize universe"); + System.out.println("2 - Change start position"); + System.out.println("3 - Add obstacle"); + System.out.println("4 - Reset universe"); + System.out.println("5 - Reset obstacles"); + System.out.println("6 - Save universe"); + System.out.println("7 - Load universe"); + System.out.println("8 - Resolve"); + System.out.println("0 - Exit"); - System.out.println("\n1 - Resize universe"); - System.out.println("2 - Change start position"); - System.out.println("3 - Add obstacle"); - System.out.println("4 - Resolve"); - System.out.println("0 - Exit"); + // prompt the user - // prompt the user + System.out.print("\nChoice : "); + choice = scanner.nextInt(); - System.out.print("\nChoice : "); - choice = scanner.nextInt(); + switch (choice) { - switch (choice) { + case 1: + System.out.print("Enter the width of the universe : "); + universe_width = scanner.nextInt(); + System.out.print("Enter the length of the universe : "); + universe_height = scanner.nextInt(); - case 1: - System.out.print("Enter the width of the universe : "); - universe_width = scanner.nextInt(); - System.out.print("Enter the length of the universe : "); - universe_height = scanner.nextInt(); + universe.changeUniverseDim(universe_width + 2, universe_height + 2); - universe.changeUniverseDim(universe_width + 2, universe_height + 2); + break; - break; + case 2: + System.out.print("Enter the position of the start point in the first axis : "); + start_i = scanner.nextInt(); + System.out.print("Enter the position of the start point in the seccond axis : "); + start_j = scanner.nextInt(); + System.out.print("Enter the direction of the start point : "); + start_dir = scanner.nextInt(); - case 2: - System.out.print("Enter the position of the start point in the first axis : "); - start_i = scanner.nextInt() + 1; - System.out.print("Enter the position of the start point in the seccond axis : "); - start_j = scanner.nextInt() + 1; - System.out.print("Enter the direction of the start point : "); - start_dir = scanner.nextInt(); + firstState_i = start_i; + firstState_j = start_j; - firstState_i = start_i; - firstState_j = start_j; + if (start_dir == 10) firstState_i = start_i - 1; + else if (start_dir == 11) firstState_i = start_i + 1; + else if (start_dir == 12) firstState_j = start_j + 1; + else if (start_dir == 13) firstState_j = start_j - 1; - if (start_dir == 10) firstState_i = start_i - 1; - else if (start_dir == 11) firstState_i = start_i + 1; - else if (start_dir == 12) firstState_j = start_j + 1; - else if (start_dir == 13) firstState_j = start_j - 1; + currentState = new Situation(firstState_i + 1, firstState_j + 1, start_dir, 0); - currentState = new Situation(firstState_i + 1, firstState_j + 1, start_dir, 0); + universe.changeUniverseStart(start_i + 1, start_j + 1, start_dir); - universe.changeUniverseStart(start_i, start_j, start_dir); + break; - break; + case 3: + int firstPos_i, firstPos_j, seccondPos_i, seccondPos_j; - case 3: - int firstPos_i, firstPos_j, seccondPos_i, seccondPos_j; + System.out.print("\nFirst position of the obstacle i : "); + firstPos_i = scanner.nextInt(); + System.out.print("First position of the obstacle j : "); + firstPos_j = scanner.nextInt(); + System.out.print("Seccond position of the obstacle i : "); + seccondPos_i = scanner.nextInt(); + System.out.print("Seccond position of the obstacle j : "); + seccondPos_j = scanner.nextInt(); - System.out.print("\nFirst position of the obstacle i : "); - firstPos_i = scanner.nextInt(); - System.out.print("First position of the obstacle j : "); - firstPos_j = scanner.nextInt(); - System.out.print("Seccond position of the obstacle i : "); - seccondPos_i = scanner.nextInt(); - System.out.print("Seccond position of the obstacle j : "); - seccondPos_j = scanner.nextInt(); + for (int i = firstPos_i + 1; i < seccondPos_i + 2; i++) { + for (int j = firstPos_j + 1; j < seccondPos_j + 2; j++) { + universe.addObstacle(i, j); + } + } - for (int i = firstPos_i + 1; i < seccondPos_i + 2; i++) { - for (int j = firstPos_j + 1; j < seccondPos_j + 2; j++) { - universe.addObstacle(i, j); - } - } + break; - break; + case 4: + universe.resetUniverse(); - case 4: - boolean display_progress = false, display_regress = false; + break; - System.out.println("\n1 - display progress and regress"); - System.out.println("2 - display progress"); - System.out.println("3 - display regress"); - System.out.println("4 - display nothing"); - System.out.print("\nChoice : "); - choice = scanner.nextInt(); + case 5: + universe.resetUniverseObstacles(); - switch (choice) { - case 1: - display_progress = true; - display_regress = true; - break; + break; - case 2: - display_progress = true; - break; - case 3: - display_regress = true; - break; + case 6: + System.out.print("\nHow do you want to name your universe : "); + String name = ""; - case 4: - break; + while (name.isEmpty()) { + name = scanner.nextLine(); + } - default: - break; - } + universe.save(name); - System.out.print("\033[?25l"); - System.out.print("\033[H\033[2J"); - System.out.flush(); + break; - universe.resetUniverse(); + case 7: - universe.print(2, 4); + Set files = Stream.of(new File("./saves").listFiles()).filter(file -> !file.isDirectory()).map(File::getName).collect(Collectors.toSet()); - while (!universe.isSolved()) { - if (universe.canEvolve(currentState)) { - stack.push(currentState.copy(universe.possibleChoices(currentState))); - currentState = universe.evolve(currentState); + System.out.println("\nAvailable files : \n"); - if (display_progress == true) universe.print(universe_height + 6, 4); - } - else if (stack.size() > 0) { - currentState = stack.pop(); - universe.reset(currentState); + for (String element : files) { + System.out.println(element.replace(".txt", "")); + } - if (display_regress == true) universe.print(universe_height + 6, 4); - } else { - break; - } - } + System.out.print("\nWhat universe do you want load ? : "); + String name2 = ""; - System.out.println("\n\n"); - universe.print(universe_height + 6, 4); + while (name2.isEmpty()) { + name2 = scanner.nextLine(); + } - System.out.print("\033[?25h"); - System.out.print("\nEnter anything to continue...."); - scanner.nextInt(); + try { + BufferedReader reader = new BufferedReader(new FileReader("./saves/" + name2 + ".txt")); + universe_height = Integer.valueOf(reader.readLine()); + universe_width = Integer.valueOf(reader.readLine()); + start_dir = Integer.valueOf(reader.readLine()); + start_i = Integer.valueOf(reader.readLine()); + start_j = Integer.valueOf(reader.readLine()); - break; - default: - break; + universe.changeUniverseDim(universe_width + 2, universe_height + 2); - } - } while (choice != 0); - } - else { - System.out.println("there is no GUI yet."); - } - } + firstState_i = start_i; + firstState_j = start_j; + + if (start_dir == 10) firstState_i = start_i - 1; + else if (start_dir == 11) firstState_i = start_i + 1; + else if (start_dir == 12) firstState_j = start_j + 1; + else if (start_dir == 13) firstState_j = start_j - 1; + + currentState = new Situation(firstState_i, firstState_j, start_dir, 0); + + universe.changeUniverseStart(start_i, start_j, start_dir); + + while (true) { + try { + int pos1 = Integer.valueOf(reader.readLine()); + int pos2 = Integer.valueOf(reader.readLine()); + + universe.addObstacle(pos1, pos2); + } + catch (Exception e) { + break; + } + } + } + catch (Exception e) {} + + break; + + + case 8: + boolean display_progress = false, display_regress = false; + + System.out.println("\n1 - display progress and regress"); + System.out.println("2 - display progress"); + System.out.println("3 - display regress"); + System.out.println("4 - display nothing"); + System.out.print("\nChoice : "); + choice = scanner.nextInt(); + + switch (choice) { + case 1: + display_progress = true; + display_regress = true; + break; + + case 2: + display_progress = true; + break; + + case 3: + display_regress = true; + break; + + case 4: + break; + + default: + break; + } + + System.out.print("\033[?25l"); + System.out.print("\033[H\033[2J"); + System.out.flush(); + + universe.resetUniverse(); + + Universe.print(universe.getGrid(), universe_width + 2, universe_height + 2, 2, 4); + + int start_time = (int) Instant.now().getEpochSecond(); + + int [][] bestGrid = universe.copyGrid(); + int best_filled_boxes = 0; + int best_nb_mirrors = 0; + + do { + if (universe.canEvolve(currentState)) { + stack.push(currentState.copy(universe.possibleChoices(currentState))); + currentState = universe.evolve(currentState); + + if (display_progress == true) Universe.print(universe.getGrid(), universe_width + 2, universe_height + 2, universe_height + 6, 4); + + if ((universe.getFilledBoxes() > best_filled_boxes) || (universe.getFilledBoxes() == best_filled_boxes && universe.getNbMirrors() < best_nb_mirrors)) { + bestGrid = universe.copyGrid(); + best_filled_boxes = universe.getFilledBoxes(); + best_nb_mirrors = universe.getNbMirrors(); + + Universe.print(bestGrid, universe_width + 2, universe_height + 2, 2, 2 * universe_width + 10); + System.out.println("Miroirs: " + best_nb_mirrors + " Cases: " + best_filled_boxes); + } + } + else if (stack.size() > 0) { + currentState = stack.pop(); + universe.reset(currentState); + + if (display_regress == true) Universe.print(universe.getGrid(), universe_width + 2, universe_height + 2, universe_height + 6, 4); + } else { + break; + } + + if ((int) Instant.now().getEpochSecond() - start_time > 60 && optimize_duration == true) { + display_progress = false; + } + if ((int) Instant.now().getEpochSecond() - start_time > 2 * 60 && optimize_duration == true) { + display_regress = false; + } + } while (stack.size() != 0); + + System.out.println("\n\n"); + + Universe.print(bestGrid, universe_width + 2, universe_height + 2, universe_height + 6, 4); + + System.out.println("\nSolved in " + ((int) Instant.now().getEpochSecond() - start_time) + " secconds"); + + System.out.print("\033[?25h"); + System.out.print("\nEnter anything to continue...."); + scanner.nextInt(); + + break; + + default: + break; + + } + } while (choice != 0); + } + else { + Universe universe = new Universe(universe_width + 2, universe_height + 2, start_i + 1, start_j + 1, start_dir); + UserInterface userInterface = new UserInterface(universe); + userInterface.start(); + } + } } diff --git a/Universe.java b/Universe.java deleted file mode 100644 index 967330b..0000000 --- a/Universe.java +++ /dev/null @@ -1,322 +0,0 @@ -// Antoine CRETUAL, Lukian LEIZOUR, 14/02/2024 - -public class Universe { - // Atributes - - private int[][] grid; - private int width, height; - private int boxes_to_fill; - - // Constructors - - public Universe(int width, int height, int i_start, int j_start, int dir_start) { - this.grid = new int[height][width]; - this.height = height; - this.width = width; - this.boxes_to_fill = (width - 2) * (height - 2) - 1; - - int i, j; - for (i = 1; i < this.height - 1; i++) { - for (j = 1; j < this.width - 1; j++) { - this.grid[i][j] = 0; - } - } - - for (i = 0; i < this.height; i++) { - this.grid[i][0] = -1; - this.grid[i][width - 1] = -1; - } - - for (j = 0; j < this.width; j++) { - this.grid[0][j] = -1; - this.grid[height - 1][j] = -1; - } - - this.grid[i_start][j_start] = dir_start; - } - - // Methods - - public void print(int pos_i, int pos_j) { - int i, j; - for (i = 0; i < this.height; i++) { - for (j = 0; j < this.width; j++) { - System.out.print("\033[" + (i + pos_i) + ";" + (j*2 + pos_j) + "H"); - switch (this.grid[i][j]) { - case -1: - System.out.printf(" X"); - break; - - case 0: - System.out.printf(" "); - break; - - case 1: - System.out.printf(" |"); - break; - - case 2: - System.out.printf(" -"); - break; - - case 3: - System.out.printf(" +"); - break; - - case 4: - System.out.printf(" /"); - break; - - case 5: - System.out.printf(" \\"); - break; - - case 10: - System.out.printf(" ^"); - break; - - case 11: - System.out.printf(" v"); - break; - - case 12: - System.out.printf(" >"); - break; - - case 13: - System.out.printf(" <"); - break; - - default: - System.out.printf("%2d", this.grid[i][j]); - } - } - System.out.print("\n"); - } - } - - public void resetUniverse() { - for (int i = 1; i < this.height - 1; i++) { - for (int j = 1; j < this.width - 1; j++) { - if (this.grid[i][j] != 10 && this.grid[i][j] != 11 && this.grid[i][j] != 12 && this.grid[i][j] != 13 && this.grid[i][j] != 0 && this.grid[i][j] != -1) { - this.grid[i][j] = 0; - } - } - } - } - - public void changeUniverseDim(int width, int height) { - int [][] newgrid = new int[width][height]; - - for (int i = 1; i < height - 1; i++) { - for (int j = 1; j < width - 1; j++) { - newgrid[i][j] = 0; - } - } - - for (int i = 1; i < height - 1 && i < this.height - 1; i++) { - for (int j = 1; j < width - 1 && j < this.width - 1; j++) { - newgrid[i][j] = this.grid[i][j]; - } - } - - for (int i = 0; i < height; i++) { - newgrid[i][0] = -1; - newgrid[i][width - 1] = -1; - } - - for (int j = 0; j < width; j++) { - newgrid[height - 1][j] = -1; - newgrid[0][j] = -1; - } - - this.grid = newgrid; - this.width = width; - this.height = height; - } - - public void changeUniverseStart(int pos_i, int pos_j, int dir) { - for (int i = 0; i < this.height; i++) { - for (int j = 0; j < this.width; j++) { - if (this.grid[i][j] == 10 || this.grid[i][j] == 11 || this.grid[i][j] == 12|| this.grid[i][j] == 13) { - this.grid[i][j] = 0; - } - } - } - - this.grid[pos_i][pos_j] = dir; - } - - public void addObstacle(int pos_i, int pos_j) { - if (this.grid[pos_i][pos_j] == 0) { - this.grid[pos_i][pos_j] = -1; - this.boxes_to_fill--; - } - else {} - } - - public int possibleChoices(Situation s) { - int i = s.pos_i; - int j = s.pos_j; - int d = s.direction; - int c = s.nb_choix; - - switch (c) { - case 0: { - switch (d) { - case 10: // north - if (this.grid[i - 1][j] == 0 || this.grid[i - 1][j] == 2) return 1; // front - else if (this.grid[i][j - 1] == 0 && this.grid[i][j] == 0) return 2; // left - else if (this.grid[i][j + 1] == 0 && this.grid[i][j] == 0) return 3; // right - else return -1; // back - - case 11: // south - if (this.grid[i + 1][j] == 0 || this.grid[i + 1][j] == 2) return 1; // front - else if (this.grid[i][j + 1] == 0 && this.grid[i][j] == 0) return 2; // left - else if (this.grid[i][j - 1] == 0 && this.grid[i][j] == 0) return 3; // right - else return -1; // back - - case 12: // east - if (this.grid[i][j + 1] == 0 || this.grid[i][j + 1] == 1) return 1; // front - else if (this.grid[i - 1][j] == 0 && this.grid[i][j] == 0) return 2; // left - else if (this.grid[i + 1][j] == 0 && this.grid[i][j] == 0) return 3; // right - else return -1; // back - - case 13: //west - if (this.grid[i][j - 1] == 0 || this.grid[i][j - 1] == 1) return 1; // front - else if (this.grid[i + 1][j] == 0 && this.grid[i][j] == 0) return 2; // left - else if (this.grid[i - 1][j] == 0 && this.grid[i][j] == 0) return 3; // right - else return -1; // back - - default: {} - } - } - case 1: { - switch (d) { - case 10: // north - if (this.grid[i][j - 1] == 0 && this.grid[i][j] == 0) return 2; // left - else if (this.grid[i][j + 1] == 0 && this.grid[i][j] == 0) return 3; // right - else return -1; // back - - case 11: // south - if (this.grid[i][j + 1] == 0 && this.grid[i][j] == 0) return 2; // left - else if (this.grid[i][j - 1] == 0 && this.grid[i][j] == 0) return 3; // right - else return -1; // back - - case 12: // east - if (this.grid[i - 1][j] == 0 && this.grid[i][j] == 0) return 2; // left - else if (this.grid[i + 1][j] == 0 && this.grid[i][j] == 0) return 3; // right - else return -1; // back - - case 13: //west - if (this.grid[i + 1][j] == 0 && this.grid[i][j] == 0) return 2; // left - else if (this.grid[i - 1][j] == 0 && this.grid[i][j] == 0) return 3; // right - else return -1; // back - - default: {} - } - } - case 2: { - switch (d) { - case 10: // north - if (this.grid[i][j + 1] == 0 && this.grid[i][j] == 0) return 3; // right - else return -1; // back - - case 11: // south - if (this.grid[i][j - 1] == 0 && this.grid[i][j] == 0) return 3; // right - else return -1; // back - - case 12: // east - if (this.grid[i + 1][j] == 0 && this.grid[i][j] == 0) return 3; // right - else return -1; // back - - case 13: //west - if (this.grid[i - 1][j] == 0 && this.grid[i][j] == 0) return 3; // right - else return -1; // back - - default: {} - } - } - case 3: - return -1; - - default: return -1; - } - } - - public boolean canEvolve(Situation s) { - return possibleChoices(s) != -1; - } - - public Situation evolve(Situation s) { - int i = s.pos_i; - int j = s.pos_j; - int d = s.direction; - int c = possibleChoices(s); - - // new status of the box - - if (c == 1 && (d == 10 || d == 11)) { - if (this.grid[i][j] == 0) { - this.grid[i][j] = 1; - } else { - this.grid[i][j] = 3; - this.boxes_to_fill++; - } - } - if (c == 1 && (d == 12 || d == 13)) { - if (this.grid[i][j] == 0) { - this.grid[i][j] = 2; - } else { - this.grid[i][j] = 3; - this.boxes_to_fill++; - } - } - if ((c == 3 && d == 10) || (c == 3 && d == 11) || (c == 2 && d == 12) || (c == 2 && d == 13)) this.grid[i][j] = 4; - if ((c == 2 && d == 10) || (c == 2 && d == 11) || (c == 3 && d == 12) || (c == 3 && d == 13)) this.grid[i][j] = 5; - - // changing the position of the situation - - if (c == 1 && d == 10 || c == 2 && d == 12 || c == 3 && d == 13) { - i --; - d = 10; - } - else if (c == 1 && d == 11 || c == 2 && d == 13 || c == 3 && d == 12) { - i ++; - d = 11; - } - else if (c == 1 && d == 12 || c == 2 && d == 11 || c == 3 && d == 10) { - j ++; - d = 12; - } - else if (c == 1 && d == 13 || c == 2 && d == 10 || c == 3 && d == 11) { - j --; - d = 13; - } - - this.boxes_to_fill--; - - return new Situation(i, j, d, 0); - } - - public void reset(Situation s) { - int i = s.pos_i; - int j = s.pos_j; - int d = s.direction; - - if (this.grid[i][j] == 3) { - if (d == 10 || d == 11) { - this.grid[i][j] = 2; - } else { - this.grid[i][j] = 1; - } - } else { - this.grid[s.pos_i][s.pos_j] = 0; - this.boxes_to_fill++; - } - } - - public boolean isSolved() { - return this.boxes_to_fill == 0; - } -} diff --git a/images/blade.png b/images/blade.png new file mode 100644 index 0000000..4ffe69a Binary files /dev/null and b/images/blade.png differ diff --git a/images/crossLaser.png b/images/crossLaser.png new file mode 100644 index 0000000..7a873b0 Binary files /dev/null and b/images/crossLaser.png differ diff --git a/images/horizontalLaser.png b/images/horizontalLaser.png new file mode 100644 index 0000000..b7a14ba Binary files /dev/null and b/images/horizontalLaser.png differ diff --git a/images/miror1.png b/images/miror1.png new file mode 100644 index 0000000..971e86a Binary files /dev/null and b/images/miror1.png differ diff --git a/images/miror2.png b/images/miror2.png new file mode 100644 index 0000000..2297314 Binary files /dev/null and b/images/miror2.png differ diff --git a/images/miror3.png b/images/miror3.png new file mode 100644 index 0000000..7ee3d2c Binary files /dev/null and b/images/miror3.png differ diff --git a/images/miror4.png b/images/miror4.png new file mode 100644 index 0000000..f8eaf63 Binary files /dev/null and b/images/miror4.png differ diff --git a/images/new.png b/images/new.png new file mode 100644 index 0000000..4d78a59 Binary files /dev/null and b/images/new.png differ diff --git a/images/open.png b/images/open.png new file mode 100644 index 0000000..153e75b Binary files /dev/null and b/images/open.png differ diff --git a/images/save.png b/images/save.png new file mode 100644 index 0000000..0b6a949 Binary files /dev/null and b/images/save.png differ diff --git a/images/startBot.png b/images/startBot.png new file mode 100644 index 0000000..2273518 Binary files /dev/null and b/images/startBot.png differ diff --git a/images/startLeft.png b/images/startLeft.png new file mode 100644 index 0000000..1705cec Binary files /dev/null and b/images/startLeft.png differ diff --git a/images/startRight.png b/images/startRight.png new file mode 100644 index 0000000..dac5643 Binary files /dev/null and b/images/startRight.png differ diff --git a/images/startUp.png b/images/startUp.png new file mode 100644 index 0000000..a94f803 Binary files /dev/null and b/images/startUp.png differ diff --git a/images/verticalLaser.png b/images/verticalLaser.png new file mode 100644 index 0000000..b50d083 Binary files /dev/null and b/images/verticalLaser.png differ diff --git a/images/wall.png b/images/wall.png new file mode 100644 index 0000000..6b1825e Binary files /dev/null and b/images/wall.png differ diff --git a/makefile b/makefile index 1770321..61b95f6 100644 --- a/makefile +++ b/makefile @@ -1,7 +1,17 @@ build: + javac --source 1.8 --target 1.8 universe/*.java + javac --source 1.8 --target 1.8 userInterface/*.java javac --source 1.8 --target 1.8 AppLaser.java jar cfe AppLaser.jar AppLaser *.class run: + javac --source 1.8 --target 1.8 universe/*.java + javac --source 1.8 --target 1.8 userInterface/*.java javac --source 1.8 --target 1.8 AppLaser.java - java AppLaser -cli + java AppLaser -cli --optimize-duration + +run_gui: + javac --source 1.8 --target 1.8 universe/*.java + javac --source 1.8 --target 1.8 userInterface/*.java + javac --source 1.8 --target 1.8 AppLaser.java + java AppLaser diff --git a/saves/default.txt b/saves/default.txt new file mode 100644 index 0000000..0978dc6 --- /dev/null +++ b/saves/default.txt @@ -0,0 +1,5 @@ +3 +3 +11 +1 +1 diff --git a/saves/maze1.txt b/saves/maze1.txt new file mode 100644 index 0000000..fed829f --- /dev/null +++ b/saves/maze1.txt @@ -0,0 +1,187 @@ +10 +20 +11 +1 +1 +1 +2 +1 +6 +1 +10 +1 +14 +1 +18 +1 +20 +2 +2 +2 +4 +2 +6 +2 +8 +2 +10 +2 +12 +2 +14 +2 +16 +2 +18 +2 +20 +3 +2 +3 +4 +3 +6 +3 +8 +3 +10 +3 +12 +3 +14 +3 +16 +3 +18 +3 +20 +4 +2 +4 +4 +4 +6 +4 +8 +4 +10 +4 +12 +4 +14 +4 +16 +4 +18 +4 +20 +5 +2 +5 +4 +5 +6 +5 +8 +5 +10 +5 +12 +5 +14 +5 +16 +5 +18 +5 +20 +6 +2 +6 +4 +6 +6 +6 +8 +6 +10 +6 +12 +6 +14 +6 +16 +6 +18 +6 +20 +7 +2 +7 +4 +7 +6 +7 +8 +7 +10 +7 +12 +7 +14 +7 +16 +7 +18 +7 +20 +8 +2 +8 +4 +8 +6 +8 +8 +8 +10 +8 +12 +8 +14 +8 +16 +8 +18 +8 +20 +9 +2 +9 +4 +9 +6 +9 +8 +9 +10 +9 +12 +9 +14 +9 +16 +9 +18 +9 +20 +10 +4 +10 +8 +10 +12 +10 +16 +10 +20 diff --git a/saves/maze2.txt b/saves/maze2.txt new file mode 100644 index 0000000..50d3371 --- /dev/null +++ b/saves/maze2.txt @@ -0,0 +1,155 @@ +10 +20 +11 +1 +1 +1 +2 +1 +6 +1 +10 +1 +14 +1 +18 +1 +20 +2 +2 +2 +4 +2 +6 +2 +7 +2 +8 +2 +10 +2 +12 +2 +13 +2 +14 +2 +15 +2 +16 +2 +18 +2 +20 +3 +4 +3 +18 +4 +2 +4 +4 +4 +5 +4 +6 +4 +8 +4 +9 +4 +10 +4 +12 +4 +14 +4 +16 +4 +18 +4 +19 +4 +20 +5 +12 +5 +14 +6 +2 +6 +4 +6 +6 +6 +7 +6 +8 +6 +10 +6 +11 +6 +12 +6 +14 +6 +15 +6 +16 +6 +18 +6 +19 +6 +20 +7 +1 +7 +2 +8 +2 +8 +4 +8 +6 +8 +8 +8 +10 +8 +11 +8 +12 +8 +13 +8 +14 +8 +16 +8 +17 +8 +18 +8 +20 +9 +4 +9 +12 +9 +16 +9 +18 +10 +3 +10 +4 +10 +8 +10 +12 +10 +16 +10 +20 diff --git a/saves/prof.txt b/saves/prof.txt new file mode 100644 index 0000000..4022bef --- /dev/null +++ b/saves/prof.txt @@ -0,0 +1,83 @@ +13 +20 +10 +9 +1 +2 +6 +2 +9 +2 +10 +2 +13 +2 +14 +2 +15 +2 +16 +2 +17 +3 +3 +3 +4 +3 +5 +3 +6 +3 +9 +3 +10 +4 +19 +5 +19 +6 +3 +6 +4 +6 +5 +6 +8 +6 +9 +6 +11 +6 +14 +6 +15 +6 +16 +7 +3 +7 +8 +7 +14 +8 +3 +8 +8 +8 +14 +9 +3 +9 +8 +9 +9 +9 +12 +9 +13 +9 +14 +10 +3 +11 +3 diff --git a/saves/rightBlock.txt b/saves/rightBlock.txt new file mode 100644 index 0000000..beffdd4 --- /dev/null +++ b/saves/rightBlock.txt @@ -0,0 +1,29 @@ +10 +10 +10 +6 +1 +1 +8 +1 +9 +1 +10 +2 +8 +2 +9 +2 +10 +3 +8 +3 +9 +3 +10 +4 +8 +4 +9 +4 +10 diff --git a/saves/roux.txt b/saves/roux.txt new file mode 100644 index 0000000..bbfec18 --- /dev/null +++ b/saves/roux.txt @@ -0,0 +1,147 @@ +20 +13 +10 +20 +3 +1 +1 +2 +1 +2 +3 +2 +12 +3 +1 +3 +3 +3 +12 +4 +3 +4 +12 +5 +3 +5 +12 +6 +3 +6 +4 +6 +5 +6 +6 +6 +7 +6 +8 +6 +9 +6 +10 +6 +12 +7 +12 +8 +12 +9 +7 +9 +8 +9 +9 +9 +12 +10 +5 +10 +9 +10 +11 +10 +12 +11 +2 +11 +3 +11 +9 +12 +2 +13 +2 +14 +2 +14 +12 +15 +2 +15 +5 +15 +6 +15 +7 +15 +8 +15 +9 +15 +10 +15 +11 +15 +12 +16 +2 +16 +4 +16 +5 +16 +6 +16 +7 +16 +8 +16 +9 +16 +10 +16 +11 +16 +12 +17 +2 +18 +2 +18 +5 +18 +9 +18 +10 +18 +11 +18 +12 +19 +5 +19 +8 +19 +9 +19 +10 +19 +11 +19 +12 +20 +1 +20 +5 diff --git a/Situation.java b/universe/Situation.java similarity index 95% rename from Situation.java rename to universe/Situation.java index d456677..fb3fd9c 100644 --- a/Situation.java +++ b/universe/Situation.java @@ -1,5 +1,7 @@ // Antoine CRETUAL, Lukian LEIZOUR, 21/02/2024 +package universe; + public class Situation { // Atributes diff --git a/Stack.java b/universe/Stack.java similarity index 76% rename from Stack.java rename to universe/Stack.java index 84dde3c..464faec 100644 --- a/Stack.java +++ b/universe/Stack.java @@ -1,5 +1,7 @@ // Antoine CRETUAL, Lukian LEIZOUR, 21/02/2024 +package universe; + import java.util.Vector; public class Stack { @@ -13,6 +15,10 @@ public class Stack { array = new Vector(); } + public Stack(Vector array) { + array = array; + } + // Methods public void push(T x) { @@ -28,4 +34,8 @@ public class Stack { public int size() { return this.array.size(); } + + public Stack copy() { + return new Stack(new Vector(this.array)); + } } diff --git a/universe/Universe.java b/universe/Universe.java new file mode 100644 index 0000000..3fb6dd6 --- /dev/null +++ b/universe/Universe.java @@ -0,0 +1,431 @@ +// Antoine CRETUAL, Lukian LEIZOUR, 14/02/2024 + +package universe; + +import java.io.File; +import java.io.FileWriter; + +public class Universe { + // Atributes + + private int[][] grid; + private int width, height; + private int start_i, start_j; + private int filled_boxes; + private int nb_mirors; + private String name; + + // Constructors + + public Universe(int width, int height, int i_start, int j_start, int dir_start) { + this.grid = new int[height][width]; + this.height = height; + this.width = width; + this.start_i = i_start; + this.start_j = j_start; + this.filled_boxes = 0; + this.nb_mirors = 0; + + int i, j; + for (i = 1; i < this.height - 1; i++) { + for (j = 1; j < this.width - 1; j++) { + this.grid[i][j] = 0; + } + } + + for (i = 0; i < this.height; i++) { + this.grid[i][0] = -1; + this.grid[i][width - 1] = -1; + } + + for (j = 0; j < this.width; j++) { + this.grid[0][j] = -1; + this.grid[height - 1][j] = -1; + } + + this.grid[i_start][j_start] = dir_start; + } + + // Methods + + public static void print(int [][] tab, int width, int height, int pos_i, int pos_j) { + int i, j; + for (i = 0; i < height; i++) { + for (j = 0; j < width; j++) { + System.out.print("\033[" + (i + pos_i) + ";" + (j*2 + pos_j) + "H"); + switch (tab[i][j]) { + case -1: + System.out.printf(" X"); + break; + + case 0: + System.out.printf(" "); + break; + + case 1: + System.out.printf(" |"); + break; + + case 2: + System.out.printf(" -"); + break; + + case 3: + System.out.printf(" +"); + break; + + case 4: + System.out.printf(" /"); + break; + + case 5: + System.out.printf(" /"); + break; + + case 6: + System.out.printf(" \\"); + break; + + case 7: + System.out.printf(" \\"); + break; + + case 10: + System.out.printf(" ^"); + break; + + case 11: + System.out.printf(" v"); + break; + + case 12: + System.out.printf(" >"); + break; + + case 13: + System.out.printf(" <"); + break; + + default: + System.out.printf("%2d", tab[i][j]); + } + } + System.out.print("\n"); + } + } + + public void resetUniverse() { + for (int i = 1; i < this.height - 1; i++) { + for (int j = 1; j < this.width - 1; j++) { + if (this.grid[i][j] != 10 && this.grid[i][j] != 11 && this.grid[i][j] != 12 && this.grid[i][j] != 13 && this.grid[i][j] != 0 && this.grid[i][j] != -1) { + this.grid[i][j] = 0; + } + } + } + } + + public void resetUniverseObstacles() { + for (int i = 1; i < this.height - 1; i++) { + for (int j = 1; j < this.width - 1; j++) { + if (this.grid[i][j] != 10 && this.grid[i][j] != 11 && this.grid[i][j] != 12 && this.grid[i][j] != 13 && this.grid[i][j] != 0) { + this.grid[i][j] = 0; + } + } + } + } + + public void changeUniverseDim(int width, int height) { + int [][] newgrid = new int[height][width]; + + for (int i = 1; i < height - 1; i++) { + for (int j = 1; j < width - 1; j++) { + newgrid[i][j] = 0; + } + } + + for (int i = 1; i < height - 1 && i < this.height - 1; i++) { + for (int j = 1; j < width - 1 && j < this.width - 1; j++) { + newgrid[i][j] = this.grid[i][j]; + } + } + + for (int i = 0; i < height; i++) { + newgrid[i][0] = -1; + newgrid[i][width - 1] = -1; + } + + for (int j = 0; j < width; j++) { + newgrid[height - 1][j] = -1; + newgrid[0][j] = -1; + } + + this.grid = newgrid; + this.width = width; + this.height = height; + } + + public void changeUniverseStart(int pos_i, int pos_j, int dir) { + this.grid[this.start_i][start_j] = 0; + this.grid[pos_i][pos_j] = dir; + + this.start_i = pos_i; + this.start_j = pos_j; + } + + public void addObstacle(int pos_i, int pos_j) { + if (this.grid[pos_i][pos_j] == 0) { + this.grid[pos_i][pos_j] = -1; + } + else {} + } + + public void removeObstacle(int pos_i, int pos_j) { + if (this.grid[pos_i][pos_j] == -1) { + this.grid[pos_i][pos_j] = 0; + } + else {} + } + + public int possibleChoices(Situation s) { + int i = s.pos_i; + int j = s.pos_j; + int d = s.direction; + int c = s.nb_choix; + + switch (c) { + case 0: { + switch (d) { + case 10: // north + if (this.grid[i - 1][j] == 0 || this.grid[i - 1][j] == 2) return 1; // front + else if (this.grid[i][j - 1] == 0 && this.grid[i][j] == 0) return 2; // left + else if (this.grid[i][j + 1] == 0 && this.grid[i][j] == 0) return 3; // right + else return -1; // back + + case 11: // south + if (this.grid[i + 1][j] == 0 || this.grid[i + 1][j] == 2) return 1; // front + else if (this.grid[i][j + 1] == 0 && this.grid[i][j] == 0) return 2; // left + else if (this.grid[i][j - 1] == 0 && this.grid[i][j] == 0) return 3; // right + else return -1; // back + + case 12: // east + if (this.grid[i][j + 1] == 0 || this.grid[i][j + 1] == 1) return 1; // front + else if (this.grid[i - 1][j] == 0 && this.grid[i][j] == 0) return 2; // left + else if (this.grid[i + 1][j] == 0 && this.grid[i][j] == 0) return 3; // right + else return -1; // back + + case 13: //west + if (this.grid[i][j - 1] == 0 || this.grid[i][j - 1] == 1) return 1; // front + else if (this.grid[i + 1][j] == 0 && this.grid[i][j] == 0) return 2; // left + else if (this.grid[i - 1][j] == 0 && this.grid[i][j] == 0) return 3; // right + else return -1; // back + + default: {} + } + } + case 1: { + switch (d) { + case 10: // north + if (this.grid[i][j - 1] == 0 && this.grid[i][j] == 0) return 2; // left + else if (this.grid[i][j + 1] == 0 && this.grid[i][j] == 0) return 3; // right + else return -1; // back + + case 11: // south + if (this.grid[i][j + 1] == 0 && this.grid[i][j] == 0) return 2; // left + else if (this.grid[i][j - 1] == 0 && this.grid[i][j] == 0) return 3; // right + else return -1; // back + + case 12: // east + if (this.grid[i - 1][j] == 0 && this.grid[i][j] == 0) return 2; // left + else if (this.grid[i + 1][j] == 0 && this.grid[i][j] == 0) return 3; // right + else return -1; // back + + case 13: //west + if (this.grid[i + 1][j] == 0 && this.grid[i][j] == 0) return 2; // left + else if (this.grid[i - 1][j] == 0 && this.grid[i][j] == 0) return 3; // right + else return -1; // back + + default: {} + } + } + case 2: { + switch (d) { + case 10: // north + if (this.grid[i][j + 1] == 0 && this.grid[i][j] == 0) return 3; // right + else return -1; // back + + case 11: // south + if (this.grid[i][j - 1] == 0 && this.grid[i][j] == 0) return 3; // right + else return -1; // back + + case 12: // east + if (this.grid[i + 1][j] == 0 && this.grid[i][j] == 0) return 3; // right + else return -1; // back + + case 13: //west + if (this.grid[i - 1][j] == 0 && this.grid[i][j] == 0) return 3; // right + else return -1; // back + + default: {} + } + } + case 3: + return -1; + + default: return -1; + } + } + + public boolean canEvolve(Situation s) { + return possibleChoices(s) != -1; + } + + public Situation evolve(Situation s) { + int i = s.pos_i; + int j = s.pos_j; + int d = s.direction; + int c = possibleChoices(s); + + // new status of the box + + if (c == 1 && (d == 10 || d == 11)) { + if (this.grid[i][j] == 0) { + this.grid[i][j] = 1; + this.filled_boxes ++; + } else { + this.grid[i][j] = 3; + } + } + if (c == 1 && (d == 12 || d == 13)) { + if (this.grid[i][j] == 0) { + this.grid[i][j] = 2; + this.filled_boxes ++; + } else { + this.grid[i][j] = 3; + } + } + if ((c == 3 && d == 10) || (c == 2 && d == 13)) { + this.grid[i][j] = 4; + this.filled_boxes ++; + this.nb_mirors ++; + } + if ((c == 2 && d == 12) || (c == 3 && d == 11)) { + this.grid[i][j] = 5; + this.filled_boxes ++; + this.nb_mirors ++; + } + if ((c == 2 && d == 10) || (c == 3 && d == 12)) { + this.grid[i][j] = 6; + this.filled_boxes ++; + this.nb_mirors ++; + } + if ((c == 2 && d == 11) || (c == 3 && d == 13)) { + this.grid[i][j] = 7; + this.filled_boxes ++; + this.nb_mirors ++; + } + + // changing the position of the situation + + if (c == 1 && d == 10 || c == 2 && d == 12 || c == 3 && d == 13) { + i --; + d = 10; + } + else if (c == 1 && d == 11 || c == 2 && d == 13 || c == 3 && d == 12) { + i ++; + d = 11; + } + else if (c == 1 && d == 12 || c == 2 && d == 11 || c == 3 && d == 10) { + j ++; + d = 12; + } + else if (c == 1 && d == 13 || c == 2 && d == 10 || c == 3 && d == 11) { + j --; + d = 13; + } + + return new Situation(i, j, d, 0); + } + + public void reset(Situation s) { + int i = s.pos_i; + int j = s.pos_j; + int d = s.direction; + + if (this.grid[i][j] == 3) { + if (d == 10 || d == 11) { + this.grid[i][j] = 2; + } else { + this.grid[i][j] = 1; + } + } else { + if (this.grid[i][j] == 4 || this.grid[i][j] == 5 || this.grid[i][j] == 6 || this.grid[i][j] == 7) {this.nb_mirors--;} + this.filled_boxes--; + this.grid[i][j] = 0; + } + } + + public void save(String fileName) { + try { + File file = new File("./saves/" + fileName + ".txt"); + + file.createNewFile(); + + FileWriter writer = new FileWriter("./saves/" + fileName + ".txt"); + writer.write((this.height - 2) + "\n" + (this.width - 2) + "\n"); + + for (int i = 1; i < this.height - 1; i++) { + for (int j = 1; j < this.width - 1; j++) { + if (this.grid[i][j] == 10 || this.grid[i][j] == 11 || this.grid[i][j] == 12 || this.grid[i][j] == 13) writer.write(this.grid[i][j] + "\n" + i + "\n" + j + "\n"); + } + } + + for (int i = 1; i < this.height - 1; i++) { + for (int j = 1; j < this.width - 1; j++) { + if (this.grid[i][j] == -1) writer.write(i + "\n" + j + "\n"); + } + } + + writer.close(); + } + catch (Exception e) {} + } + + public int getFilledBoxes() { + return this.filled_boxes; + } + + public int getNbMirrors() { + return this.nb_mirors; + } + + public int[][] getGrid() { + return this.grid; + } + + public int[][] copyGrid() { + int [][] newGrid = new int[this.height][this.width]; + + for (int i = 0; i < this.height; i++) { + for (int j = 0; j < this.width; j++) { + newGrid[i][j] = this.grid[i][j]; + } + } + + return newGrid; + } + + public int getWidth() { + return this.width; + } + + public int getHeight() { + return this.height; + } + + public int[] getStartCoords() { + int [] tab = new int[2]; + tab[0] = this.start_i; + tab[1] = this.start_j; + return tab; + } +} diff --git a/userInterface/Grid.java b/userInterface/Grid.java new file mode 100644 index 0000000..1704e98 --- /dev/null +++ b/userInterface/Grid.java @@ -0,0 +1,291 @@ +package userInterface; + +import javax.swing.JButton; +import javax.swing.JFrame; +import javax.swing.JPanel; + +import java.awt.Dimension; +import java.awt.Color; +import java.awt.GridBagConstraints; +import java.awt.GridLayout; +import java.awt.Insets; + +import javax.swing.*; +import java.awt.event.*; +import java.awt.*; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + +import java.awt.image.BufferedImage; +import java.io.File; +import javax.imageio.ImageIO; + +import java.net.URL; + +import universe.Universe; +import universe.Stack; +import universe.Situation; + +import java.time.Instant; + +public class Grid extends JPanel { + private int width; + private int height; + private JButton[][] mat; + private int selected; + private Universe universe; + private int button_width, button_height; + private int refreshRate; + private boolean solving; + private int display; + + public Grid(int width, int height, Universe universe, int refreshRate, int display) { + super(new GridLayout(height, width)); + this.width = width; + this.height = height; + this.selected = 0; + this.universe = universe; + this.button_width = 600 / this.height; + this.button_height = button_width; + this.refreshRate = refreshRate; + this.solving = false; + this.display = display; + + this.mat = new JButton[height][width]; + + for (int i = 0; i < this.height; i++) { + for (int j = 0; j < this.width; j++) { + this.mat[i][j] = new JButton(); + + this.mat[i][j].setPreferredSize(new Dimension(this.button_width, this.button_height)); + + final int coord_i = i; + final int coord_j = j; + + this.mat[i][j].addActionListener(e -> { + if (solving) { + return; + } + + this.universe.resetUniverse(); + + switch (this.universe.getGrid()[coord_i + 1][coord_j + 1]) { + case 0: + if (this.selected == 1) { + this.universe.changeUniverseStart(coord_i + 1, coord_j + 1, 10); + break; + } + + this.universe.addObstacle(coord_i + 1, coord_j + 1); + break; + case -1: + this.universe.removeObstacle(coord_i + 1, coord_j + 1); + break; + case 10: + if (this.selected == 1) { + this.universe.changeUniverseStart(coord_i + 1, coord_j + 1, 11); + break; + } + break; + case 11: + if (this.selected == 1) { + this.universe.changeUniverseStart(coord_i + 1, coord_j + 1, 12); + break; + } + break; + case 12: + if (this.selected == 1) { + this.universe.changeUniverseStart(coord_i + 1, coord_j + 1, 13); + break; + } + break; + case 13: + if (this.selected == 1) { + this.universe.changeUniverseStart(coord_i + 1, coord_j + 1, 10); + break; + } + break; + } + + this.printUniverseGrid(this.universe.getGrid()); + }); + + super.add(this.mat[i][j]); + } + } + + this.printUniverseGrid(this.universe.getGrid()); + } + + public void setSelected(int selected) { + this.selected = selected; + } + + public void setRefreshRate(int refreshRate) { + this.refreshRate = refreshRate; + } + + public void setSolving(boolean solving) { + this.solving = solving; + } + + public void setDisplay(int display) { + this.display = display; + } + + public void printUniverseGrid(int [][] universeGrid) { + for (int i = 0; i < this.height; i++) { + for (int j = 0; j < this.width; j ++) { + Image photo; + switch (universeGrid[i + 1][j + 1]) { + case -1: + this.changeButtonState(i, j, "../images/wall.png"); + break; + case 0: + this.changeButtonState(i, j, null); + break; + case 1: + this.changeButtonState(i, j, "../images/verticalLaser.png"); + break; + case 2: + this.changeButtonState(i, j, "../images/horizontalLaser.png"); + break; + case 3: + this.changeButtonState(i, j, "../images/crossLaser.png"); + break; + case 4: + this.changeButtonState(i, j, "../images/miror1.png"); + break; + case 5: + this.changeButtonState(i, j, "../images/miror2.png"); + break; + case 6: + this.changeButtonState(i, j, "../images/miror3.png"); + break; + case 7: + this.changeButtonState(i, j, "../images/miror4.png"); + break; + case 10: + this.changeButtonState(i, j, "../images/startUp.png"); + break; + case 11: + this.changeButtonState(i, j, "../images/startBot.png"); + break; + case 12: + this.changeButtonState(i, j, "../images/startRight.png"); + break; + case 13: + this.changeButtonState(i, j, "../images/startLeft.png"); + break; + } + } + } + } + + public void changeButtonState(int coord_i, int coord_j, String url) { + if (url == null) { + Thread t = new Thread(new Runnable() { + @Override + public void run() { + mat[coord_i][coord_j].setBackground(Color.WHITE); + mat[coord_i][coord_j].setIcon(null); + } + }); + + t.start(); + } else { + Thread t = new Thread(new Runnable() { + @Override + public void run() { + Image image = new ImageIcon(getClass().getResource(url)).getImage().getScaledInstance(button_width, button_height, Image.SCALE_SMOOTH); + mat[coord_i][coord_j].setIcon(new ImageIcon(image)); + } + }); + + t.start(); + } + } + + public void reset() { + this.universe.resetUniverse(); + this.printUniverseGrid(this.universe.getGrid()); + } + + public void alert(String message) { + JOptionPane.showMessageDialog(this, message); + } + + public void solve() { + this.universe.resetUniverse(); + final Universe universe = this.universe; + + this.solving = true; + + Thread computeThread = new Thread(new Runnable() { + int [][] bestGrid; + @Override + public void run() { + int [] startCoords = universe.getStartCoords(); + + int firstState_i = startCoords[0]; + int firstState_j = startCoords[1]; + int start_dir = universe.getGrid()[startCoords[0]][startCoords[1]]; + + if (start_dir == 10) firstState_i = firstState_i - 1; + else if (start_dir == 11) firstState_i = firstState_i + 1; + else if (start_dir == 12) firstState_j = firstState_j + 1; + else if (start_dir == 13) firstState_j = firstState_j - 1; + + Stack stack = new Stack (); + Situation currentState = new Situation(firstState_i, firstState_j, start_dir, 0); + + this.bestGrid = universe.copyGrid(); + int best_filled_boxes = 0; + int best_nb_mirrors = 0; + + long start = Instant.now().toEpochMilli(); + long lastRefresh = start; + + do { + if (universe.canEvolve(currentState)) { + stack.push(currentState.copy(universe.possibleChoices(currentState))); + currentState = universe.evolve(currentState); + + if (display == 1 && Instant.now().toEpochMilli() - lastRefresh > refreshRate) { + lastRefresh = Instant.now().toEpochMilli(); + printUniverseGrid(universe.getGrid()); + } + + if ((universe.getFilledBoxes() > best_filled_boxes) || (universe.getFilledBoxes() == best_filled_boxes && universe.getNbMirrors() < best_nb_mirrors)) { + this.bestGrid = universe.copyGrid(); + best_filled_boxes = universe.getFilledBoxes(); + best_nb_mirrors = universe.getNbMirrors(); + + if (display == 2 && Instant.now().toEpochMilli() - lastRefresh > refreshRate) { + lastRefresh = Instant.now().toEpochMilli(); + printUniverseGrid(this.bestGrid); + } + } + } + else if (stack.size() > 0) { + currentState = stack.pop(); + universe.reset(currentState); + } else { + break; + } + if (display == 0 && Instant.now().toEpochMilli() - lastRefresh > refreshRate) { + lastRefresh = Instant.now().toEpochMilli(); + printUniverseGrid(universe.getGrid()); + } + } while (stack.size() != 0 && solving == true); + + printUniverseGrid(bestGrid); + + solving = false; + String message = "Solved in " + ((Instant.now().toEpochMilli() - start)/1000) + "s and " + ((Instant.now().toEpochMilli() - start)%1000) + "ms \nMirrors : " + best_nb_mirrors + "\nLaser length : " + best_filled_boxes; + alert(message); + } + }); + computeThread.start(); + } +} \ No newline at end of file diff --git a/userInterface/UserInterface.java b/userInterface/UserInterface.java new file mode 100644 index 0000000..c91cd08 --- /dev/null +++ b/userInterface/UserInterface.java @@ -0,0 +1,14 @@ +package userInterface; + +import universe.*; + +public class UserInterface extends Thread { + private Window window; + + public UserInterface(Universe universe) { + window = new Window(universe); + } + + public void run() { + } +} \ No newline at end of file diff --git a/userInterface/Window.java b/userInterface/Window.java new file mode 100644 index 0000000..0e08ea2 --- /dev/null +++ b/userInterface/Window.java @@ -0,0 +1,275 @@ +package userInterface; + +import java.awt.Dimension; +import java.awt.Color; +import java.awt.GridBagConstraints; +import java.awt.GridLayout; +import java.awt.Insets; + +import java.io.FileReader; +import java.io.BufferedReader; +import java.io.File; +import java.util.Set; +import java.util.stream.Stream; +import java.util.stream.Collectors; + +import javax.swing.*; +import java.awt.event.*; +import java.awt.*; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + +import java.awt.image.BufferedImage; +import java.io.File; +import javax.imageio.ImageIO; + +import java.net.URL; + +import universe.Universe; + +public class Window extends JFrame { + + private JPanel panel; + private JMenuBar menuBar; + private Grid grid; + private Universe universe; + + public Window(Universe universe) { + super("Laser Finder"); + + this.universe = universe; + + panel = new JPanel(); + panel.setPreferredSize(new Dimension(1000,800)); + panel.setBackground(Color.decode("#EBEBD3")); + + menuBar = new JMenuBar(); + + JMenu fichierMenu = new JMenu("File"); + JMenu aideMenu = new JMenu("Help"); + JMenu toolsMenu = new JMenu("Tools"); + JMenu solveMenu = new JMenu("Solve"); + JMenu displayMenu = new JMenu("Display"); + JMenu refreshRate = new JMenu("Refresh Rate"); + + URL newUrl = getClass().getResource("../images/new.png"); + URL openUrl = getClass().getResource("../images/open.png"); + URL saveUrl = getClass().getResource("../images/save.png"); + + ImageIcon nouveauIcon = new ImageIcon(newUrl.getPath()); + ImageIcon openIcon = new ImageIcon(openUrl.getPath()); + ImageIcon saveIcon = new ImageIcon(saveUrl.getPath()); + + JMenuItem nouveauItem = new JMenuItem("New", nouveauIcon); + JMenuItem ouvrirItem = new JMenuItem("Open", openIcon); + JMenuItem enregistrerItem = new JMenuItem("Save", saveIcon); + + JMenuItem apropos = new JMenuItem("About"); + JMenuItem regles = new JMenuItem("Rules"); + + JRadioButtonMenuItem radioWall = new JRadioButtonMenuItem("Wall"); + JRadioButtonMenuItem radioStart = new JRadioButtonMenuItem("Start"); + + radioWall.setSelected(true); + + ButtonGroup buttonGroup = new ButtonGroup(); + + buttonGroup.add(radioWall); + buttonGroup.add(radioStart); + + JMenuItem changeSize = new JMenuItem("Change Size"); + JMenuItem reset = new JMenuItem("Reset"); + + JMenuItem solve = new JMenuItem("Start"); + JMenuItem stop = new JMenuItem("Stop"); + + JRadioButtonMenuItem radio10ms = new JRadioButtonMenuItem("10ms"); + JRadioButtonMenuItem radio200ms = new JRadioButtonMenuItem("200ms"); + JRadioButtonMenuItem radio500ms = new JRadioButtonMenuItem("500ms"); + JRadioButtonMenuItem radio1000ms = new JRadioButtonMenuItem("1000ms"); + + radio10ms.setSelected(true); + + ButtonGroup refreshRates = new ButtonGroup(); + + refreshRates.add(radio10ms); + refreshRates.add(radio200ms); + refreshRates.add(radio500ms); + refreshRates.add(radio1000ms); + + JMenuItem displayAll = new JMenuItem("Display progress and regress"); + JMenuItem displayProgress = new JMenuItem("Display only progress"); + JMenuItem displayBest = new JMenuItem("Display best grid"); + + fichierMenu.add(nouveauItem); + fichierMenu.add(ouvrirItem); + fichierMenu.add(enregistrerItem); + + aideMenu.add(apropos); + aideMenu.add(regles); + + toolsMenu.add(radioWall); + toolsMenu.add(radioStart); + toolsMenu.addSeparator(); + toolsMenu.add(changeSize); + toolsMenu.addSeparator(); + toolsMenu.add(reset); + + solveMenu.add(solve); + solveMenu.add(stop); + + refreshRate.add(radio10ms); + refreshRate.add(radio200ms); + refreshRate.add(radio500ms); + refreshRate.add(radio1000ms); + + displayMenu.add(refreshRate); + displayMenu.addSeparator(); + displayMenu.add(displayAll); + displayMenu.add(displayProgress); + displayMenu.add(displayBest); + + menuBar.add(fichierMenu); + menuBar.add(aideMenu); + menuBar.add(toolsMenu); + menuBar.add(solveMenu); + menuBar.add(displayMenu); + + nouveauItem.addActionListener(e -> { + this.universe.changeUniverseStart(1, 1, 11); + this.universe.changeUniverseDim(5, 5); + this.universe.resetUniverseObstacles(); + this.panel.remove(this.grid); + this.grid = new Grid(3, 3, this.universe, 10, 0); + this.panel.add(this.grid); + super.pack(); + super.repaint(); + }); + + enregistrerItem.addActionListener(e -> { + String name = JOptionPane.showInputDialog("Choose the universe name"); + this.universe.save(name); + }); + + ouvrirItem.addActionListener(e -> { + String message = "Choose the universe among those : "; + + Set files = Stream.of(new File("./saves").listFiles()).filter(file -> !file.isDirectory()).map(File::getName).collect(Collectors.toSet()); + + for (String element : files) { + message += "\n- " + element.replace(".txt", ""); + } + + String name = JOptionPane.showInputDialog(message); + + try { + BufferedReader reader = new BufferedReader(new FileReader("./saves/" + name + ".txt")); + int universe_height = Integer.valueOf(reader.readLine()); + int universe_width = Integer.valueOf(reader.readLine()); + int start_dir = Integer.valueOf(reader.readLine()); + int start_i = Integer.valueOf(reader.readLine()); + int start_j = Integer.valueOf(reader.readLine()); + + + this.universe.changeUniverseDim(universe_width + 2, universe_height + 2); + this.universe.changeUniverseStart(start_i, start_j, start_dir); + this.universe.resetUniverseObstacles(); + + while (true) { + try { + int pos1 = Integer.valueOf(reader.readLine()); + int pos2 = Integer.valueOf(reader.readLine()); + + this.universe.addObstacle(pos1, pos2); + } + catch (Exception error) { + break; + } + } + + this.panel.remove(this.grid); + this.grid = new Grid(universe_width, universe_height, this.universe, 10, 0); + this.panel.add(this.grid); + super.pack(); + super.repaint(); + } + catch (Exception error) {} + }); + + regles.addActionListener(e -> { + JOptionPane.showMessageDialog(this, "Définissez la taille du plateau ainsi que l'orientation du laser, enfin ajoutez des obstacles et laissez le programme trouver le bon chemin !"); + }); + + changeSize.addActionListener(e -> { + int width = Integer.valueOf(JOptionPane.showInputDialog("Choose the width")); + int height = Integer.valueOf(JOptionPane.showInputDialog("Choose the height")); + + this.universe.changeUniverseDim(width + 2, height + 2); + this.panel.remove(this.grid); + this.grid = new Grid(width, height, this.universe, 10, 0); + this.panel.add(this.grid); + super.pack(); + super.repaint(); + }); + + radioWall.addActionListener(e -> { + this.grid.setSelected(0); + }); + + radioStart.addActionListener(e -> { + this.grid.setSelected(1); + }); + + solve.addActionListener(e -> { + this.grid.solve(); + }); + + stop.addActionListener(e -> { + this.grid.setSolving(false); + }); + + reset.addActionListener(e -> { + this.grid.reset(); + }); + + radio10ms.addActionListener(e -> { + this.grid.setRefreshRate(10); + }); + + radio200ms.addActionListener(e -> { + this.grid.setRefreshRate(200); + }); + + radio500ms.addActionListener(e -> { + this.grid.setRefreshRate(500); + }); + + radio1000ms.addActionListener(e -> { + this.grid.setRefreshRate(1000); + }); + + displayAll.addActionListener(e -> { + this.grid.setDisplay(0); + }); + + displayProgress.addActionListener(e -> { + this.grid.setDisplay(1); + }); + + displayBest.addActionListener(e -> { + this.grid.setDisplay(2); + }); + + this.grid = new Grid(this.universe.getHeight() - 2, this.universe.getWidth() - 2, this.universe, 10, 0); + this.panel.add(grid, BorderLayout.CENTER); + + super.setJMenuBar(menuBar); + super.setContentPane(this.panel); + + super.setLocationRelativeTo(null); + super.setLocation(1000, 400); + super.pack(); + super.setVisible(true); + super.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + } +} \ No newline at end of file