rebase ff

Merge conflicts
This commit is contained in:
Lyanis SOUIDI 2023-04-28 23:24:33 +02:00
parent 21e2bdb163
commit 0e01163567
Signed by: Lyanis SOUIDI
GPG Key ID: 251ADD56CFE6A854
29 changed files with 1051 additions and 441 deletions

7
.idea/.gitignore vendored
View File

@ -1,8 +1 @@
# Default ignored files
/shelf/
/workspace.xml
# Editor-based HTTP Client requests
/httpRequests/
# Datasource local storage ignored files
/dataSources/
/dataSources.local.xml

View File

@ -1,124 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="Palette2">
<group name="Swing">
<item class="com.intellij.uiDesigner.HSpacer" tooltip-text="Horizontal Spacer" icon="/com/intellij/uiDesigner/icons/hspacer.svg" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="1" hsize-policy="6" anchor="0" fill="1" />
</item>
<item class="com.intellij.uiDesigner.VSpacer" tooltip-text="Vertical Spacer" icon="/com/intellij/uiDesigner/icons/vspacer.svg" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="1" anchor="0" fill="2" />
</item>
<item class="javax.swing.JPanel" icon="/com/intellij/uiDesigner/icons/panel.svg" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3" />
</item>
<item class="javax.swing.JScrollPane" icon="/com/intellij/uiDesigner/icons/scrollPane.svg" removable="false" auto-create-binding="false" can-attach-label="true">
<default-constraints vsize-policy="7" hsize-policy="7" anchor="0" fill="3" />
</item>
<item class="javax.swing.JButton" icon="/com/intellij/uiDesigner/icons/button.svg" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="3" anchor="0" fill="1" />
<initial-values>
<property name="text" value="Button" />
</initial-values>
</item>
<item class="javax.swing.JRadioButton" icon="/com/intellij/uiDesigner/icons/radioButton.svg" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="3" anchor="8" fill="0" />
<initial-values>
<property name="text" value="RadioButton" />
</initial-values>
</item>
<item class="javax.swing.JCheckBox" icon="/com/intellij/uiDesigner/icons/checkBox.svg" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="3" anchor="8" fill="0" />
<initial-values>
<property name="text" value="CheckBox" />
</initial-values>
</item>
<item class="javax.swing.JLabel" icon="/com/intellij/uiDesigner/icons/label.svg" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="0" anchor="8" fill="0" />
<initial-values>
<property name="text" value="Label" />
</initial-values>
</item>
<item class="javax.swing.JTextField" icon="/com/intellij/uiDesigner/icons/textField.svg" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
<preferred-size width="150" height="-1" />
</default-constraints>
</item>
<item class="javax.swing.JPasswordField" icon="/com/intellij/uiDesigner/icons/passwordField.svg" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
<preferred-size width="150" height="-1" />
</default-constraints>
</item>
<item class="javax.swing.JFormattedTextField" icon="/com/intellij/uiDesigner/icons/formattedTextField.svg" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
<preferred-size width="150" height="-1" />
</default-constraints>
</item>
<item class="javax.swing.JTextArea" icon="/com/intellij/uiDesigner/icons/textArea.svg" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JTextPane" icon="/com/intellij/uiDesigner/icons/textPane.svg" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JEditorPane" icon="/com/intellij/uiDesigner/icons/editorPane.svg" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JComboBox" icon="/com/intellij/uiDesigner/icons/comboBox.svg" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="0" hsize-policy="2" anchor="8" fill="1" />
</item>
<item class="javax.swing.JTable" icon="/com/intellij/uiDesigner/icons/table.svg" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JList" icon="/com/intellij/uiDesigner/icons/list.svg" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="2" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JTree" icon="/com/intellij/uiDesigner/icons/tree.svg" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JTabbedPane" icon="/com/intellij/uiDesigner/icons/tabbedPane.svg" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3">
<preferred-size width="200" height="200" />
</default-constraints>
</item>
<item class="javax.swing.JSplitPane" icon="/com/intellij/uiDesigner/icons/splitPane.svg" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3">
<preferred-size width="200" height="200" />
</default-constraints>
</item>
<item class="javax.swing.JSpinner" icon="/com/intellij/uiDesigner/icons/spinner.svg" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1" />
</item>
<item class="javax.swing.JSlider" icon="/com/intellij/uiDesigner/icons/slider.svg" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1" />
</item>
<item class="javax.swing.JSeparator" icon="/com/intellij/uiDesigner/icons/separator.svg" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3" />
</item>
<item class="javax.swing.JProgressBar" icon="/com/intellij/uiDesigner/icons/progressbar.svg" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="0" fill="1" />
</item>
<item class="javax.swing.JToolBar" icon="/com/intellij/uiDesigner/icons/toolbar.svg" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="0" fill="1">
<preferred-size width="-1" height="20" />
</default-constraints>
</item>
<item class="javax.swing.JToolBar$Separator" icon="/com/intellij/uiDesigner/icons/toolbarSeparator.svg" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="0" anchor="0" fill="1" />
</item>
<item class="javax.swing.JScrollBar" icon="/com/intellij/uiDesigner/icons/scrollbar.svg" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="0" anchor="0" fill="2" />
</item>
</group>
</component>
</project>

12
.vscode/launch.json vendored Normal file
View File

@ -0,0 +1,12 @@
{
"version": "0.2.0",
"configurations": [
{
"type": "java",
"name": "Labyrinthe",
"request": "launch",
"mainClass": "Main",
"projectName": "SAE21_2022_c8f95a52"
}
]
}

View File

@ -1,3 +1,11 @@
# If the first argument is "run"...
ifeq (run,$(firstword $(MAKECMDGOALS)))
# use the rest as arguments for "run"
RUN_ARGS := $(wordlist 2,$(words $(MAKECMDGOALS)),$(MAKECMDGOALS))
# ...and turn them into do-nothing targets
$(eval $(RUN_ARGS):;@:)
endif
### VARIABLES ###
JC = javac
@ -21,7 +29,7 @@ $(OUTDIR)/Main.class : $(OFILES)
### REGLES OPTIONNELLES ###
run : $(OUTDIR)/Main.class
${JVM} ${JVMFLAGS} -cp $(OUTDIR) Main
${JVM} ${JVMFLAGS} -cp $(OUTDIR) Main $(RUN_ARGS)
clean :
-rm -rf $(OUTDIR)

View File

@ -1,6 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="JAVA_MODULE" version="4">
<component name="NewModuleRootManager" inherit-compiler-output="true">
<component name="NewModuleRootManager">
<output url="file://$MODULE_DIR$/out" />
<exclude-output />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />

View File

@ -10,8 +10,4 @@ public interface Algo {
*/
void nextMove();
/**
* Resets the algorithm
*/
void reset();
}

17
src/AlgoType.java Normal file
View File

@ -0,0 +1,17 @@
/**
* Enum for the different types of algorithms
* @version 1.0
* @author Amir Daouadi
* @author Lyanis Souidi
*/
public enum AlgoType {
/**
* The random algorithm
*/
RANDOM,
/**
* The deterministic algorithm
*/
DETERMINISTIC,
}

98
src/AutoSimulation.java Normal file
View File

