diff --git a/src/eugenisme/controller/Eugenisme.java b/src/eugenisme/controller/Eugenisme.java index 18912b2e6cc3402a8c9cf81bb3b73214032b94c3..829689ec7964b4ee66807599cd3d903710e5ddd9 100644 --- a/src/eugenisme/controller/Eugenisme.java +++ b/src/eugenisme/controller/Eugenisme.java @@ -8,6 +8,7 @@ import eugenisme.model.SimulationManagerGUI; import eugenisme.model.ant.Fourmi; import eugenisme.model.world.Monde; import eugenisme.utils.command.Command; +import eugenisme.utils.command.Line; import eugenisme.utils.field.Field; import eugenisme.view.uigene.UIGene; @@ -15,14 +16,21 @@ import eugenisme.view.uigene.UIGene; /** * Eugenisme fait la gestion des expériences */ -public class Eugenisme { - private static boolean wasPaused = false; - - private static final String SETTINGS_FILE_PATH = "ressources/config.txt"; - private volatile static State state = State.INITIALIZE; - private static Experience experience = new Experience(); - private static Thread threadEvent; - +public class Eugenisme +{ + private static boolean wasPaused = false; + + private static final String SETTINGS_FILE_PATH = "ressources/config.txt"; + private volatile static State state = State.INITIALIZE; + private static Experience experience = new Experience(); + private static Thread threadEvent; + + private static Thread threadDisplayFourmi; + private static Thread threadDisplayMonde; + + private static Fourmi displayFourmi = null; + private static Monde displayMonde = null; + /** * initilisation générale */ @@ -55,14 +63,20 @@ public class Eugenisme { " | max " + experience.getScoreMax()); } - // On appelle itererGeneration - if (!experience.itererGeneration()) { - // si l'experience est fini on sauvegarde et on arrete la boucle - save(); - if (experience.afficherFenetreGenesFourmi.get()) displayFourmi(); - if (experience.afficherFenetreSimulation.get()) displayMonde(); - state = State.SETUP; - } + // On appelle itererGeneration + if(!experience.itererGeneration()) { + // si l'experience est fini on sauvegarde et on arrete la boucle + save(); + if(experience.afficherFenetreGenesFourmi.get()) { + startDisplayFourmi(); + } + if(experience.afficherFenetreSimulation.get()) { + displayFourmi = experience.getFourmis().get(0); + displayMonde = experience.getMonde().clone(); + startDisplayMonde(); + } + state = State.SETUP; + } } /** @@ -76,13 +90,16 @@ public class Eugenisme { * Lance une fenêtre d'UI qui affiche le monde et la fourmi passés en paramètre. */ private static void displayMonde() { - Monde monde = experience.getMonde(); - SimulationManagerGUI smg = - new SimulationManagerGUI(monde, - experience.tempsSim.get(), - Fourmi.fromString("genome: RANDOM_CHOICE[DETECTE_NOURRITURE[PORTE_NOURRITURE[RENTRER_FOURMILIERE, DEPOSER_NOURRITURE], PORTE_NOURRITURE[RENTRER_FOURMILIERE, DEPLACEMENT_BAS]], DETECTE_NOURRITURE[RAMASSER_NOURRITURE, DETECTE_FOURMILIERE[DEPOSER_NOURRITURE, RANDOM_CHOICE[DEPLACEMENT_DROITE, DEPOSER_NOURRITURE]]]]")); - smg.run(); - } + if(displayFourmi == null || displayMonde == null) { + System.out.println("Situation invalide"); + return; + } + SimulationManagerGUI mondeGUI = + new SimulationManagerGUI(displayMonde, + experience.tempsSim.get(), + displayFourmi); + mondeGUI.run(); + } /** * sauvegarde @@ -134,7 +151,9 @@ public class Eugenisme { threadEvent.setDaemon(true); // lancement traitement des inputs threadEvent.start(); - System.out.println("Entrez \"start\" pour débuter la simulation, ou \"help\" pour avoir la liste des commandes"); + System.out.println("Entrez \"start\" pour débuter la simulation, ou \"help\" pour avoir la liste des commandes"); + + // boucle générale while (state != State.KILL) { state.run(); } @@ -149,215 +168,334 @@ public class Eugenisme { * thread parallèle permettant de traiter les entrées utilisateur */ private static void eventThread() { - while (state != State.KILL) state.execute(); + Line cmd; + while (state != State.KILL) { + cmd = InputHandler.nextLine(); + state.execute(cmd); + } } - + /** - * liste des états du programme + * Démare le Thread qui encapsule l'affichage du génome des fourmis */ - public enum State { - // initialisation generale - INITIALIZE(Eugenisme::initialize, null), - // phase de setup - SETUP(null, SETUP_COMMAND()), - RUN(Eugenisme::mainLoop, RUN_COMMAND()), - KILL(null, null); - - private Runnable function; - private Command command; - - private State(Runnable func, Command cmd) { - function = func; - command = cmd; - } - - public void run() { - if (function != null) function.run(); - } - - public void execute() { - if (command != null) command.execute(InputHandler.nextLine()); - } - - - /** - * Commande pour la phase de setup - * les commandes sont données par des fonctions et non par des constantes car les constantes sont initialisees après les enum en java, donc unitilisable ici - * le but est également de déplacer l'initialisation car elle est massive et rendrait le code illisible - */ - private static Command SETUP_COMMAND() { - return new Command(line -> System.out.println("try 'help' for help")) - .addSubCommand("config", - new Command(line -> System.out.println("try 'config help' for help")) - .addSubCommand("help", - new Command(line -> - { - System.out.println("<set/get/list/load/save>"); - } - ) - ).addSubCommand("list", - new Command(line -> - { - System.out.println("Config disponibles : "); - for (Field<?> field : experience.fieldCluster.getFields()) { - System.out.println("- " + field.getName() + " : " + field.get()); - } - } - ) - ).addSubCommand("set", - new Command(line -> - { - String name = line.next(); - String arg = line.next(); - try { - experience.fieldCluster.parseField(name, arg); - System.out.println(name + " set to " + arg); - } catch (NullPointerException e) { - System.out.println("Setting not found : " + name); - } catch (NumberFormatException e) { - System.out.println("Invalid parametter : " + arg); - } - } - ) - ).addSubCommand("get", - new Command(line -> - { - String name = line.next(); - Field<?> field = experience.fieldCluster.getField(name); - if (field != null) - System.out.println(field.getName() + " : " + field.get()); - else - System.out.println("Setting not found : " + name); - } - ) - ).addSubCommand("load", - new Command(line -> System.out.println("try 'config load help' for help")) - .addSubCommand("default", - new Command(line -> - { - System.out.println("loading settings from : " + SETTINGS_FILE_PATH); - experience.loadSettingsFromFile(SETTINGS_FILE_PATH); - } - ) - ).addSubCommand("path", - new Command(line -> - { - String path = line.next(); - System.out.println("loading settings from : " + path); - experience.loadSettingsFromFile(path); - } - ) - ).addSubCommand("help", - new Command(line -> - { - System.out.println("load <default/path>"); - } - ) - ) - ).addSubCommand("save", - new Command(line -> System.out.println("try 'config save help' for help")) - .addSubCommand("default", - new Command(line -> - { - System.out.println("saving settings to : " + SETTINGS_FILE_PATH); - experience.saveSettingsToFile(SETTINGS_FILE_PATH); - } - ) - ).addSubCommand("path", - new Command(line -> - { - String path = line.next(); - System.out.println("saving settings to : " + path); - experience.saveSettingsToFile(path); - } - ) - ).addSubCommand("help", - new Command(line -> - { - System.out.println("save <default/path>"); - } - ) - ) - ) - ).addSubCommand("resume", - new Command(line -> - { - if (!wasPaused) { - System.out.println("Initialization failed : Aucune opération n'est en pause"); - return; - } - try { - experience.resumeFromFile(); - state = State.RUN; - System.out.println("resumed from pause"); - } catch (InitializationFailException e) { - System.out.println("Initialization failed : " + e.getMessage()); - return; - } - } - ) - ).addSubCommand("start", - new Command(line -> - { - try { - experience.initialize(); - state = State.RUN; - System.out.println("begin"); - } catch (InitializationFailException e) { - System.out.println("Initialization failed : " + e.getMessage()); - return; - } - } - ) - ).addSubCommand("exit", - new Command(line -> - { - exit(); - } - ) - ).addSubCommand("help", - new Command(line -> - { - System.out.println("<config/resume/start/exit>"); - } - ) - ); - - } - - /** - * Commande pour la phase de run - */ - private static Command RUN_COMMAND() { - return new Command(line -> System.out.println("try 'help' for help")) - .addSubCommand("help", - new Command(line -> - { - System.out.println("<exit/save/pause>"); - } - ) - ).addSubCommand("exit", - new Command(line -> - { - exit(); - } - ) - ).addSubCommand("save", - new Command(line -> - { - save(); - state = State.SETUP; - } - ) - ).addSubCommand("pause", - new Command(line -> - { - pause(); - state = State.SETUP; - } - ) - ); - } + public static void startDisplayFourmi() { + stopDisplayFourmi(); + + threadDisplayFourmi = new Thread(Eugenisme::displayFourmi); + threadDisplayFourmi.setDaemon(true); + + threadDisplayFourmi.start(); + } + + /** + * Démare le Thread qui encapsule l'affichage du Monde et de la fourmi qui y vit + */ + public static void startDisplayMonde() { + stopDisplayMonde(); + + threadDisplayMonde = new Thread(Eugenisme::displayMonde); + threadDisplayMonde.setDaemon(true); + + threadDisplayMonde.start(); } + + /** + * Arrête le Thread d'affichage du génome + */ + public static void stopDisplayFourmi() { + if(threadDisplayFourmi != null && threadDisplayFourmi.isAlive()) + threadDisplayFourmi.interrupt(); + } + + /** + * Arrête le Thread d'affichage du Monde + */ + public static void stopDisplayMonde() { + if(threadDisplayMonde != null && threadDisplayMonde.isAlive()) + threadDisplayMonde.interrupt(); + } + /** + * liste des etats du programme + * @author adrien + * + */ + public enum State + { + // initialisation generale + INITIALIZE(Eugenisme::initialize, null), + // phase de setup + SETUP(null, SETUP_COMMAND()), + RUN(Eugenisme::mainLoop, RUN_COMMAND()), + KILL(null, null); + + private Runnable function; + private Command command; + private State(Runnable func, Command cmd) {function = func; command = cmd; } + public void run() { if(function != null) function.run(); } + public void execute(Line cmd) { if(command != null) command.execute(cmd); } + + + /** + * Commande pour la phase de setup + * les commandes sont donnees par des fonction et non par des constantes car les constantes sont initialisees apres les enum en java, donc unitilisable ici + * le but est aussi de deplacer l'initialisation car elle est massive et rendrais le code ilisible + */ + private static Command SETUP_COMMAND() + { + return new Command( line -> InputHandler.parse("help") ) + .addSubCommand("config", + new Command( line -> InputHandler.parse("config help") ) + .addSubCommand("help", + new Command( line -> System.out.println("config <help/set/get/list/load/save>") ) + ).addSubCommand("list", + new Command(line -> + { + System.out.println("Paramètres disponibles : "); + for(Field<?> field : experience.fieldCluster.getFields()) + { + System.out.println("- " + field.getName() + " : " + field.get()); + } + } + ) + ).addSubCommand("set", + new Command(line -> + { + String name = line.next(); + String arg = line.next(); + try + { + experience.fieldCluster.parseField(name, arg); + System.out.println(name + " set to " + arg); + } + catch(NullPointerException e) + { + System.out.println("Setting not found : " + name); + } + catch(NumberFormatException e) + { + System.out.println("Invalid parametter : " + arg); + } + } + ) + ).addSubCommand("get", + new Command(line -> + { + String name = line.next(); + Field<?> field = experience.fieldCluster.getField(name); + if(field != null) + System.out.println(field.getName() + " : " + field.get()); + else + System.out.println("Setting not found : " + name); + } + ) + ).addSubCommand("load", + new Command(line -> InputHandler.parse("config load help")) + .addSubCommand("default", + new Command(line -> + { + System.out.println("loading settings from : " + SETTINGS_FILE_PATH); + experience.loadSettingsFromFile(SETTINGS_FILE_PATH); + } + ) + ).addSubCommand("path", + new Command(line -> + { + String path = line.next(); + System.out.println("loading settings from : " + path); + experience.loadSettingsFromFile(path); + } + ) + ).addSubCommand("help", + new Command( line -> System.out.println("config load <help/default/path>") ) + ) + ).addSubCommand("save", + new Command( line -> InputHandler.parse("config save help") ) + .addSubCommand("default", + new Command(line -> + { + System.out.println("saving settings to : " + SETTINGS_FILE_PATH); + experience.saveSettingsToFile(SETTINGS_FILE_PATH); + } + ) + ).addSubCommand("path", + new Command(line -> + { + String path = line.next(); + System.out.println("saving settings to : " + path); + experience.saveSettingsToFile(path); + } + ) + ).addSubCommand("help", + new Command( line -> System.out.println("config save <help/default/path>") ) + ) + ) + ).addSubCommand("display", + new Command(line -> InputHandler.parse("display help") ) + .addSubCommand("help", + new Command(line -> System.out.println("display <help/select/show/hide>") ) + ).addSubCommand("select", + new Command(line -> InputHandler.parse("display select help") ) + .addSubCommand("help", + new Command(line -> System.out.println("display select <help/fourmi/monde>") ) + ).addSubCommand("fourmi", + new Command(line -> InputHandler.parse("display select fourmi help") ) + .addSubCommand("help", + new Command(line -> System.out.println("display select fourmi <help/fromString/fromExperience>") ) + ).addSubCommand("fromString", + new Command(line -> + { + try { displayFourmi = Fourmi.fromString(line.dump()); } + catch(IllegalArgumentException e) { + System.out.println("genome invalide"); + displayFourmi = null; + } + if(displayFourmi != null) + System.out.println("Fourmi chargée"); + } + ) + ).addSubCommand("fromExperience", + new Command(line -> + { + if(experience.getFourmis().isEmpty()) + { + System.out.println("l'experience n'a pas donné de résultat"); + } + else + { + int id = Integer.parseInt(line.next()); + if(experience.tailleSelectionTopFourmi.get() < id && id >= 0) + { + displayFourmi = experience.getFourmis().get(id); + System.out.println("Fourmi chargée"); + } + else + { + System.out.println("id invalide"); + } + } + } + ) + ) + ).addSubCommand("monde", + new Command(line -> InputHandler.parse("display select monde help") ) + .addSubCommand("help", + new Command(line -> System.out.println("display select fourmi <help/fromFile/fromExperience>") ) + ).addSubCommand("fromFile", + new Command(line -> + { + int h = Integer.parseInt(line.next()); + int w = Integer.parseInt(line.next()); + displayMonde = new Monde(h, w); + displayMonde.loadFromFile(line.next()); + } + ) + ).addSubCommand("fromExperience", + new Command(line -> + displayMonde = experience.getMonde().clone() + ) + ) + ) + ).addSubCommand("show", + new Command(line -> InputHandler.parse("display show help") ) + .addSubCommand("help", + new Command(line -> System.out.println("display show <help/genome/simulation>") ) + ).addSubCommand("genome", + new Command(line -> + startDisplayFourmi() + ) + ).addSubCommand("simulation", + new Command(line -> + startDisplayMonde() + ) + ) + ).addSubCommand("hide", + new Command(line -> InputHandler.parse("display hide help") ) + .addSubCommand("help", + new Command(line -> System.out.println("display hide <help/genome/simulation>") ) + ).addSubCommand("genome", + new Command(line -> + stopDisplayFourmi() + ) + ).addSubCommand("simulation", + new Command(line -> + stopDisplayMonde() + ) + ) + ) + ).addSubCommand("resume", + new Command(line -> + { + if(!wasPaused) + { + System.out.println("Initialization failed : Aucune oppération n'est en pause"); + return; + } + try + { + experience.resumeFromFile(); + state = State.RUN; + System.out.println("resumed from pause"); + } + catch (InitializationFailException e) + { + System.out.println("Initialization failed : " + e.getMessage()); + return; + } + } + ) + ).addSubCommand("start", + new Command(line -> + { + try + { + experience.initialize(); + state = State.RUN; + System.out.println("begin"); + } + catch (InitializationFailException e) + { + System.out.println("Initialization failed : " + e.getMessage()); + return; + } + } + ) + ).addSubCommand("exit", + new Command(line -> + exit() + ) + ).addSubCommand("help", + new Command(line -> System.out.println("<help/config/resume/start/exit/display>") ) + ); + + } + /** + * Commande pour la phase de run + */ + private static Command RUN_COMMAND() + { + return new Command(line -> InputHandler.parse("help") ) + .addSubCommand("help", + new Command(line -> System.out.println("<exit/save/pause>") ) + ).addSubCommand("exit", + new Command(line -> + exit() + ) + ).addSubCommand("save", + new Command(line -> + { + save(); + state = State.SETUP; + } + ) + ).addSubCommand("pause", + new Command(line -> + { + pause(); + state = State.SETUP; + } + ) + ); + } + } } diff --git a/src/eugenisme/controller/InputHandler.java b/src/eugenisme/controller/InputHandler.java index 9c7ea72a15d1ecf59ad839fde6864e8d5d12962a..9880b61b0900b4d4b4467114a23eb3570a95257b 100644 --- a/src/eugenisme/controller/InputHandler.java +++ b/src/eugenisme/controller/InputHandler.java @@ -94,7 +94,7 @@ public class InputHandler { */ public static void parse(String data) { for (String cmd : data.split(";")) { - Line line = new Line(cmd.split("[ ,\t]")); + Line line = new Line(cmd.split("[ \t]")); if (!line.isEmpty()) { input.offer(line); synchronized (input) { diff --git a/src/eugenisme/model/SimulationManagerGUI.java b/src/eugenisme/model/SimulationManagerGUI.java index 900d76983d63bd2d8ae6a2f1de408e40702b1402..753549723f400ca4ed0b36177339aa794c517090 100644 --- a/src/eugenisme/model/SimulationManagerGUI.java +++ b/src/eugenisme/model/SimulationManagerGUI.java @@ -42,7 +42,7 @@ public class SimulationManagerGUI implements Runnable { try { Thread.sleep(1000); } catch (InterruptedException e) { - e.printStackTrace(); + i = tempsSim; } } // application du score a la fourmi diff --git a/src/eugenisme/model/ant/Gene.java b/src/eugenisme/model/ant/Gene.java index 21bf8e578b592b49afd6ce28055cb00384bd7043..cb715b5f44cbdaccf90555c672afa76202e4a0bf 100644 --- a/src/eugenisme/model/ant/Gene.java +++ b/src/eugenisme/model/ant/Gene.java @@ -211,7 +211,7 @@ public class Gene implements Cloneable { try { _type = GeneType.valueOf(name); } catch (IllegalArgumentException e) { - System.err.println("String read:(" + name + ")"); + System.err.println("Invalid GeneType : (" + name + ")"); throw e; } // si on a lu un noeud diff --git a/src/eugenisme/utils/command/Line.java b/src/eugenisme/utils/command/Line.java index ae42a977b38dbda20fce19c940dc5c1b359b12ac..bbd2f48f25a37c35e04e90c9719e4557e8c2474d 100644 --- a/src/eugenisme/utils/command/Line.java +++ b/src/eugenisme/utils/command/Line.java @@ -46,6 +46,19 @@ public class Line { public String peek() { return line.peek(); } + + /** + * Retourne tout le reste de la ligne, apres la fonction la ligne est vide + * + * @return les mots restants separes par un espace + */ + public String dump() + { + String ret = ""; + while(!line.isEmpty()) + ret += line.poll() + " "; + return ret; + } public boolean hasNext() { return !line.isEmpty(); diff --git a/src/eugenisme/view/GUI.java b/src/eugenisme/view/GUI.java index cd79922fca4c8148e5d44672bb1c6fe69ab343ee..e50f944a0e21533ab1d85839d3130181ddbeae6c 100644 --- a/src/eugenisme/view/GUI.java +++ b/src/eugenisme/view/GUI.java @@ -1,11 +1,16 @@ package eugenisme.view; +import java.awt.GridLayout; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; + +import javax.swing.JFrame; +import javax.swing.JPanel; + +import eugenisme.controller.Eugenisme; import eugenisme.model.ant.Fourmi; import eugenisme.model.world.Monde; -import javax.swing.*; -import java.awt.*; - /** * Affiche l'évolution d'une fourmi dans le monde grâce à une fenêtre */ @@ -34,6 +39,13 @@ public class GUI { public void startUI() { frame = new JFrame(); frame.setSize(100 * monde.getWidth(), 100 * monde.getHeight()); + + frame.addWindowListener(new WindowAdapter() { + public void windowClosing(WindowEvent windowEvent) { + frame.setVisible(false); + Eugenisme.stopDisplayMonde(); + } + }); panelPrincipal = new JPanel(); panelPrincipal.setLayout(new GridLayout(monde.getWidth(), monde.getHeight())); diff --git a/src/eugenisme/view/uigene/UIGene.java b/src/eugenisme/view/uigene/UIGene.java index 191fbafe691850f444fbbadee140fad3ea9e2669..d2f1089734ccefcce8d6681daf5fec887647001e 100644 --- a/src/eugenisme/view/uigene/UIGene.java +++ b/src/eugenisme/view/uigene/UIGene.java @@ -4,16 +4,19 @@ import java.awt.BorderLayout; import java.awt.Dimension; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; import java.util.ArrayList; import java.util.List; import javax.swing.JComboBox; import javax.swing.JFrame; +import eugenisme.controller.Eugenisme; import eugenisme.model.Experience; /** - * Affiche l'arbre génétique final de la simulation dans une fenêtre + * Affiche l'arbre g�n�tique final de la simulation dans une fen�tre */ public class UIGene extends JFrame { @@ -22,9 +25,9 @@ public class UIGene extends JFrame { UIGenePanel panel; /** - * Constructeur de la fenêtre + * Constructeur de la fen�tre * - * @param exp l'expérience actuelle + * @param exp l'exp�rience actuelle */ public UIGene(Experience exp) { this.exp = exp; @@ -37,7 +40,7 @@ public class UIGene extends JFrame { List<String> listeFourmis = new ArrayList<String>(); // liste des fourmis for (int i = 1; i <= exp.tailleSelectionTopFourmi.get(); i++) { listeFourmis.add("Fourmis " + i); - }// on sélectionne les meilleures fourmis définies par tailleSelectionTopFourmi + }// on s�lectionne les meilleures fourmis d�finies par tailleSelectionTopFourmi JComboBox choixFourmis = new JComboBox(); // on met les fourmis dans une combobox for (Object o : listeFourmis) { @@ -51,6 +54,15 @@ public class UIGene extends JFrame { } }; choixFourmis.addActionListener(actionListener); + + // ref permet de passer la référence dans l'event handler + JFrame ref = this; + ref.addWindowListener(new WindowAdapter() { + public void windowClosing(WindowEvent windowEvent) { + ref.setVisible(false); + Eugenisme.stopDisplayFourmi(); + } + }); } private void addPanel(ActionEvent e, JComboBox<String> choixFourmis) {