@ -0,0 +1,98 @@
/**
* This class is used to store the data of the auto simulations
* @version 1.0
* @author Amir Daouadi
* @author Lyanis Souidi
*/
public class AutoSimulation {
/**
* The grid to use for the simulations
*/
private final Grid grid;
/**
* The algorithm type to use for the simulations
*/
private final AlgoType algoType;
/**
* The simulations
*/
private final Simulation[] simulations = new Simulation[100];
/**
* Constructor
* @param grid The grid to use for the simulations
* @param algoType The algorithm type to use for the simulations
*/
public AutoSimulation(Grid grid, AlgoType algoType) {
this.grid = grid;
this.algoType = algoType;
for (int i = 0; i < this.simulations.length; i++) {
simulations[i] = new Simulation();
}
}
/**
* Get the grid used for the simulations
* @return The grid
*/
public Grid getGrid() {
return this.grid;
}
/**
* Get the algorithm type used for the simulations
* @return The algorithm type
*/
public AlgoType getAlgoType() {
return this.algoType;
}
/**
* Get the simulations
* @return The simulations
*/
public Simulation[] getSimulations() {
return this.simulations;
}
/**
* Get the average number of moves of the simulations
* @return The average number of moves
*/
public float getAverageMoves() {
int endedSimulations = 0;
float averageMoves = 0;
for (Simulation simulation : simulations) {
if (simulation.isEnded()) {
endedSimulations++;
averageMoves += simulation.getMoves();
}
}
if (endedSimulations == 0) return 0;
averageMoves = averageMoves / endedSimulations;
return averageMoves;
}
/**
* Get the number of ended simulations
* @return The number of ended simulations
*/
public int getNumberOfEndedSimulations() {
int endedSimulations = 0;
for (Simulation simulation : simulations) {
if (simulation.isEnded()) {
endedSimulations++;
}
}
return endedSimulations;
}
}

View File

@ -0,0 +1,51 @@
/**
* Controller for the automatic simulation
* @version 1.0
* @author Amir Daouadi
* @author Lyanis Souidi
*/
public class AutoSimulationController {
/**
* The automatic simulation view
*/
private final AutoSimulationView view;
/**
* The automatic simulation model
*/
private final AutoSimulation model;
/**
* Constructor
* @param view The automatic simulation view
* @param model The automatic simulation model
*/
public AutoSimulationController(AutoSimulationView view, AutoSimulation model) {
this.view = view;
this.model = model;
new Thread(this::run).start();
}
/**
* Run the simulations
*/
public void run() {
for (Simulation simulation : this.model.getSimulations()) {
if (!simulation.isEnded()) {
Algo algo;
if (this.model.getAlgoType() == AlgoType.RANDOM) {
algo = new RandomAlgo(this.model.getGrid(), simulation);
} else {
algo = new DeterministicAlgo(this.model.getGrid(), simulation);
}
while (!simulation.isEnded()) {
algo.nextMove();
this.view.repaint();
}
this.model.getGrid().reset();
}
}
}
}

View File

@ -2,64 +2,51 @@ import javax.swing.*;
import java.awt.*;
/**
* The view for the auto simulation
* The view for the automatic simulation
* Display directly the success rate and the average number of moves of the simulations
* @version 1.0
* @version 1.1
* @author Amir Daouadi
* @author Lyanis Souidi
*/
public class AutoSimulationView extends JPanel {
/**
* The simulations to display
*/
private Simulation[] simulations;
/**
* The success rate of the simulations
*/
private float success = 0;
/**
* The average number of moves of the simulations
*/
private float moves = 0;
public final AutoSimulation model;
/**
* Constructor
* @param simulations The simulations to display
* @param model The automatic simulation model
*/
public AutoSimulationView(Simulation[] simulations) {
public AutoSimulationView(AutoSimulation model) {
super();
this.simulations = simulations;
this.model = model;
this.setOpaque(false);
this.setPreferredSize(new Dimension(700, 500));
}
/**
* Calculate the success rate and the average number of moves
*/
private void calculate() {
for (Simulation simulation : simulations) {
this.success += simulation.isSuccess() ? 1 : 0;
this.moves += simulation.getMoves();
}
this.success = (this.success / simulations.length) * 100;
this.moves = this.moves / simulations.length;
}
@Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
calculate();
g.setColor(Color.BLACK);
if (this.model.getSimulations()[0].getMoves() == 0) return;
g.setFont(new Font("Arial", Font.PLAIN, 20));
FontMetrics metrics = g.getFontMetrics(g.getFont());
String successStr = "Taux de réussite : " + this.success + "%";
g.drawString(successStr, (getWidth() - metrics.stringWidth(successStr)) / 2, ((getHeight() - metrics.getHeight()) / 2 + metrics.getAscent()) - 50);
int y = 0;
String movesStr = "Nombre de mouvements moyen : " + this.moves;
g.drawString(movesStr, (getWidth() - metrics.stringWidth(movesStr)) / 2, ((getHeight() - metrics.getHeight()) / 2 + metrics.getAscent()) + 50);
int endedSimulations = this.model.getNumberOfEndedSimulations();
int totalSimulations = this.model.getSimulations().length;
int index = endedSimulations >= totalSimulations ? totalSimulations - 1 : endedSimulations;
Simulation lastSimulation = this.model.getSimulations()[index];
if (!lastSimulation.isEnded()) {
y = 50;
g.setColor(Color.RED);
String simulationStr = "Simulation " + endedSimulations + "/" + totalSimulations + " : " + lastSimulation.getMoves() + " mouvements";
g.drawString(simulationStr, (getWidth() - metrics.stringWidth(simulationStr)) / 2, ((getHeight() - metrics.getHeight()) / 2 + metrics.getAscent()) - 50);
}
g.setColor(Color.BLACK);
String movesStr = "Nombre de mouvements moyen : " + this.model.getAverageMoves();
g.drawString(movesStr, (getWidth() - metrics.stringWidth(movesStr)) / 2, ((getHeight() - metrics.getHeight()) / 2 + metrics.getAscent()) + y);
}
}

View File

@ -0,0 +1,74 @@
import java.util.Stack;
/**
* Deterministic algorithm
* @version 0.1
* @author Amir Daouadi
* @author Lyanis Souidi
*/
public class DeterministicAlgo implements Algo {
/**
* The grid model
*/
private final Grid grid;
/**
* The simulation model
*/
private final Simulation simulation;
/**
* The Thésée model
*/
private final Thesee thesee;
/**
* The Thésée controller
*/
private final TheseeController theseeController;
/**
* The directions stack used to go back
*/
private final Stack<Direction> directions = new Stack<>();
/**
* Constructor
* @param grid The grid model
* @param simulation The simulation model
*/
public DeterministicAlgo(Grid grid, Simulation simulation) {
this.grid = grid;
this.simulation = simulation;
this.thesee = this.grid.getThesee();
this.theseeController = new TheseeController(this.thesee);
this.thesee.getSquare().setVisited(true);
}
/**
* Makes the next move of the algorithm
*/
@Override
public void nextMove() {
if (this.simulation.isEnded()) return;
Direction[] availableDirection = this.theseeController.getAvailableDirections();
Direction nextUnvisitedDirection = null;
for (Direction direction : availableDirection) {
try {
if (!this.thesee.getSquare(direction).isVisited()) {
nextUnvisitedDirection = direction;
break;
}
} catch (Exception ignored) {}
}
if (nextUnvisitedDirection != null) {
if (this.theseeController.move(nextUnvisitedDirection, this.simulation)) this.directions.push(nextUnvisitedDirection);
} else this.theseeController.move(this.directions.pop().opposite(), this.simulation);
if (!this.simulation.isEnded() && this.grid.isEnded()) {
this.simulation.setEnded();
}
}
}

64
src/Direction.java Normal file
View File

@ -0,0 +1,64 @@
/**
* Enum for the direction of Thésée's movement.
* @version 1.0
* @author Amir Daouadi
* @author Lyanis Souidi
*/
public enum Direction {
/**
* Up direction
*/
UP,
/**
* Down direction
*/
DOWN,
/**
* Left direction
*/
LEFT,
/**
* Right direction
*/
RIGHT;
/**
* Get the index to add to the row of the current square to get the row of the next square.
* @return The index to add to the row
*/
public int row() {
return switch (this) {
case UP -> -1;
case DOWN -> 1;
default -> 0;
};
}
/**
* Get the index to add to the column of the current square to get the column of the next square.
* @return The index to add to the column
*/
public int column() {
return switch (this) {
case LEFT -> -1;
case RIGHT -> 1;
default -> 0;
};
}
/**
* Get the opposite direction
* @return The opposite direction
*/
public Direction opposite() {
return switch (this) {
case UP -> DOWN;
case DOWN -> UP;
case LEFT -> RIGHT;
case RIGHT -> LEFT;
};
}
}

View File

@ -1,5 +1,5 @@
public class Editor {
private Grid gridModel;
private final Grid gridModel;
public Editor(Grid gridModel) {
this.gridModel = gridModel;

View File

@ -1,76 +1,141 @@
import javax.swing.*;
import javax.swing.filechooser.FileNameExtensionFilter;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.io.File;
import java.util.Random;
public class EditorController extends GridController {
private Editor model;
private EditorView view;
private final Editor model;
private final EditorView view;
private enum Mode { DISABLED, WALL, THESEE, EXIT }
private Mode editMode = Mode.DISABLED;
private Button editTheseeButton = new Button("Placer Joueur");
private Button editExitButton = new Button("Placer Sortie");
private Button editWallButton = new Button("Enlever/Ajouter Murs");
private boolean edited = false;
private final Button editTheseeButton = new Button("Modifier Thésée");
private final Button editExitButton = new Button("Modifier Sortie");
private final Button editWallButton = new Button("Modifier Murs");
private final Button exportButton = new Button("Exporter");
private final Button startButton = new Button("Démarrer");
public EditorController(Editor model, EditorView view) {
super(model.getGrid(), view);
this.model = model;
this.view = view;
this.view.window.setPageTitle(this.model.getGrid().getFile().getName());
this.view.addMouseListener(new MouseAdapter() {
public void mouseClicked(MouseEvent e) {
public void mousePressed(MouseEvent e) {
edit(view.click(e));
}
});
JPanel buttons = new JPanel();
editWallButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
if (editMode == Mode.DISABLED) {
editWallButton.setText("Mode Dessin");
setEditMode(Mode.WALL);
} else {
editWallButton.setText("Enlever/Ajouter Murs");
setEditMode(Mode.DISABLED);
}
Button randomizeButton = new Button("Aléatoire");
randomizeButton.addActionListener(e -> {
random();
if (!edited) {
edited = true;
view.window.setPageTitle("*" + view.window.getPageTitle());
}
view.repaint();
});
buttons.add(randomizeButton);
this.editWallButton.addActionListener(e -> setEditMode(Mode.WALL));
buttons.add(editWallButton);
editTheseeButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
if (editMode == Mode.DISABLED) {
editTheseeButton.setText("Mode Dessin");
setEditMode(Mode.THESEE);
} else {
editTheseeButton.setText("Placer Joueur");
setEditMode(Mode.DISABLED);
}
}
});
buttons.add(editTheseeButton);
this.editTheseeButton.addActionListener(e -> setEditMode(Mode.THESEE));
buttons.add(this.editTheseeButton);
editExitButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
if (editMode == Mode.DISABLED) {
editExitButton.setText("Mode Dessin");
setEditMode(Mode.EXIT);
} else {
editExitButton.setText("Placer Sortie");
setEditMode(Mode.DISABLED);
this.editExitButton.addActionListener(e -> setEditMode(Mode.EXIT));
buttons.add(this.editExitButton);
this.exportButton.addActionListener(e -> {
JFileChooser fileChooser = new JFileChooser();
fileChooser.setDialogTitle("Sélectionnez le fichier dans lequel vous souhaitez enregistrer votre grille");
fileChooser.setSelectedFile(model.getGrid().getFile());
fileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
fileChooser.setMultiSelectionEnabled(false);
fileChooser.setAcceptAllFileFilterUsed(false);
fileChooser.setFileFilter(new FileNameExtensionFilter("Fichier labyrinthe (*.lab)", "lab"));
int choix = fileChooser.showSaveDialog(view);
if (choix == JFileChooser.APPROVE_OPTION) {
File file = fileChooser.getSelectedFile();
if (!file.toString().toLowerCase().endsWith(".lab")) {
file = new File(file + ".lab");
}
view.window.setPageTitle(file.getName());
model.getGrid().setFile(file);
try {
FileManager.exportGrid(model.getGrid());
} catch (Exception ex) {
JOptionPane.showMessageDialog(view, ex.getMessage(), "Erreur", JOptionPane.ERROR_MESSAGE);
}
}
});
buttons.add(editExitButton);
buttons.add(this.exportButton);
this.startButton.addActionListener(e -> {
if (!this.model.getGrid().validate()) {
JOptionPane.showMessageDialog(view, "La grille n'est pas valide.\nAssurez-vous que la grille contienne Thésée ainsi qu'une sortie, et que Thésée peut aller jusqu'à la sortie.", "Erreur", JOptionPane.ERROR_MESSAGE);
return;
}
String[] algoOptions = {"Aléatoire", "Déterministe"};
String[] viewOptions = {"Automatique", "Manuel"};
int algoChoice = JOptionPane.showOptionDialog(view, "Choisissez l'algorithme à utiliser :", "Choix de l'algorithme", JOptionPane.DEFAULT_OPTION, JOptionPane.PLAIN_MESSAGE, null, algoOptions, algoOptions[0]);
if (algoChoice == -1) {
JOptionPane.showMessageDialog(view, "Aucun choix n'a été fait.", "Attention", JOptionPane.WARNING_MESSAGE);
return;
}
int viewChoice = JOptionPane.showOptionDialog(view, "Choisissez l'affichage à utiliser :", "Choix de l'affichage", JOptionPane.DEFAULT_OPTION, JOptionPane.PLAIN_MESSAGE, null, viewOptions, viewOptions[0]);
if (viewChoice == -1) {
JOptionPane.showMessageDialog(view, "Aucun choix n'a été fait.", "Attention", JOptionPane.WARNING_MESSAGE);
return;
}
AlgoType algoType = algoChoice == 0 ? AlgoType.RANDOM : AlgoType.DETERMINISTIC;
if (viewChoice == 0) {
AutoSimulation autoSimulation = new AutoSimulation(model.getGrid(), algoType);
AutoSimulationView autoSimulationView = new AutoSimulationView(autoSimulation);
new AutoSimulationController(autoSimulationView, autoSimulation);
view.window.setContentPane(autoSimulationView);
} else {
ManualSimulation manualSimulation = new ManualSimulation(model.getGrid(), algoType);
ManualSimulationView manualSimulationView = new ManualSimulationView(view.window, manualSimulation);
new ManualSimulationController(manualSimulationView, manualSimulation);
view.window.setContentPane(manualSimulationView);
}
view.window.validate();
});
buttons.add(this.startButton);
boolean validGrid = this.model.getGrid().validate();
this.exportButton.setEnabled(validGrid);
this.startButton.setEnabled(validGrid);
this.view.add(buttons, BorderLayout.NORTH);
}
/**
* Process the click on a square
* @param square The square clicked
*/
private void edit(Square square) {
if (square != null) {
if (!this.edited) {
this.edited = true;
this.view.window.setPageTitle("*" + this.view.window.getPageTitle());
}
if (this.editMode == Mode.WALL) {
if (square.isWall()) {
square.setEmpty();
@ -81,22 +146,24 @@ public class EditorController extends GridController {
JOptionPane.showMessageDialog(this.view, ex.getMessage(), "Erreur", JOptionPane.ERROR_MESSAGE);
}
}
this.view.repaint();
} else if (this.editMode == Mode.THESEE) {
try {
this.model.getGrid().getThesee().setSquare(square);
this.model.getGrid().getThesee().setSquare(square, true);
} catch (Exception ex) {
JOptionPane.showMessageDialog(this.view, ex.getMessage(), "Erreur", JOptionPane.ERROR_MESSAGE);
}
this.view.repaint();
} else if (this.editMode == Mode.EXIT) {
try {
square.setExit();
} catch (Exception ex) {
JOptionPane.showMessageDialog(this.view, ex.getMessage(), "Erreur", JOptionPane.ERROR_MESSAGE);
}
this.view.repaint();
}
boolean validGrid = this.model.getGrid().validate();
this.exportButton.setEnabled(validGrid);
this.startButton.setEnabled(validGrid);
this.view.repaint();
}
}
@ -106,15 +173,10 @@ public class EditorController extends GridController {
*/
private void setEditMode(Mode mode) {
this.editMode = mode;
if (mode != Mode.DISABLED) {
this.editTheseeButton.setEnabled(mode == Mode.THESEE);
this.editExitButton.setEnabled(mode == Mode.EXIT);
this.editWallButton.setEnabled(mode == Mode.WALL);
} else {
this.editTheseeButton.setEnabled(true);
this.editExitButton.setEnabled(true);
this.editWallButton.setEnabled(true);
}
this.editTheseeButton.setEnabled(mode != Mode.THESEE);
this.editExitButton.setEnabled(mode != Mode.EXIT);
this.editWallButton.setEnabled(mode != Mode.WALL);
}
/**
@ -125,16 +187,25 @@ public class EditorController extends GridController {
Random rand = new Random();
Grid gridModel = this.model.getGrid();
gridModel.empty();
gridModel.getSquare(rand.nextInt(gridModel.getSize()), rand.nextInt(gridModel.getSize())).setExit();
try {
gridModel.getThesee().setSquare(gridModel.getSquare(rand.nextInt(gridModel.getSize()), rand.nextInt(gridModel.getSize())));
} catch (Exception ignored) {}
for (int i = 0; i < gridModel.getSize(); i++) {
for (int j = 0; j < gridModel.getSize(); j++) {
if (!gridModel.getSquare(i, j).isExit() && !gridModel.getSquare(i, j).isThesee() && rand.nextInt(3) == 0) gridModel.getSquare(i, j).setWall();
}
}
// If the grid is invalid, try again.
if (!gridModel.validate()) random();
this.exportButton.setEnabled(true);
this.startButton.setEnabled(true);
} catch (Exception e) {
System.out.println(e.getMessage());
System.err.println(e.getMessage());
}
}
}

View File

@ -1,7 +1,7 @@
import java.io.*;
/**
* Class to manage file import/export
* @version 1.1
* @version 1.0
* @author Amir Daouadi
* @author Lyanis Souidi
*/
@ -18,7 +18,7 @@ public class FileManager {
FileInputStream fs = new FileInputStream(file);
DataInputStream ds = new DataInputStream(fs);
try {
grid = new Grid(ds.read());
grid = new Grid(ds.read(), file);
grid.getThesee().setSquare(grid.getSquare(ds.read(), ds.read()));
grid.getSquare(ds.read(), ds.read()).setExit();
@ -47,10 +47,11 @@ public class FileManager {
/**
* Export a grid to a file
* @param grid The grid to export
* @param file The file to export to
* @throws Exception If an error occurs during the export
*/
public static void exportGrid(Grid grid, File file) throws Exception {
public static void exportGrid(Grid grid) throws Exception {
if (!grid.validate()) throw new Exception("La grille n'est pas valide. Assurez-vous que la grille contient Thésée et la sortie ainsi que la sortie puisse être accessible depuis la position de Thésée.");
File file = grid.getFile();
try {
FileOutputStream fs = new FileOutputStream(file);
DataOutputStream ds = new DataOutputStream(fs);
@ -64,16 +65,9 @@ public class FileManager {
ds.writeByte(theseeSquare.getColumn());
// Écriture de la position de la sortie
for (int i = 0; i < grid.getSize(); i++) {
for (int j = 0; j < grid.getSize(); j++) {
Square square = grid.getSquare(i, j);
if (square.isExit()) {
ds.writeByte(square.getRow());
ds.writeByte(square.getColumn());
break;
}
}
}
Square exitSquare = grid.getExit();
ds.writeByte(exitSquare.getRow());
ds.writeByte(exitSquare.getColumn());
// Écriture des murs
int bit = 0;
@ -95,6 +89,7 @@ public class FileManager {
if (bit != 0) {
ds.writeByte(value);
}
ds.close();
} catch (Exception e) {
throw new Exception("Une erreur est survenue lors de l'écriture du fichier.");
}

View File

@ -1,8 +1,52 @@
import java.io.File;
import java.util.Stack;
/**
* This class is used to store the grid's data
* @version 1.0
* @author Amir Daouadi
* @author Lyanis Souidi
*/
public class Grid {
/**
* The grid's squares
*/
private Square[][] squares;
/**
* Thésée
*/
private Thesee thesee = new Thesee();
/**
* The grid's name
*/
private File file;
/**
* Constructor
* @param size The size of the grid (number of squares on a row/column)
*/
public Grid(int size) {
createGrid(size, new File("Sans titre"));
}
/**
* Constructor
* @param size The size of the grid (number of squares on a row/column)
* @param file The name of the grid
*/
public Grid(int size, File file) {
createGrid(size, file);
}
/**
* Create the grid
* @param size The size of the grid (number of squares on a row/column)
* @param file The name of the grid
*/
private void createGrid(int size, File file) {
this.file = file;
this.squares = new Square[size][size];
for (int i = 0; i < size; i++) {
for (int j = 0; j < size; j++) {
@ -11,6 +55,37 @@ public class Grid {
}
}
/**
* Empty the grid
* Removes the exit, Thésée and walls
* @see Square#setEmpty()
*/
public void empty() {
this.thesee = new Thesee();
for (Square[] row : this.squares) {
for (Square square : row) {
square.setEmpty();
}
}
}
/**
* Get the grid's name
* @return The grid's name
*/
public File getFile() {
return this.file;
}
/**
* Set the grid's name
* @param file The grid's name
*/
public void setFile(File file) {
this.file = file;
}
/**
* Get the grid's size (number of squares on a row/column)
* @return The grid's size
@ -34,7 +109,102 @@ public class Grid {
}
}
/**
* Get Thésée
* @return Thésée
*/
public Thesee getThesee() {
return this.thesee;
}
/**
* Checks if all the accessible squares have been visited
* @return true if all the accessible squares have been visited, false otherwise
*/
public boolean isEnded() {
for (Square[] row : this.squares) {
for (Square square : row) {
if (square.isAccessible() && !square.isVisited()) return false;
}
}
return true;
}
/**
* Resets Thésée's position and all the squares' visited and accessible status
*/
public void reset() {
this.thesee.reset();
for (Square[] row : this.squares) {
for (Square square : row) {
square.setVisited(false);
}
}
}
/**
* Get the exit square
* @return The exit square
*/
public Square getExit() {
for (Square[] row : this.squares) {
for (Square square : row) {
if (square.isExit()) return square;
}
}
return null;
}
/**
* Validates the grid
* @return true if the grid can be solved, false otherwise
*/
public boolean validate() {
reset();
Square theseeSquare = this.thesee.getSquare();
if (theseeSquare == null) return false;
Square exitSquare = getExit();
if (exitSquare == null) return false;
if (theseeSquare == exitSquare) return false;
discover(theseeSquare);
return exitSquare.isAccessible();
}
/**
* Discovers all the accessible squares from a given square
* @param square The square to start from
*/
private void discover(Square square) {
Stack<Square> discoveredSquares = new Stack<>();
discoveredSquares.push(square);
while (!discoveredSquares.isEmpty()) {
Square discoveredSquare = discoveredSquares.pop();
discoveredSquare.setAccessible(true);
try {
Square upSquare = getSquare(discoveredSquare.getRow() - 1, discoveredSquare.getColumn());
if (!upSquare.isWall() && !upSquare.isAccessible()) discoveredSquares.push(upSquare);
} catch (Exception ignored) {}
try {
Square downSquare = getSquare(discoveredSquare.getRow() + 1, discoveredSquare.getColumn());
if (!downSquare.isWall() && !downSquare.isAccessible()) discoveredSquares.push(downSquare);
} catch (Exception ignored) {}
try {
Square leftSquare = getSquare(discoveredSquare.getRow(), discoveredSquare.getColumn() - 1);
if (!leftSquare.isWall() && !leftSquare.isAccessible()) discoveredSquares.push(leftSquare);
} catch (Exception ignored) {}
try {
Square rightSquare = getSquare(discoveredSquare.getRow(), discoveredSquare.getColumn() + 1);
if (!rightSquare.isWall() && !rightSquare.isAccessible()) discoveredSquares.push(rightSquare);
} catch (Exception ignored) {}
}
}
}

View File

@ -2,15 +2,13 @@ import javax.swing.*;
import java.awt.*;
public class GridView extends JPanel {
public Window window;
public final Window window;
protected Grid model;
protected int gridSize;
protected int gridStartX;
protected int gridStartY;
protected int squareSize;
private Font font;
private final String exit = "";
private final String thesee = "Θ";
/**
* Manages the display of the grid
@ -44,7 +42,11 @@ public class GridView extends JPanel {
for (int i = 0; i < this.model.getSize(); i++) {
for (int j = 0; j < this.model.getSize(); j++) {
try {
if (this.model.getSquare(i, j).isWall()) g.setColor(new Color(122, 68, 25));
Square square = this.model.getSquare(i, j);
if (square.isWall() && square.isVisited()) g.setColor(new Color(82, 79, 47));
else if (square.isWall()) g.setColor(new Color(122, 68, 25));
else if (square.isVisited()) g.setColor(new Color(41, 90, 69));
else g.setColor(new Color(77, 170, 87));
g.fillRect(this.gridStartX + (this.squareSize * j), this.gridStartY + (this.squareSize * i), this.squareSize, this.squareSize);
@ -52,13 +54,15 @@ public class GridView extends JPanel {
FontMetrics metrics = g.getFontMetrics(this.font);
g.setFont(this.font);
// Draw exit
if (this.model.getSquare(i, j).isExit()) {
g.drawString(this.exit, (this.gridStartX + (this.squareSize * j)) + ((this.squareSize - metrics.stringWidth(this.exit)) / 2), (this.gridStartY + (this.squareSize * i)) + (((this.squareSize - metrics.getHeight()) / 2) + metrics.getAscent()));
if (square.isExit()) {
String exit = "";
g.drawString(exit, (this.gridStartX + (this.squareSize * j)) + ((this.squareSize - metrics.stringWidth(exit)) / 2), (this.gridStartY + (this.squareSize * i)) + (((this.squareSize - metrics.getHeight()) / 2) + metrics.getAscent()));
}
// Draw Thésée
if (this.model.getThesee().getSquare() == this.model.getSquare(i, j)) {
g.drawString(this.thesee, (this.gridStartX + (this.squareSize * j)) + ((this.squareSize - metrics.stringWidth(this.thesee)) / 2), (this.gridStartY + (this.squareSize * i)) + (((this.squareSize - metrics.getHeight()) / 2) + metrics.getAscent()));
if (this.model.getThesee().getSquare() == square) {
String thesee = "Θ";
g.drawString(thesee, (this.gridStartX + (this.squareSize * j)) + ((this.squareSize - metrics.stringWidth(thesee)) / 2), (this.gridStartY + (this.squareSize * i)) + (((this.squareSize - metrics.getHeight()) / 2) + metrics.getAscent()));
}
} catch (Exception e) {
System.out.println(e.getMessage());

View File

@ -1,9 +1,10 @@
import javax.swing.*;
import javax.swing.filechooser.FileNameExtensionFilter;
import java.awt.*;
import java.io.File;
public class HomeView extends JPanel {
private Window window;
public final Window window;
public HomeView(Window window) {
this.window = window;
@ -40,52 +41,50 @@ public class HomeView extends JPanel {
}
private Button choisirGrille() {
JPanel panel = new JPanel();
Button choisirGrille = new Button("Générer une grille", new Dimension(250, 50));
choisirGrille.addActionListener(e -> {
String strTaille = JOptionPane.showInputDialog(panel, "Entrez la taille de la grille :", "Taille de la grille", JOptionPane.PLAIN_MESSAGE);
String strTaille = JOptionPane.showInputDialog(this, "Entrez la taille de la grille :", "Taille de la grille", JOptionPane.PLAIN_MESSAGE);
if (strTaille != null && !strTaille.isEmpty()) {
if (!Character.isDigit(strTaille.charAt(0))) {
JOptionPane.showMessageDialog(panel, "Le premier caractère doit être un chiffre ou nombre.", "Erreur", JOptionPane.ERROR_MESSAGE);
JOptionPane.showMessageDialog(this, "Le premier caractère doit être un chiffre ou nombre.", "Erreur", JOptionPane.ERROR_MESSAGE);
return;
}
try {
int taille = Integer.parseInt(strTaille);
if (taille > 3 && taille < 21) {
if (taille >= 2 && taille <= 255) {
if (!sizeWarning(this, taille)) return;
String[] options = {"Remplir aléatoirement", "Partir d'une grille vide"};
int choix = JOptionPane.showOptionDialog(panel, "Choisissez comment remplir la grille :", "Remplissage de la grille", JOptionPane.DEFAULT_OPTION, JOptionPane.PLAIN_MESSAGE, null, options, options[0]);
int choix = JOptionPane.showOptionDialog(this, "Choisissez comment remplir la grille :", "Remplissage de la grille", JOptionPane.DEFAULT_OPTION, JOptionPane.PLAIN_MESSAGE, null, options, options[0]);
EditorView editorView = new EditorView(window);
EditorController editorController = new EditorController(new Editor(new Grid(taille)), editorView);
switch (choix) {
case 0:
case 0 -> {
// afficher la grille aléatoirement
editorController.random();
window.setContentPane(editorView);
window.validate();
break;
case 1:
}
case 1 -> {
window.setContentPane(editorView);
window.validate();
break;
default:
}
default ->
// gérer le cas aucun choix n'a été fait
JOptionPane.showMessageDialog(panel, "Aucun choix n'a été fait.", "Attention", JOptionPane.WARNING_MESSAGE);
return;
JOptionPane.showMessageDialog(this, "Aucun choix n'a été fait.", "Attention", JOptionPane.WARNING_MESSAGE);
}
} else {
String errorMessage = "La taille doit être au moins de 4.";
if (taille >= 21) {
errorMessage = "La taille ne doit pas dépasser 20.";
String errorMessage = "La taille doit être supérieur ou égale à 2.";
if (taille > 255) {
errorMessage = "La taille doit être inférieur ou égale à 255.";
}
JOptionPane.showMessageDialog(panel, errorMessage, "Erreur", JOptionPane.ERROR_MESSAGE);
JOptionPane.showMessageDialog(this, errorMessage, "Erreur", JOptionPane.ERROR_MESSAGE);
}
} catch (NumberFormatException ex) {
JOptionPane.showMessageDialog(panel, "Tapez " + strTaille.charAt(0) + " pour une grille " + strTaille.charAt(0) +"x"+ strTaille.charAt(0) +".", "Erreur", JOptionPane.ERROR_MESSAGE);
JOptionPane.showMessageDialog(this, "Tapez " + strTaille.charAt(0) + " pour une grille " + strTaille.charAt(0) +"x"+ strTaille.charAt(0) +".", "Erreur", JOptionPane.ERROR_MESSAGE);
}
}
});
@ -94,22 +93,27 @@ public class HomeView extends JPanel {
}
private Button importerGrille() {
JPanel panel = new JPanel();
Button importerGrille = new Button("Importer une grille", new Dimension(250, 50));
importerGrille.addActionListener(e -> {
JFileChooser fileChooser = new JFileChooser();
fileChooser.setDialogTitle("Selectionnez le fichier ou se trouve votre grille");
int choix = fileChooser.showOpenDialog(panel);
fileChooser.setDialogTitle("Sélectionnez le fichier où se trouve votre grille");
fileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
fileChooser.setMultiSelectionEnabled(false);
fileChooser.setAcceptAllFileFilterUsed(false);
fileChooser.setFileFilter(new FileNameExtensionFilter("Fichier labyrinthe (*.lab)", "lab"));
int choix = fileChooser.showOpenDialog(this);
if (choix == JFileChooser.APPROVE_OPTION) {
File fichier = fileChooser.getSelectedFile();
try {
Grid grid = FileManager.importGrid(fichier);
if (!sizeWarning(this, grid.getSize())) return;
EditorView editorView = new EditorView(window);
new EditorController(new Editor(FileManager.importGrid(fichier)), editorView);
new EditorController(new Editor(grid), editorView);
window.setContentPane(editorView);
window.validate();
} catch (Exception ex) {
JOptionPane.showMessageDialog(panel, ex.getMessage(), "Erreur", JOptionPane.ERROR_MESSAGE);
JOptionPane.showMessageDialog(this, ex.getMessage(), "Erreur", JOptionPane.ERROR_MESSAGE);
}
}
});
@ -117,6 +121,18 @@ public class HomeView extends JPanel {
return importerGrille;
}
/**
* Shows a warning message if the grid size is too big
* @param size the size of the grid
* @return true if the user wants to continue, false otherwise
*/
public static boolean sizeWarning(JComponent parentComponent, int size) {
if (size <= 25) return true;
String[] options = {"Abandonner", "Continuer avec cette grille"};
int choice = JOptionPane.showOptionDialog(parentComponent, "Vous essayez d'ouvrir une grille de taille " + size + "x" + size + ".\nEn continuant avec cette grille, vous pourrez rencontrer des difficultées lors de l'edition et la durée des simulations de résolutions pourra être impactée.\nVoulez-vous continuer quand même ?", "Attention", JOptionPane.DEFAULT_OPTION, JOptionPane.WARNING_MESSAGE, null, options, options[0]);
return choice != 0;
}
@Override
public void paintComponent(Graphics g) {
super.paintComponent(g);

View File

@ -1,8 +1,30 @@
import javax.swing.*;
import java.io.File;
public class Main {
public static void main(String[] args) {
Window window = new Window();
HomeView home = new HomeView(window);
window.setContentPane(home);
// If the first argument is a .lab file, try to open it
if (args.length > 0 && args[0].toLowerCase().endsWith(".lab")) {
Grid grid = null;
try {
File file = new File(args[0]);
grid = FileManager.importGrid(new File(file.getAbsolutePath()));
} catch (Exception ignored) {}
if (grid != null && HomeView.sizeWarning(new JPanel(), grid.getSize())) {
window.setPageTitle(args[0]);
EditorView editorView = new EditorView(window);
new EditorController(new Editor(grid), editorView);
window.setContentPane(editorView);
window.setVisible(true);
return;
}
}
// Else, open the home page
HomeView homeView = new HomeView(window);
window.setContentPane(homeView);
window.setVisible(true);
}
}

57
src/ManualSimulation.java Normal file
View File

@ -0,0 +1,57 @@
/**
* This class is used to store the data of a manual simulation
* @version 1.0
* @author Amir Daouadi
* @author Lyanis Souidi
*/
public class ManualSimulation {
/**
* The grid to use for the simulations
*/
private final Grid grid;
/**
* The algorithm type to use for the simulations
*/
private final AlgoType algoType;
/**
* The simulation
*/
private final Simulation simulation = new Simulation();
/**
* Constructor
* @param grid The grid to use for the simulation
* @param algoType The algorithm type to use for the simulation
*/
public ManualSimulation(Grid grid, AlgoType algoType) {
this.grid = grid;
this.algoType = algoType;
}
/**
* Get the grid used for the simulation
* @return The grid
*/
public Grid getGrid() {
return this.grid;
}
/**
* Get the algorithm type used for the simulation
* @return The algorithm type
*/
public AlgoType getAlgoType() {
return this.algoType;
}
/**
* Get the simulation
* @return The simulation
*/
public Simulation getSimulation() {
return this.simulation;
}
}

View File

@ -1,7 +1,6 @@
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.*;
/**
* Controller for the manual simulation view.
@ -13,58 +12,68 @@ public class ManualSimulationController {
/**
* The simulation model
*/
private Simulation model;
private final ManualSimulation model;
/**
* The manual simulation view
*/
private ManualSimulationView view;
/**
* The grid model
*/
private Grid grid;
private final ManualSimulationView view;
/**
* The algorithm used for the simulation
*/
private Algo algo;
/**
* The restart button
*/
private Button restartButton = new Button("Recommencer");
/**
* The next button
*/
private Button nextButton = new Button("Coup suivant");
private final Button nextButton = new Button("Coup suivant");
/**
* Constructor
* @param model The simulation model
* @param model The manual simulation model
* @param view The manual simulation view
* @param algo The algorithm used for the simulation
*/
public ManualSimulationController(Simulation model, ManualSimulationView view, Algo algo) {
public ManualSimulationController(ManualSimulationView view, ManualSimulation model) {
this.model = model;
this.view = view;
this.algo = algo;
JPanel buttons = new JPanel();
restartButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
algo.reset();
}
});
buttons.add(restartButton);
nextButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
algo.nextMove();
if (model.isSuccess()) {
nextButton.setEnabled(false);
}
}
});
nextButton.addActionListener(e -> move());
buttons.add(nextButton);
this.view.add(buttons, BorderLayout.NORTH);
this.view.addKeyListener(new KeyAdapter() {
public void keyPressed(KeyEvent e) {
move();
}
});
this.view.setFocusable(true);
this.view.requestFocusInWindow();
run();
}
/**
* Run the simulation
*/
public void run() {
if (this.model.getAlgoType() == AlgoType.RANDOM) {
this.algo = new RandomAlgo(this.model.getGrid(), this.model.getSimulation());
} else {
this.algo = new DeterministicAlgo(this.model.getGrid(), this.model.getSimulation());
}
}
private void move() {
if (model.getSimulation().isEnded()) return;
this.algo.nextMove();
this.view.repaint();
if (model.getSimulation().isEnded()) {
nextButton.setEnabled(false);
JOptionPane.showMessageDialog(view, "Partie terminée en " + model.getSimulation().getMoves() + " coups !", "Fin de partie", JOptionPane.INFORMATION_MESSAGE);
}
}
}

View File

@ -10,15 +10,17 @@ public class ManualSimulationView extends GridView {
/**
* The simulation model
*/
private Simulation model;
private final ManualSimulation model;
/**
* Constructor
* @param window The window
* @param model The simulation model
*/
public ManualSimulationView(Window window, Simulation model) {
public ManualSimulationView(Window window, ManualSimulation model) {
super(window);
this.model = model;
super.setGrid(this.model.getGrid());
}
@Override
@ -27,9 +29,8 @@ public class ManualSimulationView extends GridView {
g.setColor(Color.BLACK);
g.setFont(new Font("Arial", Font.PLAIN, 20));
FontMetrics metrics = g.getFontMetrics(g.getFont());
String movesStr = "Coups : " + this.model.getMoves();
g.drawString(movesStr, 5, 5);
String movesStr = "Coups : " + this.model.getSimulation().getMoves();
g.drawString(movesStr, 10, 20);
}
}

59
src/RandomAlgo.java Normal file
View File

@ -0,0 +1,59 @@
import java.util.Random;
/**
* Random algorithm
* @version 0.1
* @author Amir Daouadi
* @author Lyanis Souidi
*/
public class RandomAlgo implements Algo {
/**
* The grid model
*/
private final Grid grid;
/**
* The simulation model
*/
private final Simulation simulation;
/**
* The Thésée controller
*/
private final TheseeController theseeController;
/**
* Random number generator
*/
private final Random random = new Random();
/**
* Constructor
* @param grid The grid model
* @param simulation The simulation model
*/
public RandomAlgo(Grid grid, Simulation simulation) {
this.grid = grid;
this.simulation = simulation;
this.theseeController = new TheseeController(this.grid.getThesee());
this.grid.getThesee().getSquare().setVisited(true);
}
/**
* Makes the next move of the algorithm
*/
public void nextMove() {
if (this.simulation.isEnded()) return;
Direction[] availableDirection = this.theseeController.getAvailableDirections();
Direction randomDirection = availableDirection[this.random.nextInt(availableDirection.length)];
this.theseeController.move(randomDirection, this.simulation);
this.theseeController.getAvailableDirections();
if (!this.simulation.isEnded() && this.grid.isEnded()) {
this.simulation.setEnded();
}
}
}

View File

@ -1,15 +0,0 @@
import java.util.Random;
public class RandomDirection {
public static final int UP = 0;
public static final int DOWN = 1;
public static final int LEFT = 2;
public static final int RIGHT = 3;
public static int getRandomDirection() {
Random rand = new Random();
int direction = rand.nextInt(4);
return direction;
}
}

View File

@ -11,9 +11,9 @@ public class Simulation {
private int moves = 0;
/**
* If the simulation has been successful or not
* If the simulation has ended or not
*/
private boolean success = false;
private boolean end = false;
/**
* Get the number of moves of the simulation
@ -24,11 +24,18 @@ public class Simulation {
}
/**
* Get if the simulation has been successful or not
* @return If the simulation has been successful or not
* Check if the simulation has ended or not
* @return If the simulation has ended or not
*/
public boolean isSuccess() {
return this.success;
public boolean isEnded() {
return this.end;
}
/**
* Set the simulation as ended
*/
public void setEnded() {
this.end = true;
}
/**
@ -38,11 +45,4 @@ public class Simulation {
this.moves++;
}
/**
* Set if the simulation has been successful or not
* @param success If the simulation has been successful or not
*/
public void setSuccess(boolean success) {
this.success = success;
}
}

View File

@ -1,8 +1,10 @@
public class Square {
public final int row;
public final int column;
public int type = 0;
private Grid gridModel;
private final int row;
private final int column;
private int type = 0;
private boolean isVisited = false;
private boolean isAccessible = false;
private final Grid gridModel;
public Square(Grid gridModel, int row, int column) {
this.gridModel = gridModel;
@ -26,14 +28,6 @@ public class Square {
return this.type == 2;
}
/**
* Checks if the current square is empty (not a wall and not an exit)
* @return true if the current square is empty, false otherwise
*/
public boolean isEmpty() {
return this.type == 0;
}
public boolean isThesee() {
return this.gridModel.getThesee().getSquare() == this;
}
@ -52,16 +46,11 @@ public class Square {
*/
public void setExit() throws Exception {
if (this.gridModel.getThesee().getSquare() == this) throw new Exception("Vous ne pouvez pas placer la sortie sur la même case que Thésée. Déplacez d'abord Thésée puis réessayez.");
for (int i = 0; i < this.gridModel.getSize(); i++) {
for (int j = 0; j < this.gridModel.getSize(); j++) {
try {
if (this.gridModel.getSquare(i, j).isExit()) {
this.gridModel.getSquare(i, j).setEmpty();
}
} catch (Exception e) {
System.err.println(e.getMessage());
}
}
Square oldExit = this.gridModel.getExit();
if (oldExit != null) {
oldExit.setEmpty();
}
this.type = 2;
@ -85,4 +74,20 @@ public class Square {
public Grid getGrid() {
return this.gridModel;
}
public boolean isVisited() {
return this.isVisited;
}
public void setVisited(boolean isVisited) {
this.isVisited = isVisited;
}
public boolean isAccessible() {
return this.isAccessible;
}
public void setAccessible(boolean isAccessible) {
this.isAccessible = isAccessible;
}
}

View File

@ -1,18 +1,57 @@
/**
* Represents Thésée in the labyrinth.
*/
public class Thesee {
private Square square;
private Square intialSquare;
/**
* Moves Thésée to the given square.
* @param square The square to move Thesee to
* @throws Exception If the given square is a wall
*/
public void setSquare(Square square) throws Exception {
if (square.isExit()) throw new Exception("Vous ne pouvez pas placer Thesee sur la même case que la sortie. Déplacez d'abord la sortie puis réessayez.");
square.setEmpty();
this.square = square;
if (this.intialSquare == null) this.intialSquare = this.square;
setSquare(square, false);
}
/**
* Moves Thésée to the given square.
* @param square The square to move Thesee to
* @param initialPosition Whether the square is the initial position
* @throws Exception If the given square is a wall
*/
public void setSquare(Square square, boolean initialPosition) throws Exception {
if (square.isExit()) throw new Exception("Vous ne pouvez pas placer Thésée sur la même case que la sortie. Déplacez d'abord la sortie puis réessayez.");
square.setEmpty();
this.square = square;
if (initialPosition) {
this.intialSquare = this.square;
} else {
if (this.intialSquare == null) this.intialSquare = this.square;
}
}
/**
* Get the square where Thésée is.
* @return The square where Thésée is
*/
public Square getSquare() {
return this.square;
}
/**
* Get a square next to Thésée.
* @param direction The direction to get the square from
* @return The requested square
* @throws Exception If the position is out of grid's bounds
*/
public Square getSquare(Direction direction) throws Exception {
return this.square.getGrid().getSquare(this.square.getRow() + direction.row(), this.square.getColumn() + direction.column());
}
/**
* Resets Thésée's position to the initial square/
*/
public void reset() {
this.square = this.intialSquare;
}

View File

@ -1,9 +1,5 @@
import javax.swing.*;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
public class TheseeController implements KeyListener {
private Thesee model;
public class TheseeController {
private final Thesee model;
private GridView gridView;
public TheseeController(Thesee model, GridView gridView) {
@ -11,78 +7,71 @@ public class TheseeController implements KeyListener {
this.gridView = gridView;
}
public boolean moveUp() {
public TheseeController(Thesee model) {
this.model = model;
}
/**
* Move Thésée in the given direction
* @param direction The direction to move Thésée to
* @param simulation The simulation model
* @return true if the move was successful, false otherwise.
*/
public boolean move(Direction direction, Simulation simulation) {
simulation.addMove();
try {
Square currentSquare = this.model.getSquare();
Square newSquare = currentSquare.getGrid().getSquare(currentSquare.getRow(), currentSquare.getColumn() - 1);
if (newSquare.isWall()) return false;
this.model.setSquare(newSquare);
this.gridView.repaint();
Square newSquare = this.model.getSquare(direction);
newSquare.setVisited(true);
// If the new square is a wall, add a move to simulate the rollback of the move
if (newSquare.isWall()) {
simulation.addMove();
if (this.gridView != null) this.gridView.repaint();
return false;
}
if (newSquare.isExit()) simulation.setEnded();
else this.model.setSquare(newSquare);
if (this.gridView != null) this.gridView.repaint();
return true;
} catch (Exception e) {
return false;
}
}
public boolean moveDown() {
/**
* Get the available directions for the next move.
* It helps prevent Thésée from going out of the grid.
* @return The available directions
*/
public Direction[] getAvailableDirections() {
Direction[] availableDirections = new Direction[4];
int availableDirectionsCount = 0;
try {
Square currentSquare = this.model.getSquare();
Square newSquare = currentSquare.getGrid().getSquare(currentSquare.getRow(), currentSquare.getColumn() + 1);
if (newSquare.isWall()) return false;
this.model.setSquare(newSquare);
this.gridView.repaint();
return true;
} catch (Exception e) {
return false;
}
}
this.model.getSquare(Direction.UP);
availableDirections[availableDirectionsCount] = Direction.UP;
availableDirectionsCount++;
} catch (Exception ignored) {}
public boolean moveLeft() {
try {
Square currentSquare = this.model.getSquare();
Square newSquare = currentSquare.getGrid().getSquare(currentSquare.getRow() - 1, currentSquare.getColumn());
if (newSquare.isWall()) return false;
this.model.setSquare(newSquare);
this.gridView.repaint();
return true;
} catch (Exception e) {
return false;
}
}
this.model.getSquare(Direction.DOWN);
availableDirections[availableDirectionsCount] = Direction.DOWN;
availableDirectionsCount++;
} catch (Exception ignored) {}
public boolean moveRight() {
try {
Square currentSquare = this.model.getSquare();
Square newSquare = currentSquare.getGrid().getSquare(currentSquare.getRow() + 1, currentSquare.getColumn());
if (newSquare.isWall()) return false;
this.model.setSquare(newSquare);
this.gridView.repaint();
return true;
} catch (Exception e) {
return false;
}
}
this.model.getSquare(Direction.LEFT);
availableDirections[availableDirectionsCount] = Direction.LEFT;
availableDirectionsCount++;
} catch (Exception ignored) {}
@Override
public void keyPressed(KeyEvent e) {
int keyCode = e.getKeyCode();
boolean moved;
if (keyCode == KeyEvent.VK_UP) {
moved = moveUp();
} else if (keyCode == KeyEvent.VK_DOWN) {
moved = moveDown();
} else if (keyCode == KeyEvent.VK_LEFT) {
moved = moveLeft();
} else if (keyCode == KeyEvent.VK_RIGHT) {
moved = moveRight();
}
}
try {
this.model.getSquare(Direction.RIGHT);
availableDirections[availableDirectionsCount] = Direction.RIGHT;
availableDirectionsCount++;
} catch (Exception ignored) {}
@Override
public void keyReleased(KeyEvent e) {
}
@Override
public void keyTyped(KeyEvent e) {
Direction[] availableDirectionsTrimmed = new Direction[availableDirectionsCount];
System.arraycopy(availableDirections, 0, availableDirectionsTrimmed, 0, availableDirectionsCount);
return availableDirectionsTrimmed;
}
}

View File

@ -3,13 +3,24 @@ import java.awt.Dimension;
import java.awt.Toolkit;
public class Window extends JFrame {
private static final String programTitle = "Labyrinthe";
private String pageTitle = "";
public Window() {
super("Labyrinthe");
super(programTitle);
Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
Dimension d = new Dimension(screenSize.width-150, screenSize.height-150);
this.setSize(d);
this.setLocationRelativeTo(null);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setMinimumSize(new Dimension(750, 750));
this.setMinimumSize(new Dimension(800, 850));
}
public String getPageTitle() {
return this.pageTitle;
}
public void setPageTitle(String title) {
this.pageTitle = title;
this.setTitle(this.pageTitle + " - " + Window.programTitle);
}
}