diff --git a/forms/interface.ui b/forms/interface.ui
index a4f06a2b59760a354d8cc87be36d37747f2ffe54..a658ce94d2b629028d6350f434ffb8606b106abe 100644
--- a/forms/interface.ui
+++ b/forms/interface.ui
@@ -115,13 +115,20 @@
                    <verstretch>0</verstretch>
                   </sizepolicy>
                  </property>
+                 <property name="minimum">
+                  <number>1</number>
+                 </property>
                  <property name="orientation">
                   <enum>Qt::Horizontal</enum>
                  </property>
                 </widget>
                </item>
                <item>
-                <widget class="QSpinBox" name="simSpeedSpinbox"/>
+                <widget class="QSpinBox" name="simSpeedSpinbox">
+                 <property name="minimum">
+                  <number>1</number>
+                 </property>
+                </widget>
                </item>
               </layout>
              </item>
diff --git a/include/colorlabel.h b/include/colorlabel.h
index 23a60176fc18ad1465674eaa7018598a2659b53a..0d1a689670480898bafa0fcfb9d4031d6cfda449 100644
--- a/include/colorlabel.h
+++ b/include/colorlabel.h
@@ -34,6 +34,8 @@ private slots:
     void loadStateID(unsigned int); // La fonction idPath permet de parcourir la liste des états et d'avoir un affiche du nom et de la couleur sur l'interface
     void pickColor();
 
+    void on_state_label_textEdited(const QString &arg1);
+
 private:
     Ui::ColorLabel *ui;
     Alphabet a;
diff --git a/include/gridview.hpp b/include/gridview.hpp
index 1d1e367db22b2c4970036398c11366f59cf76318..7779c0b3d9896f2f54b626f49e309825283bc1b6 100644
--- a/include/gridview.hpp
+++ b/include/gridview.hpp
@@ -16,6 +16,7 @@ Cette classe représente le widget utilisé pour l'affichage et l'interaction av
 
 #include <QFrame>
 #include <QGraphicsView>
+#include <QLabel>
 
 #include <QGraphicsRectItem>
 
@@ -156,6 +157,7 @@ private:
     void select_all();
 
     void click_on(Coord coord);
+    void update_current_mouse_pos(Coord coord);
 
     const QPixmap &grid_pixmap() const;
 
@@ -173,7 +175,9 @@ private:
     History m_undo_history;
     QImage m_grid_image;
     QPixmap m_grid_pixmap;
+    QLabel* m_mouse_pos_label;
     Grid m_grid;
+    Coord m_last_mouse_pos;
     bool m_in_toggle_mode;
     std::vector<std::pair<unsigned, unsigned>> m_toggle_states;
     std::vector<QGraphicsRectItem*> m_selection_rects;
diff --git a/include/interface.hpp b/include/interface.hpp
index 98ca37b2bdd888dd3d43d763a8b28d203404a459..c0e4c03027c3fdb1cc729384e291c7a59057f7ba 100644
--- a/include/interface.hpp
+++ b/include/interface.hpp
@@ -59,8 +59,6 @@ private slots:
     //! \brief Créer une nouvelle grille ayant des états aléatoire
     void on_randomPatternButton_clicked();
 
-    void on_nbrStatesComboBox_currentTextChanged(const QString &arg1);
-
     //! \brief Applique l'état sélectionné aux cellules sélectionnées de la GridView
     void on_drawCellButton_clicked();
 
@@ -113,16 +111,28 @@ private:
     //! \brief Charge la grille depuis une image.
     void load_from_image();
 
+    //! \brief Charge un nouvel alphabet et met à jour l'UI.
     void ui_update_alphabet(const Alphabet& alph);
 
+    //! \brief Essaie de charger l'état de l'application si il a été sauvegardé.
+    //! \returns True si le chargement a été réussi, false sinon.
+    bool try_load_saved_state();
+
     //! \brief Sauvegarde la configuration actuelle.
     void save_grid_configuration();
 
     //! \brief Charge une configuration liée au modèle donné.
-    void load_grid_configuration();
+    void load_grid_configuration(const QJsonObject &configuration);
 
     //! \brief Retourne le modèle par défaut à charger
     QJsonObject default_model() const;
+
+    //! \brief Retourne la configuration par défaut à charger
+    QJsonObject default_configuration() const;
+
+protected:
+    void closeEvent(QCloseEvent* e) override;
+
 private:
     Ui::MainWindow *ui;
     Simulation simulation;
diff --git a/include/neighborhoodDialog.hpp b/include/neighborhoodDialog.hpp
index f37e0d9a6debc5d2f79b7f8ef631953e8632428b..406160de1aea96bda1533a4fa3f1fb5550b55a91 100644
--- a/include/neighborhoodDialog.hpp
+++ b/include/neighborhoodDialog.hpp
@@ -16,22 +16,24 @@ class NeighborhoodDialog : public QDialog
 
     Coord currentPoint;
 public:
-    explicit NeighborhoodDialog(QWidget *parent = nullptr);
+    explicit NeighborhoodDialog(Neighborhood& n, QWidget *parent = nullptr);
     ~NeighborhoodDialog();
-
-    //! \brief Retourne le voisinage
-    Neighborhood* getVoisinage() const;
-
-    GridView& getGridView() const ;
+    void ResizeCreateGrid(int x, int y, Neighborhood& n);
 
 public slots:
-    Neighborhood& getNeighborhood() const;
+    Neighborhood* getNeighborhood() const;
 
 protected:
     void done(int r);
 
 private slots:
 
+    void on_validateGridDim_2_clicked();
+
+    void on_heightSpinBox_2_valueChanged(int arg1);
+
+    void on_widthSpinBox_2_valueChanged(int arg1);
+
 private:
     Ui::NeighborhoodDialog *ui;
 };
diff --git a/include/neighborhood_rules/mooreNeighborhoodRule.hpp b/include/neighborhood_rules/mooreNeighborhoodRule.hpp
index daba76f4984e6099dcc76fd9e3a9977dd83ecf32..7e575049891ad14446e9cbd81f8f72caf72310a6 100644
--- a/include/neighborhood_rules/mooreNeighborhoodRule.hpp
+++ b/include/neighborhood_rules/mooreNeighborhoodRule.hpp
@@ -17,7 +17,8 @@ Contient la classe de la règle de Moore (semblable à VonNeumann avec les diago
 //! \brief Voisinage de Moore.
 class mooreNeighborhoodRule : public NeighborhoodRule
 {
-    NeighborhoodFormat format;
+    mutable NeighborhoodFormat format;
+    mutable int current_format_radius;
 public:
     mooreNeighborhoodRule(int _radius = 1);
 
@@ -29,6 +30,9 @@ public:
     //! \return Retourne les formats de voisinage possible dans un std::vector.
     std::vector<NeighborhoodFormat> getFormats() const;
 
+private:
+    void update_format() const;
+
 private:
     //! \brief Rayon du voisinage (en nombre de cellule)
     DEFINE_CONFIGURABLE_PROPERTY(IntegerProperty, radius, "Radius", 1);
diff --git a/include/neighborhood_rules/vonNeumannNeighborhoodRule.hpp b/include/neighborhood_rules/vonNeumannNeighborhoodRule.hpp
index 4dad492df20d0d1596eed2c2a01833bc933205ae..8caed011c30b2f1c398665f34f18a6ad83b8eb71 100644
--- a/include/neighborhood_rules/vonNeumannNeighborhoodRule.hpp
+++ b/include/neighborhood_rules/vonNeumannNeighborhoodRule.hpp
@@ -17,7 +17,8 @@ Contient la classe de la règle de Von Neumann.
 //! \brief Voisinage de Von Neumann.
 class vonNeumannNeighborhoodRule : public NeighborhoodRule
 {
-    NeighborhoodFormat format;
+    mutable NeighborhoodFormat format;
+    mutable int current_format_radius;
 public:
     vonNeumannNeighborhoodRule(int _radius = 1);
 
@@ -29,6 +30,9 @@ public:
     //! \return Retourne les formats de voisinage possible dans un std::vector.
     std::vector<NeighborhoodFormat> getFormats() const;
 
+private:
+    void update_format() const;
+
 private:
     //! \brief Rayon du voisinage (en nombre de cellule)
     DEFINE_CONFIGURABLE_PROPERTY(IntegerProperty, radius, "Radius", 1);
diff --git a/include/neighborhoodrule.hpp b/include/neighborhoodrule.hpp
index d4c34450cdf7442322fe2e7ec6e5c73f4c6e21c2..97ae842ba6f27c74d49a690488d5bc9c8bd00b89 100644
--- a/include/neighborhoodrule.hpp
+++ b/include/neighborhoodrule.hpp
@@ -46,10 +46,10 @@ public:
     //! \return Retourne les formats de voisinage possible dans un std::vector.
     virtual std::vector<NeighborhoodFormat> getFormats() const = 0;
 
-    //! \brief Fait avancer l'état de la règle de voisinage d'une génération
-    // Fait avancer l'état de la règle de voisinage d'une génération. Cette fonction est utilisée pour les voisinages tels que celui de Margolus, qui dépendent de la parité de la génération actuelle.
-    // \remark L'implémentation par défaut ne fait rien.
-    virtual void step() {}
+    //! \brief Change le numéro de génération de la règle de voisinage d'une génération
+    //! Fait avancer ou reculer l'état de la règle de voisinage d'une génération. Cette fonction est utilisée pour les voisinages tels que celui de Margolus, qui dépendent de la parité de la génération actuelle.
+    //! \remark L'implémentation par défaut ne fait rien.
+    virtual void update_generation(unsigned gen) {}
 };
 
 #endif // NEIGHBORHOODRULE_HPP
diff --git a/include/propertyvisitors.hpp b/include/propertyvisitors.hpp
index 5a94a846f3aaf4243fc99d9ac927b54d075626da..2af21eb06a7e97de73406039befa405f5c48c352 100644
--- a/include/propertyvisitors.hpp
+++ b/include/propertyvisitors.hpp
@@ -16,6 +16,7 @@ Fichier contenant diverses classes filles de PropertyVisitor permettant l'affich
 #include <QVariant>
 
 #include "property.hpp"
+#include "neighborhoodDialog.hpp"
 
 //! \brief Exception lancée lors d'une erreur liée aux visiteurs de propriétés.
 class PropertyVisitorException : public std::exception
@@ -51,6 +52,7 @@ private:
     QWidget* current_widget();
     void push_array_widget(const Property& prop);
     QWidget *pop_widget();
+    NeighborhoodDialog* neighborhoodDialog;
 
 private:
     void visit(StringProperty& str);
diff --git a/include/structure.hpp b/include/structure.hpp
index 19870a452b0d6b9080165db83cf8af8285b13eff..d0c7a8567ae4c18a05d0802ec851ad7d80691294 100644
--- a/include/structure.hpp
+++ b/include/structure.hpp
@@ -6,7 +6,7 @@
 \brief Structure
 
 Fichier contenant la classe Structure, représentant un ensemble de cellules constituant une structure.
-**/
+                                               **/
 
 #ifndef STRUCTURE_HPP
 #define STRUCTURE_HPP
@@ -18,13 +18,13 @@ Fichier contenant la classe Structure, représentant un ensemble de cellules con
 
 #include "coord.hpp"
 
-/**
+                                           /**
 \class Structure
 \brief Représente une structure
 
-Cette classe permet de représenter un ensemble de cellules constituant une structure, comme un oscillateur ou un glider.
-**/
-class Structure
+                                           Cette classe permet de représenter un ensemble de cellules constituant une structure, comme un oscillateur ou un glider.
+            **/
+        class Structure
 {
 public:
     //! Titre de la structure
@@ -40,7 +40,10 @@ public:
 
 public:
     //! \brief Constructeur par défaut, représente une structure vide.
-    Structure() = default;
+    Structure()
+    {
+        top_left = {0, 0};
+    }
 
     //! \brief Constructeur acceptant deux itérateurs en argument, pointant vers des std::pair de coordonées et de valeur d'état. Appelle 'load<It>(begin, end)'.
     //! \pre It doit pointer vers un std::pair<Coord, int>.
@@ -56,12 +59,13 @@ public:
     void load(It begin, It end)
     {
         static_assert (std::is_same<typename std::remove_reference<decltype(*begin)>::type, std::pair<Coord, unsigned>>::value ||
-                       std::is_same<typename std::remove_reference<decltype(*begin)>::type, std::pair<const Coord, unsigned>>::value,
-                "Iterator value type must be std::pair<Coord, unsigned>");
+                          std::is_same<typename std::remove_reference<decltype(*begin)>::type, std::pair<const Coord, unsigned>>::value,
+                      "Iterator value type must be std::pair<Coord, unsigned>");
 
         int min_x, min_y, max_x, max_y;
         min_x = min_y = std::numeric_limits<int>::max();
         max_x = max_y = std::numeric_limits<int>::min();
+        bool empty = true;
         // Première passe pour calculer les positions minimales et maximales
         for (auto it = begin; it != end; ++it)
         {
@@ -69,13 +73,20 @@ public:
             if (it->second == 0)
                 continue;
 
+            empty = false;
+
             if (it->first.x > max_x) max_x = it->first.x;
             if (it->first.x < min_x) min_x = it->first.x;
             if (it->first.y > max_y) max_y = it->first.y;
             if (it->first.y < min_y) min_y = it->first.y;
         }
 
-        top_left.x = min_x; top_left.y = min_y;
+        if (empty)
+            top_left = {0, 0};
+        else
+        {
+            top_left.x = min_x; top_left.y = min_y;
+        }
 
         m_width = max_x - min_x + 1;
         m_height = max_y - min_y + 1;
diff --git a/models/griffeath.json b/models/griffeath.json
new file mode 100644
index 0000000000000000000000000000000000000000..e33ff1c3a8cf14970bb12a2a1ecd56fddc04eaa8
--- /dev/null
+++ b/models/griffeath.json
@@ -0,0 +1,48 @@
+{
+    "alphabet": [
+        {
+            "color": [
+                255,
+                255,
+                0
+            ],
+            "name": "0"
+        },
+        {
+            "color": [
+                255,
+                215,
+                135
+            ],
+            "name": "1"
+        },
+        {
+            "color": [
+                255,
+                170,
+                0
+            ],
+            "name": "2"
+        },
+        {
+            "color": [
+                255,
+                0,
+                0
+            ],
+            "name": "3"
+        }
+    ],
+    "author": "JM",
+    "date": "dim. juin 6 2021",
+    "desc": "Automate cellulaire de Griffeath.",
+    "neighborhood_data": {
+        "radius": 1
+    },
+    "neighborhood_name": "Moore",
+    "title": "griffeath",
+    "transition_data": {
+        "rule_string": "i, (i+1)%4:[3..*] -> (i+1)%4"
+    },
+    "transition_name": "Totalistic rulestring"
+}
diff --git a/models/langston.json b/models/langston.json
deleted file mode 100644
index b7e0cddb7a0faf2cac104a65d3ba5f774b3377f2..0000000000000000000000000000000000000000
--- a/models/langston.json
+++ /dev/null
@@ -1,32 +0,0 @@
-{
-    "alphabet": [
-        {
-            "color": [
-                255,
-                255,
-                255
-            ],
-            "name": "Dead"
-        },
-        {
-            "color": [
-                0,
-                0,
-                255
-            ],
-            "name": "Alive"
-        }
-    ],
-    "author": "JM",
-    "date": "jeu. juin 3 2021",
-    "desc": "Langston's Loops.\n!!CORRIGER L'ALPHABET!!",
-    "neighborhood_data": {
-        "radius": 1
-    },
-    "neighborhood_name": "Von Neumann",
-    "title": "langston_loops",
-    "transition_data": {
-        "rule_string": "rotate4\n0,0,0,0,0->0\n0,0,0,0,1->2\n0,0,0,0,2->0\n0,0,0,0,3->0\n0,0,0,0,5->0\n0,0,0,0,6->3\n0,0,0,0,7->1\n0,0,0,1,1->2\n0,0,0,1,2->2\n0,0,0,1,3->2\n0,0,0,2,1->2\n0,0,0,2,2->0\n0,0,0,2,3->0\n0,0,0,2,6->2\n0,0,0,2,7->2\n0,0,0,3,2->0\n0,0,0,5,2->5\n0,0,0,6,2->2\n0,0,0,7,2->2\n0,0,1,0,2->2\n0,0,1,1,2->0\n0,0,2,0,2->0\n0,0,2,0,3->0\n0,0,2,0,5->0\n0,0,2,1,2->5\n0,0,2,2,2->0\n0,0,2,3,2->2\n0,0,5,2,2->2\n0,1,2,3,2->1\n0,1,2,4,2->1\n0,1,2,5,2->5\n0,1,2,6,2->1\n0,1,2,7,2->1\n0,1,2,7,5->1\n0,1,4,2,2->1\n0,1,4,3,2->1\n0,1,4,4,2->1\n0,1,4,7,2->1\n0,1,6,2,5->1\n0,1,7,2,2->1\n0,1,7,2,5->5\n0,1,7,5,2->1\n0,1,7,6,2->1\n0,1,7,7,2->1\n0,2,5,2,7->1\n1,0,0,0,1->1\n1,0,0,0,6->1\n1,0,0,0,7->7\n1,0,0,1,1->1\n1,0,0,1,2->1\n1,0,0,2,1->1\n1,0,0,2,4->4\n1,0,0,2,7->7\n1,0,0,5,1->1\n1,0,1,0,1->1\n1,0,1,1,1->1\n1,0,1,2,4->4\n1,0,1,2,7->7\n1,0,2,0,2->6\n1,0,2,1,2->1\n1,0,2,2,1->1\n1,0,2,2,4->4\n1,0,2,2,6->3\n1,0,2,2,7->7\n1,0,2,3,2->7\n1,0,2,4,2->4\n1,0,2,6,2->6\n1,0,2,6,4->4\n1,0,2,6,7->7\n1,0,2,7,1->0\n1,0,2,7,2->7\n1,0,5,4,2->7\n1,1,1,1,2->1\n1,1,1,2,2->1\n1,1,1,2,4->4\n1,1,1,2,5->1\n1,1,1,2,6->1\n1,1,1,2,7->7\n1,1,1,5,2->2\n1,1,2,1,2->1\n1,1,2,2,2->1\n1,1,2,2,4->4\n1,1,2,2,5->1\n1,1,2,2,7->7\n1,1,2,3,2->1\n1,1,2,4,2->4\n1,1,2,6,2->1\n1,1,2,7,2->7\n1,1,3,2,2->1\n1,2,2,2,4->4\n1,2,2,2,7->7\n1,2,2,4,3->4\n1,2,2,5,4->7\n1,2,3,2,4->4\n1,2,3,2,7->7\n1,2,4,2,5->5\n1,2,4,2,6->7\n1,2,5,2,7->5\n2,0,0,0,1->2\n2,0,0,0,2->2\n2,0,0,0,4->2\n2,0,0,0,7->1\n2,0,0,1,2->2\n2,0,0,1,5->2\n2,0,0,2,1->2\n2,0,0,2,2->2\n2,0,0,2,3->2\n2,0,0,2,4->2\n2,0,0,2,5->0\n2,0,0,2,6->2\n2,0,0,2,7->2\n2,0,0,3,2->6\n2,0,0,4,2->3\n2,0,0,5,1->7\n2,0,0,5,2->2\n2,0,0,5,7->5\n2,0,0,7,2->2\n2,0,1,0,2->2\n2,0,1,1,2->2\n2,0,1,2,2->2\n2,0,1,4,2->2\n2,0,1,7,2->2\n2,0,2,0,2->2\n2,0,2,0,3->2\n2,0,2,0,5->2\n2,0,2,0,7->3\n2,0,2,1,2->2\n2,0,2,1,5->2\n2,0,2,2,1->2\n2,0,2,2,2->2\n2,0,2,2,7->2\n2,0,2,3,2->1\n2,0,2,4,2->2\n2,0,2,4,5->2\n2,0,2,5,2->0\n2,0,2,5,5->2\n2,0,2,6,2->2\n2,0,2,7,2->2\n2,0,3,1,2->2\n2,0,3,2,1->6\n2,0,3,2,2->6\n2,0,3,4,2->2\n2,0,4,2,2->2\n2,0,5,1,2->2\n2,0,5,2,1->2\n2,0,5,2,2->2\n2,0,5,5,2->1\n2,0,5,7,2->5\n2,0,6,2,2->2\n2,0,6,7,2->2\n2,0,7,1,2->2\n2,0,7,2,2->2\n2,0,7,4,2->2\n2,0,7,7,2->2\n2,1,1,2,2->2\n2,1,1,2,6->1\n2,1,2,2,2->2\n2,1,2,2,4->2\n2,1,2,2,6->2\n2,1,2,2,7->2\n2,1,4,2,2->2\n2,1,5,2,2->2\n2,1,6,2,2->2\n2,1,7,2,2->2\n2,2,2,2,7->2\n2,2,2,4,4->2\n2,2,2,4,6->2\n2,2,2,7,6->2\n2,2,2,7,7->2\n3,0,0,0,1->3\n3,0,0,0,2->2\n3,0,0,0,4->1\n3,0,0,0,7->6\n3,0,0,1,2->3\n3,0,0,4,2->1\n3,0,0,6,2->2\n3,0,1,0,2->1\n3,0,1,2,2->0\n3,0,2,5,1->1\n4,0,1,1,2->0\n4,0,1,2,2->0\n4,0,1,2,5->0\n4,0,2,1,2->0\n4,0,2,2,2->1\n4,0,2,3,2->6\n4,0,2,5,2->0\n4,0,3,2,2->1\n5,0,0,0,2->2\n5,0,0,2,1->5\n5,0,0,2,2->5\n5,0,0,2,3->2\n5,0,0,2,7->2\n5,0,0,5,2->0\n5,0,2,0,2->2\n5,0,2,1,2->2\n5,0,2,1,5->2\n5,0,2,2,2->0\n5,0,2,2,4->4\n5,0,2,7,2->2\n5,1,2,1,2->2\n5,1,2,2,2->0\n5,1,2,4,2->2\n5,1,2,7,2->2\n6,0,0,0,1->1\n6,0,0,0,2->1\n6,0,2,1,2->0\n6,1,2,1,2->5\n6,1,2,1,3->1\n6,1,2,2,2->5\n7,0,0,0,7->7\n7,0,1,1,2->0\n7,0,1,2,2->0\n7,0,1,2,5->0\n7,0,2,1,2->0\n7,0,2,2,2->1\n7,0,2,2,5->1\n7,0,2,3,2->1\n7,0,2,5,2->5\n7,0,2,7,2->0"
-    },
-    "transition_name": "Non isotropic rulestring"
-}
diff --git a/models/langton.json b/models/langton.json
new file mode 100644
index 0000000000000000000000000000000000000000..288c8eb57312ade3829a6d55fb2f7c6e7de0ee74
--- /dev/null
+++ b/models/langton.json
@@ -0,0 +1,80 @@
+{
+    "alphabet": [
+        {
+            "color": [
+                0,
+                0,
+                0
+            ],
+            "name": "Background"
+        },
+        {
+            "color": [
+                0,
+                0,
+                255
+            ],
+            "name": "Core"
+        },
+        {
+            "color": [
+                255,
+                0,
+                0
+            ],
+            "name": "Sheath"
+        },
+        {
+            "color": [
+                0,
+                170,
+                0
+            ],
+            "name": "Green"
+        },
+        {
+            "color": [
+                255,
+                255,
+                0
+            ],
+            "name": "Yellow"
+        },
+        {
+            "color": [
+                255,
+                85,
+                255
+            ],
+            "name": "Pink"
+        },
+        {
+            "color": [
+                255,
+                255,
+                255
+            ],
+            "name": "White"
+        },
+        {
+            "color": [
+                0,
+                255,
+                255
+            ],
+            "name": "Cyan"
+        }
+    ],
+    "author": "JM",
+    "date": "dim. juin 6 2021",
+    "desc": "",
+    "neighborhood_data": {
+        "radius": 1
+    },
+    "neighborhood_name": "Von Neumann",
+    "title": "langton",
+    "transition_data": {
+        "rule_string": "rotate4\n0,0,0,0,0->0\n0,0,1,0,0->2\n0,0,2,0,0->0\n0,0,3,0,0->0\n0,0,5,0,0->0\n0,0,6,0,0->3\n0,0,7,0,0->1\n0,0,1,0,1->2\n0,0,2,0,1->2\n0,0,3,0,1->2\n0,0,1,0,2->2\n0,0,2,0,2->0\n0,0,3,0,2->0\n0,0,6,0,2->2\n0,0,7,0,2->2\n0,0,2,0,3->0\n0,0,2,0,5->5\n0,0,2,0,6->2\n0,0,2,0,7->2\n0,0,2,1,0->2\n0,0,2,1,1->0\n0,0,2,2,0->0\n0,0,3,2,0->0\n0,0,5,2,0->0\n0,0,2,2,1->5\n0,0,2,2,2->0\n0,0,2,2,3->2\n0,0,2,5,2->2\n0,1,2,2,3->1\n0,1,2,2,4->1\n0,1,2,2,5->5\n0,1,2,2,6->1\n0,1,2,2,7->1\n0,1,5,2,7->1\n0,1,2,4,2->1\n0,1,2,4,3->1\n0,1,2,4,4->1\n0,1,2,4,7->1\n0,1,5,6,2->1\n0,1,2,7,2->1\n0,1,5,7,2->5\n0,1,2,7,5->1\n0,1,2,7,6->1\n0,1,2,7,7->1\n0,2,7,5,2->1\n1,0,1,0,0->1\n1,0,6,0,0->1\n1,0,7,0,0->7\n1,0,1,0,1->1\n1,0,2,0,1->1\n1,0,1,0,2->1\n1,0,4,0,2->4\n1,0,7,0,2->7\n1,0,1,0,5->1\n1,0,1,1,0->1\n1,0,1,1,1->1\n1,0,4,1,2->4\n1,0,7,1,2->7\n1,0,2,2,0->6\n1,0,2,2,1->1\n1,0,1,2,2->1\n1,0,4,2,2->4\n1,0,6,2,2->3\n1,0,7,2,2->7\n1,0,2,2,3->7\n1,0,2,2,4->4\n1,0,2,2,6->6\n1,0,4,2,6->4\n1,0,7,2,6->7\n1,0,1,2,7->0\n1,0,2,2,7->7\n1,0,2,5,4->7\n1,1,2,1,1->1\n1,1,2,1,2->1\n1,1,4,1,2->4\n1,1,5,1,2->1\n1,1,6,1,2->1\n1,1,7,1,2->7\n1,1,2,1,5->2\n1,1,2,2,1->1\n1,1,2,2,2->1\n1,1,4,2,2->4\n1,1,5,2,2->1\n1,1,7,2,2->7\n1,1,2,2,3->1\n1,1,2,2,4->4\n1,1,2,2,6->1\n1,1,2,2,7->7\n1,1,2,3,2->1\n1,2,4,2,2->4\n1,2,7,2,2->7\n1,2,3,2,4->4\n1,2,4,2,5->7\n1,2,4,3,2->4\n1,2,7,3,2->7\n1,2,5,4,2->5\n1,2,6,4,2->7\n1,2,7,5,2->5\n2,0,1,0,0->2\n2,0,2,0,0->2\n2,0,4,0,0->2\n2,0,7,0,0->1\n2,0,2,0,1->2\n2,0,5,0,1->2\n2,0,1,0,2->2\n2,0,2,0,2->2\n2,0,3,0,2->2\n2,0,4,0,2->2\n2,0,5,0,2->0\n2,0,6,0,2->2\n2,0,7,0,2->2\n2,0,2,0,3->6\n2,0,2,0,4->3\n2,0,1,0,5->7\n2,0,2,0,5->2\n2,0,7,0,5->5\n2,0,2,0,7->2\n2,0,2,1,0->2\n2,0,2,1,1->2\n2,0,2,1,2->2\n2,0,2,1,4->2\n2,0,2,1,7->2\n2,0,2,2,0->2\n2,0,3,2,0->2\n2,0,5,2,0->2\n2,0,7,2,0->3\n2,0,2,2,1->2\n2,0,5,2,1->2\n2,0,1,2,2->2\n2,0,2,2,2->2\n2,0,7,2,2->2\n2,0,2,2,3->1\n2,0,2,2,4->2\n2,0,5,2,4->2\n2,0,2,2,5->0\n2,0,5,2,5->2\n2,0,2,2,6->2\n2,0,2,2,7->2\n2,0,2,3,1->2\n2,0,1,3,2->6\n2,0,2,3,2->6\n2,0,2,3,4->2\n2,0,2,4,2->2\n2,0,2,5,1->2\n2,0,1,5,2->2\n2,0,2,5,2->2\n2,0,2,5,5->1\n2,0,2,5,7->5\n2,0,2,6,2->2\n2,0,2,6,7->2\n2,0,2,7,1->2\n2,0,2,7,2->2\n2,0,2,7,4->2\n2,0,2,7,7->2\n2,1,2,1,2->2\n2,1,6,1,2->1\n2,1,2,2,2->2\n2,1,4,2,2->2\n2,1,6,2,2->2\n2,1,7,2,2->2\n2,1,2,4,2->2\n2,1,2,5,2->2\n2,1,2,6,2->2\n2,1,2,7,2->2\n2,2,7,2,2->2\n2,2,4,2,4->2\n2,2,6,2,4->2\n2,2,6,2,7->2\n2,2,7,2,7->2\n3,0,1,0,0->3\n3,0,2,0,0->2\n3,0,4,0,0->1\n3,0,7,0,0->6\n3,0,2,0,1->3\n3,0,2,0,4->1\n3,0,2,0,6->2\n3,0,2,1,0->1\n3,0,2,1,2->0\n3,0,1,2,5->1\n4,0,2,1,1->0\n4,0,2,1,2->0\n4,0,5,1,2->0\n4,0,2,2,1->0\n4,0,2,2,2->1\n4,0,2,2,3->6\n4,0,2,2,5->0\n4,0,2,3,2->1\n5,0,2,0,0->2\n5,0,1,0,2->5\n5,0,2,0,2->5\n5,0,3,0,2->2\n5,0,7,0,2->2\n5,0,2,0,5->0\n5,0,2,2,0->2\n5,0,2,2,1->2\n5,0,5,2,1->2\n5,0,2,2,2->0\n5,0,4,2,2->4\n5,0,2,2,7->2\n5,1,2,2,1->2\n5,1,2,2,2->0\n5,1,2,2,4->2\n5,1,2,2,7->2\n6,0,1,0,0->1\n6,0,2,0,0->1\n6,0,2,2,1->0\n6,1,2,2,1->5\n6,1,3,2,1->1\n6,1,2,2,2->5\n7,0,7,0,0->7\n7,0,2,1,1->0\n7,0,2,1,2->0\n7,0,5,1,2->0\n7,0,2,2,1->0\n7,0,2,2,2->1\n7,0,5,2,2->1\n7,0,2,2,3->1\n7,0,2,2,5->5\n7,0,2,2,7->0"
+    },
+    "transition_name": "Non isotropic rulestring"
+}
diff --git a/patterns/Langton/langton_loop.json b/patterns/Langton/langton_loop.json
new file mode 100644
index 0000000000000000000000000000000000000000..86c6ca3ac528f7ffad5871310be1d8b3932a3385
--- /dev/null
+++ b/patterns/Langton/langton_loop.json
@@ -0,0 +1,438 @@
+{
+    "author": "JM",
+    "cells": [
+        {
+            "state": 2,
+            "x": 1,
+            "y": 0
+        },
+        {
+            "state": 2,
+            "x": 2,
+            "y": 0
+        },
+        {
+            "state": 2,
+            "x": 3,
+            "y": 0
+        },
+        {
+            "state": 2,
+            "x": 4,
+            "y": 0
+        },
+        {
+            "state": 2,
+            "x": 5,
+            "y": 0
+        },
+        {
+            "state": 2,
+            "x": 6,
+            "y": 0
+        },
+        {
+            "state": 2,
+            "x": 7,
+            "y": 0
+        },
+        {
+            "state": 2,
+            "x": 8,
+            "y": 0
+        },
+        {
+            "state": 2,
+            "x": 0,
+            "y": 1
+        },
+        {
+            "state": 1,
+            "x": 1,
+            "y": 1
+        },
+        {
+            "state": 7,
+            "x": 2,
+            "y": 1
+        },
+        {
+            "state": 1,
+            "x": 4,
+            "y": 1
+        },
+        {
+            "state": 4,
+            "x": 5,
+            "y": 1
+        },
+        {
+            "state": 1,
+            "x": 7,
+            "y": 1
+        },
+        {
+            "state": 4,
+            "x": 8,
+            "y": 1
+        },
+        {
+            "state": 2,
+            "x": 9,
+            "y": 1
+        },
+        {
+            "state": 2,
+            "x": 0,
+            "y": 2
+        },
+        {
+            "state": 2,
+            "x": 2,
+            "y": 2
+        },
+        {
+            "state": 2,
+            "x": 3,
+            "y": 2
+        },
+        {
+            "state": 2,
+            "x": 4,
+            "y": 2
+        },
+        {
+            "state": 2,
+            "x": 5,
+            "y": 2
+        },
+        {
+            "state": 2,
+            "x": 6,
+            "y": 2
+        },
+        {
+            "state": 2,
+            "x": 7,
+            "y": 2
+        },
+        {
+            "state": 2,
+            "x": 9,
+            "y": 2
+        },
+        {
+            "state": 2,
+            "x": 0,
+            "y": 3
+        },
+        {
+            "state": 7,
+            "x": 1,
+            "y": 3
+        },
+        {
+            "state": 2,
+            "x": 2,
+            "y": 3
+        },
+        {
+            "state": 2,
+            "x": 7,
+            "y": 3
+        },
+        {
+            "state": 1,
+            "x": 8,
+            "y": 3
+        },
+        {
+            "state": 2,
+            "x": 9,
+            "y": 3
+        },
+        {
+            "state": 2,
+            "x": 0,
+            "y": 4
+        },
+        {
+            "state": 1,
+            "x": 1,
+            "y": 4
+        },
+        {
+            "state": 2,
+            "x": 2,
+            "y": 4
+        },
+        {
+            "state": 2,
+            "x": 7,
+            "y": 4
+        },
+        {
+            "state": 1,
+            "x": 8,
+            "y": 4
+        },
+        {
+            "state": 2,
+            "x": 9,
+            "y": 4
+        },
+        {
+            "state": 2,
+            "x": 0,
+            "y": 5
+        },
+        {
+            "state": 2,
+            "x": 2,
+            "y": 5
+        },
+        {
+            "state": 2,
+            "x": 7,
+            "y": 5
+        },
+        {
+            "state": 1,
+            "x": 8,
+            "y": 5
+        },
+        {
+            "state": 2,
+            "x": 9,
+            "y": 5
+        },
+        {
+            "state": 2,
+            "x": 0,
+            "y": 6
+        },
+        {
+            "state": 7,
+            "x": 1,
+            "y": 6
+        },
+        {
+            "state": 2,
+            "x": 2,
+            "y": 6
+        },
+        {
+            "state": 2,
+            "x": 7,
+            "y": 6
+        },
+        {
+            "state": 1,
+            "x": 8,
+            "y": 6
+        },
+        {
+            "state": 2,
+            "x": 9,
+            "y": 6
+        },
+        {
+            "state": 2,
+            "x": 0,
+            "y": 7
+        },
+        {
+            "state": 1,
+            "x": 1,
+            "y": 7
+        },
+        {
+            "state": 2,
+            "x": 2,
+            "y": 7
+        },
+        {
+            "state": 2,
+            "x": 3,
+            "y": 7
+        },
+        {
+            "state": 2,
+            "x": 4,
+            "y": 7
+        },
+        {
+            "state": 2,
+            "x": 5,
+            "y": 7
+        },
+        {
+            "state": 2,
+            "x": 6,
+            "y": 7
+        },
+        {
+            "state": 2,
+            "x": 7,
+            "y": 7
+        },
+        {
+            "state": 1,
+            "x": 8,
+            "y": 7
+        },
+        {
+            "state": 2,
+            "x": 9,
+            "y": 7
+        },
+        {
+            "state": 2,
+            "x": 10,
+            "y": 7
+        },
+        {
+            "state": 2,
+            "x": 11,
+            "y": 7
+        },
+        {
+            "state": 2,
+            "x": 12,
+            "y": 7
+        },
+        {
+            "state": 2,
+            "x": 13,
+            "y": 7
+        },
+        {
+            "state": 2,
+            "x": 0,
+            "y": 8
+        },
+        {
+            "state": 7,
+            "x": 2,
+            "y": 8
+        },
+        {
+            "state": 1,
+            "x": 3,
+            "y": 8
+        },
+        {
+            "state": 7,
+            "x": 5,
+            "y": 8
+        },
+        {
+            "state": 1,
+            "x": 6,
+            "y": 8
+        },
+        {
+            "state": 7,
+            "x": 8,
+            "y": 8
+        },
+        {
+            "state": 1,
+            "x": 9,
+            "y": 8
+        },
+        {
+            "state": 1,
+            "x": 10,
+            "y": 8
+        },
+        {
+            "state": 1,
+            "x": 11,
+            "y": 8
+        },
+        {
+            "state": 1,
+            "x": 12,
+            "y": 8
+        },
+        {
+            "state": 1,
+            "x": 13,
+            "y": 8
+        },
+        {
+            "state": 2,
+            "x": 14,
+            "y": 8
+        },
+        {
+            "state": 2,
+            "x": 1,
+            "y": 9
+        },
+        {
+            "state": 2,
+            "x": 2,
+            "y": 9
+        },
+        {
+            "state": 2,
+            "x": 3,
+            "y": 9
+        },
+        {
+            "state": 2,
+            "x": 4,
+            "y": 9
+        },
+        {
+            "state": 2,
+            "x": 5,
+            "y": 9
+        },
+        {
+            "state": 2,
+            "x": 6,
+            "y": 9
+        },
+        {
+            "state": 2,
+            "x": 7,
+            "y": 9
+        },
+        {
+            "state": 2,
+            "x": 8,
+            "y": 9
+        },
+        {
+            "state": 2,
+            "x": 9,
+            "y": 9
+        },
+        {
+            "state": 2,
+            "x": 10,
+            "y": 9
+        },
+        {
+            "state": 2,
+            "x": 11,
+            "y": 9
+        },
+        {
+            "state": 2,
+            "x": 12,
+            "y": 9
+        },
+        {
+            "state": 2,
+            "x": 13,
+            "y": 9
+        }
+    ],
+    "date": "dim. juin 6 2021",
+    "desc": "",
+    "title": "langton"
+}
diff --git a/src/colorlabel.cpp b/src/colorlabel.cpp
index b77792cee23a45af549dbb45c714d593ba47f9f6..5590c8a13d3d4deca975ae98818416c48ab78f6c 100644
--- a/src/colorlabel.cpp
+++ b/src/colorlabel.cpp
@@ -140,3 +140,10 @@ void ColorLabel::pickColor()
     pal.setColor(QPalette::Window, color);
     ui->color_label->setPalette(pal);
 }
+
+void ColorLabel::on_state_label_textEdited(const QString &arg1)
+{
+    state s = a.getState(current_id);
+    a.setState(current_id, state(s.getColor(), arg1.toStdString()));
+    ui->state_list->item(current_id)->setText(arg1);
+}
diff --git a/src/gridview.cpp b/src/gridview.cpp
index 321ab499c50b3571b617c1bae8961640ab1ced6d..5f6d37ccc30da743e8155d81d0eb5665bce2812c 100644
--- a/src/gridview.cpp
+++ b/src/gridview.cpp
@@ -91,7 +91,6 @@ public:
     DragDropHandlerItem(GridView& in_gridview, QGraphicsItem *parent = nullptr)
         : QGraphicsRectItem(0, 0, 1, 1, parent), m_grid_view(in_gridview)
     {
-        setAcceptHoverEvents(true);
         setAcceptDrops(true);
 
         setPen(Qt::NoPen);
@@ -186,8 +185,9 @@ void GridGraphicsView::mousePressEvent(QMouseEvent *event)
         QGraphicsView::mousePressEvent(event);
     }
     else
-
         QGraphicsView::mousePressEvent(event);
+
+    m_gridview.update_current_mouse_pos(coord);
 }
 
 void GridGraphicsView::mouseMoveEvent(QMouseEvent *event)
@@ -196,6 +196,8 @@ void GridGraphicsView::mouseMoveEvent(QMouseEvent *event)
     if (!sceneRect().contains(item_pos) || !sceneRect().contains(mapToScene(m_last_mouse_pos)))
         return;
 
+    Coord coord = Coord{(int)item_pos.x(), (int)item_pos.y()};
+
     if (!m_gridview.in_toggle_mode() && QGuiApplication::keyboardModifiers() == Qt::NoModifier && event->buttons() == Qt::LeftButton)
     {
         draw_bresenham(mapToScene(m_last_mouse_pos), item_pos);
@@ -210,6 +212,7 @@ void GridGraphicsView::mouseMoveEvent(QMouseEvent *event)
         QGraphicsView::mouseMoveEvent(event);
 
     m_last_mouse_pos = event->pos();
+    m_gridview.update_current_mouse_pos(coord);
 }
 
 void GridGraphicsView::drawForeground(QPainter *painter, const QRectF &)
@@ -219,7 +222,7 @@ void GridGraphicsView::drawForeground(QPainter *painter, const QRectF &)
     if (lod < 10)
         return; // trop zoomé, on ne dessine rien
 
-    painter->setPen(QPen(Qt::black, 0)); // cosmetic 1-pixel pen
+    painter->setPen(QPen(Qt::gray, 0)); // cosmetic 1-pixel pen
 
     QVector<QLine> lines;
     // horizontal lines
@@ -297,6 +300,8 @@ GridView::GridView(QWidget *parent)
 
     QGridLayout *layout = new QGridLayout;
     layout->addWidget(m_view);
+    m_mouse_pos_label = new QLabel("");
+    layout->addWidget(m_mouse_pos_label);
     layout->addWidget(new QLabel("Clic gauche : éditer; Clic droit : sélectionner", this));
     layout->addWidget(new QLabel("Maintenir SHIFT pour déplacer la grille; Molette ou CTRL+/CTRL- pour zoomer", this));
     setLayout(layout);
@@ -316,6 +321,7 @@ GridView::GridView(QWidget *parent)
     Alphabet alph(state{stateColor{255, 255, 255}, "Dead"});
     alph.newEtat(state{stateColor{0, 0, 255}, "Alive"});
     set_alphabet(alph);
+    update_current_mouse_pos({0, 0});
 
     connect(m_zoom, &detail::Graphics_view_zoom::zoomed, this, [this]
             {
@@ -447,17 +453,20 @@ void GridView::load_grid(const Grid &grid)
     {
         for (int j = 0; j < (int)m_height; ++j)
         {
-            QColor color = stateColor_to_QColor(m_alph.getState(grid.get_state(Coord{i, j})).getColor());
+            QColor color = stateColor_to_QColor(m_alph.getState(grid.get_state(Coord{i, j}) % m_alph.taille()).getColor());
             m_grid_image.setPixelColor(i, j, color);
+            m_grid.set_cell(Coord{i, j}, grid.get_state(Coord{i, j}) % m_alph.taille());
         }
     }
     m_grid_pixmap.convertFromImage(m_grid_image);
     m_scene->setSceneRect(QRectF(0, 0, m_width, m_height));
     m_drag_drop_handler->setRect(QRectF(0, 0, m_width, m_height));
+    update_current_mouse_pos(m_last_mouse_pos);
 }
 
 void GridView::set_cell_state(Coord pos, unsigned state)
 {
+    state %= m_alph.taille();
     QColor color = stateColor_to_QColor(m_alph.getState(state).getColor());
     m_grid_image.setPixelColor(pos.x, pos.y, color);
     m_grid.set_cell(pos, state);
@@ -553,6 +562,14 @@ void GridView::click_on(Coord coord)
     }
 }
 
+void GridView::update_current_mouse_pos(Coord coord)
+{
+    m_last_mouse_pos = coord;
+    auto state_label = m_alph.getState(m_grid.get_state(coord)).getStateLabel();
+    m_mouse_pos_label->setText(QString("Mouse position : %1,%2 : \"%3\"").arg(coord.x).arg(coord.y).arg(
+        QString::fromStdString(state_label)));
+}
+
 void GridView::paste_structure_at(Coord origin, const Structure &s)
 {
     push_history();
diff --git a/src/interface.cpp b/src/interface.cpp
index d0356f9fc89353f202fd3073d89dd830c6bae548..e54ee3b4d25fce03f3661dbbdcc7b6d867c2dc34 100644
--- a/src/interface.cpp
+++ b/src/interface.cpp
@@ -43,8 +43,7 @@ MainWindow::MainWindow(QWidget *parent)
                 ColorLabel* dialog = new ColorLabel(simulation.getAlphabet(), this);
                 if (dialog->exec())
                 {
-                    simulation.setAlphabet(dialog->getAlphabet());
-                    ui->grid_view->set_alphabet(dialog->getAlphabet());
+                    ui_update_alphabet(dialog->getAlphabet());
                 }
             });
     connect(ui->transition_list, QOverload<int>::of(&QComboBox::currentIndexChanged), this, [this](int)
@@ -66,7 +65,11 @@ MainWindow::MainWindow(QWidget *parent)
 
     ui->struct_library->update_cell_pixel_size(ui->grid_view->cell_screen_size());
 
-    load_model(default_model());
+    if (!try_load_saved_state())
+    {
+        load_model(default_model());
+        load_grid_configuration(default_configuration());
+    }
 
     connect(timer, &QTimer::timeout, this, [this](){
         on_nextButton_clicked();
@@ -94,7 +97,11 @@ void MainWindow::on_simSpeedSlider_valueChanged(int value)
 
 void MainWindow::on_openPatternButton_clicked()
 {
-    load_grid_configuration();
+    ConfigurationLoadingDialog dialog(m_loaded_model.value("title").toString(), this);
+    if (!dialog.exec())
+        return;
+
+    load_grid_configuration(dialog.configuration());
 }
 
 void MainWindow::on_openRuleButton_clicked()
@@ -204,7 +211,8 @@ void MainWindow::on_validateGridDim_clicked()
     }
 
     ui->grid_view->copy_grid(newGrid);
-
+    simulation.reset();
+    simulation.setGrid(newGrid);
     ui->validateGridDim->setEnabled(false);
 }
 
@@ -237,32 +245,6 @@ void MainWindow::on_randomPatternButton_clicked()
     ui->grid_view->copy_grid(newGrid);
 }
 
-void MainWindow::on_nbrStatesComboBox_currentTextChanged(const QString &arg1)
-{
-    // A mettre dans la fonction valider
-    /*
-    // Nombre d'états possibles
-    int val = arg1.toInt();
-    // Nombre de valeurs dans le comboxBox (en partant de 0)
-    int currentNbrValue = ui->nbrStateComboBox->count();
-    // Si on change le nbr d'états
-    if (val != currentNbrValue) {
-        // Si on ajoute des états
-        if (val > currentNbrValue) {
-            for(int i = currentNbrValue; i < val; i++ ) {
-                ui->nbrStateComboBox->addItem(QString::number(i));
-            }
-        }
-        // Si on retire des états
-        else {
-            for(int i = currentNbrValue - 1; i >= val; i-- ) {
-                ui->nbrStateComboBox->removeItem(i);
-            }
-        }
-    }
-    */
-}
-
 void MainWindow::on_drawCellButton_clicked()
 {
     ui->grid_view->fill_selection(ui->nbrStateComboBox->currentIndex());
@@ -327,6 +309,7 @@ void MainWindow::update_neighborhood_settings()
 void MainWindow::enable_rule_customization()
 {
     //ui->simulation_tab->setEnabled(false);
+    ui->savePatternButton->setEnabled(false);
     ui->customize_button->setText("Cancel customization");
     ui->rule_settings->setEnabled(true);
     m_customizing = true;
@@ -335,6 +318,7 @@ void MainWindow::enable_rule_customization()
 void MainWindow::disable_rule_customization()
 {
     //ui->simulation_tab->setEnabled(true);
+    ui->savePatternButton->setEnabled(true);
     ui->customize_button->setEnabled(true);
     ui->rule_settings->setEnabled(false);
     ui->customize_button->setText("Customize...");
@@ -400,13 +384,11 @@ void MainWindow::load_model(const QJsonObject &obj)
             prop->accept(visit);
     }
 
-    ui_update_alphabet(alpha);
-
     // On transfère la propriété de ces pointeurs vers Simulation, qui en est désormais propriétaire pour l'exécution de l'automate
     simulation.setNeighborhoodRule(m_neighborhood_rule);
     simulation.setTransitionRule(m_transition_rule);
-    simulation.setAlphabet(alpha);
-    ui->grid_view->set_alphabet(alpha);
+    simulation.reset();
+    ui_update_alphabet(alpha);
 
     m_loaded_model = obj;
 }
@@ -516,12 +498,40 @@ void MainWindow::load_from_image()
 
 void MainWindow::ui_update_alphabet(const Alphabet &alpha)
 {
+    simulation.setAlphabet(alpha);
     ui->grid_view->set_alphabet(alpha);
     ui->nbrStateComboBox->clear();
-    std::cout << alpha.taille() << endl;
-    fflush(stdout);
     for (unsigned i = 0; i < alpha.taille(); ++i)
+    {
         ui->nbrStateComboBox->addItem(QString::number(i));
+    }
+}
+
+bool MainWindow::try_load_saved_state()
+{
+    QFile file("saved_state.json");
+    if (!file.open(QFile::ReadOnly | QFile::Text))
+    {
+        return false;
+    }
+    QTextStream in(&file);
+
+    QJsonParseError parseError;
+    QJsonDocument jsonDoc = QJsonDocument::fromJson(in.readAll().toUtf8(), &parseError);
+    if(parseError.error != QJsonParseError::NoError)
+    {
+        return false;
+    }
+    QJsonObject data = jsonDoc.object();
+    QJsonObject model = data.value("model").toObject();
+    QJsonObject config = data.value("config").toObject();
+    if (model.isEmpty() || config.isEmpty())
+        return false;
+
+    load_model(model);
+    load_grid_configuration(config);
+
+    return true;
 }
 
 void MainWindow::save_grid_configuration()
@@ -561,25 +571,23 @@ void MainWindow::save_grid_configuration()
     file.close();
 }
 
-void MainWindow::load_grid_configuration()
+void MainWindow::load_grid_configuration(const QJsonObject& configuration)
 {
-    ConfigurationLoadingDialog dialog(m_loaded_model.value("title").toString(), this);
-    if (!dialog.exec())
-        return;
-
-    Grid g(dialog.configuration().value("width").toInt(10),
-           dialog.configuration().value("height").toInt(10));
+    Grid g(configuration.value("width").toInt(10),
+           configuration.value("height").toInt(10));
     Coord origin;
-    origin.x = dialog.configuration().value("left").toInt(0);
-    origin.y = dialog.configuration().value("top").toInt(0);
+    origin.x = configuration.value("left").toInt(0);
+    origin.y = configuration.value("top").toInt(0);
 
-    RLEStructureReader reader(dialog.configuration().value("data").toString().toStdString());
+    RLEStructureReader reader(configuration.value("data").toString().toStdString());
     Structure s = reader.read_structure();
 
     ui->grid_view->copy_grid(g);
     ui->grid_view->paste_structure_at(origin, s);
     ui->widthSpinBox->setValue(g.get_col());
     ui->heightSpinBox->setValue(g.get_rows());
+    simulation.reset();
+    simulation.setGrid(g);
 }
 
 QJsonObject MainWindow::default_model() const
@@ -602,6 +610,63 @@ QJsonObject MainWindow::default_model() const
     return doc.object();
 }
 
+QJsonObject MainWindow::default_configuration() const
+{
+    const char* json = R"(
+    {
+    "data": "x = 2, y = 2\n!",
+    "height": 50,
+    "left": 0,
+    "model": "Game of Life",
+    "title": "Game of Life Default",
+    "top": 0,
+    "width": 50
+    }
+)";
+
+    QJsonDocument doc = QJsonDocument::fromJson(QByteArray(json));
+
+    return doc.object();
+}
+
+void MainWindow::closeEvent(QCloseEvent *e)
+{
+    // Sauvegarder l'état actuel de l'application
+
+    const Grid& grid = ui->grid_view->get_grid();
+    Structure grid_data = grid.to_structure();
+
+    RLEStructureWriter writer;
+    std::string structure_data = writer.save_structure(grid_data);
+
+    QJsonObject config_data;
+    config_data["width"] = (int)grid.get_col();
+    config_data["height"] = (int)grid.get_rows();
+    config_data["title"] = "Saved configuration";
+    config_data["model"] = m_loaded_model.value("title");
+    config_data["left"] = grid_data.top_left.x;
+    config_data["top"] = grid_data.top_left.y;
+    config_data["data"] = QString::fromStdString(structure_data);
+
+    QJsonObject model = m_loaded_model;
+
+    QJsonObject save_data;
+    save_data["config"] = config_data;
+    save_data["model"] = model;
+
+    QFile file("saved_state.json");
+    if (!file.open(QIODevice::WriteOnly | QFile::Text | QFile::Truncate))
+    {
+        return;
+    }
+
+    QJsonDocument doc(save_data);
+    file.write(doc.toJson());
+    file.close();
+
+    QMainWindow::closeEvent(e);
+}
+
 void MainWindow::on_saveRuleButton_clicked()
 {
     save_model();
diff --git a/src/neighborhoodDialog.cpp b/src/neighborhoodDialog.cpp
index 0e708b3538a4e2a5fdde97255e163ad7ed179500..2a54147d79f50dad457e64cd6b263e3cf5b58e58 100644
--- a/src/neighborhoodDialog.cpp
+++ b/src/neighborhoodDialog.cpp
@@ -4,7 +4,7 @@
 #include <QDate>
 #include <QMessageBox>
 
-NeighborhoodDialog::NeighborhoodDialog(QWidget *parent) :
+NeighborhoodDialog::NeighborhoodDialog(Neighborhood& n, QWidget *parent) :
       QDialog(parent), ui(new Ui::NeighborhoodDialog)
 {
     ui->setupUi(this);
@@ -23,44 +23,63 @@ NeighborhoodDialog::NeighborhoodDialog(QWidget *parent) :
 
     gv.set_alphabet(a);
 
+    // Initialisation taille de la grille
+    int xMax = 11;
+    int yMax = 11;
+    int nbrVoisins = n.size();
 
-    QSize size = gv.grid_size();
-    currentPoint = {size.width() / 2, size.height() / 2};
-    Grid newGrid(gv.get_grid());
-    newGrid.set_cell(currentPoint, 2);
-    gv.copy_grid(newGrid);
-    gv.enable_toggle_mode(1, 0);
-    // TODO le clic sur la cellule centrale
-}
+    for(int i = 0; i < nbrVoisins; i++) {
+        int currentX = n.neighbor_at_index(i).first.x;
+        int currentY = n.neighbor_at_index(i).first.y;
+        if(abs(currentX) >= xMax /2) xMax = (abs(currentX)+1) * 2;
+        if(abs(currentY) >= yMax /2) yMax = (abs(currentY)+1) * 2;
+    }
 
-NeighborhoodDialog::~NeighborhoodDialog()
-{
-    delete ui;
+    std::cout << "xMax =" << xMax << " yMax=" << yMax << endl;
+
+    ui->widthSpinBox_2->setValue(xMax);
+    ui->heightSpinBox_2->setValue(yMax);
+    ResizeCreateGrid(xMax, yMax, n);
+    gv.enable_toggle_mode(1, 0);
+    gv.add_toggle_rule(3, 2);
 }
 
-void NeighborhoodDialog::done(int r)
+void NeighborhoodDialog::ResizeCreateGrid(int x, int y, Neighborhood& n)
 {
-    if(QDialog::Accepted == r)  // ok was pressed
-    {
+    GridView& gv = *(*ui).grid_view;
+    int nbrVoisins = n.size();
 
+    Grid newGrid(y, x);
+    currentPoint = {x/ 2, y / 2};
+    newGrid.set_cell(currentPoint, 2);
+    for(int i = 0; i < nbrVoisins; i++) {
+        Coord newNeighborRelative = n.neighbor_at_index(i).first;
+        if(newNeighborRelative == Coord {0, 0}) {
+            newGrid.set_cell(currentPoint, 3);
+        }
+        else {
+            Coord newNeighborAbsolute = {currentPoint.x + newNeighborRelative.x, currentPoint.y + newNeighborRelative.y};
+            if( (newNeighborAbsolute.x < x && newNeighborAbsolute.y < y) &&
+                    (newNeighborAbsolute.x >= 0 && newNeighborAbsolute.y >= 0)) {
+                newGrid.set_cell(newNeighborAbsolute, 1);
+            }
+        }
     }
-    else    // cancel, close or exc was pressed
-    {
-        QDialog::done(r);
-        return;
-    }
+    gv.copy_grid(newGrid);
 }
 
-Neighborhood* NeighborhoodDialog::getVoisinage() const
+NeighborhoodDialog::~NeighborhoodDialog()
 {
-    return nullptr;
+    delete ui;
 }
 
-GridView& NeighborhoodDialog::getGridView() const{
-    return *(ui->grid_view);
+void NeighborhoodDialog::done(int r)
+{
+    QDialog::done(r);
+    return;
 }
 
-Neighborhood& NeighborhoodDialog::getNeighborhood() const
+Neighborhood* NeighborhoodDialog::getNeighborhood() const
 {
     Neighborhood* newNeighborhood = new Neighborhood;
     Grid currentGrid = ui->grid_view->get_grid();
@@ -69,7 +88,7 @@ Neighborhood& NeighborhoodDialog::getNeighborhood() const
     int width = currentSizeGrid.width();
     for(int j = 0; j < height ; j++) {
         for(int i = 0; i < width ; i++) {
-            if( currentGrid.get_state({i,j}) == 1) {
+            if( currentGrid.get_state({i,j}) == 1 || currentGrid.get_state({i,j}) == 3) {
                 Coord newCoord = {i - currentPoint.x, j - currentPoint.y};
                 newNeighborhood->addNeighbor(newCoord, 1);
                 std::cout << "Nouveau voisin : X=" << newCoord.x << " Y=" << newCoord.y << endl;
@@ -77,5 +96,64 @@ Neighborhood& NeighborhoodDialog::getNeighborhood() const
             }
         }
     }
-    return *newNeighborhood;
+    return newNeighborhood;
+}
+
+void NeighborhoodDialog::on_validateGridDim_2_clicked()
+{
+    Grid oldGrid = ui->grid_view->get_grid();
+
+    unsigned int nbrRow = ui->heightSpinBox_2->value(); // nbr de lignes => axe y
+    unsigned int nbrCol = ui->widthSpinBox_2->value(); // nbr de colonne => axe x
+    Grid newGrid(nbrCol, nbrRow);
+
+    Neighborhood* oldNeighborhood = this->getNeighborhood();
+
+    ResizeCreateGrid(nbrCol, nbrRow, *oldNeighborhood);
+
+    ui->validateGridDim_2->setEnabled(false);
+
+    delete oldNeighborhood;
+
+    /*
+    unsigned oldNbrRow = oldGrid.get_rows(); // rows = nbr de lignes => axe y
+    unsigned oldNbrCol = oldGrid.get_col(); // col = nbr de colonne => axe x
+
+    if(oldNbrRow <= nbrRow && oldNbrCol <= nbrCol) {
+        //std::cout << "superieur\n";
+        fflush(stdout);
+        for (unsigned y = 0; y < oldNbrRow ; y++) {
+            for (unsigned x = 0; x < oldNbrCol ; x++) {
+                Coord pos = {static_cast<int>(x), static_cast<int>(y)};
+                newGrid.set_cell(pos, oldGrid.get_state(pos));
+                //std::cout << "oldState : " << oldGrid.get_state(pos) << endl;
+            }
+        }
+    }
+    else
+    {
+        //std::cout << "superieur\n";
+        fflush(stdout);
+        for (unsigned y = 0; y < nbrRow ; y++) {
+            for (unsigned x = 0; x < nbrCol ; x++) {
+                Coord pos = {static_cast<int>(x), static_cast<int>(y)};
+                newGrid.set_cell(pos, oldGrid.get_state(pos));
+                //std::cout << "oldState : " << oldGrid.get_state(pos) << endl;
+            }
+        }
+    }
+
+    ui->grid_view->copy_grid(newGrid);
+    ui->validateGridDim_2->setEnabled(false);
+    */
+}
+
+void NeighborhoodDialog::on_heightSpinBox_2_valueChanged(int)
+{
+    ui->validateGridDim_2->setEnabled(true);
+}
+
+void NeighborhoodDialog::on_widthSpinBox_2_valueChanged(int)
+{
+    ui->validateGridDim_2->setEnabled(true);
 }
diff --git a/src/neighborhood_rules/mooreNeighborhoodRule.cpp b/src/neighborhood_rules/mooreNeighborhoodRule.cpp
index 35fe0f16ee885e819656bbd7c2eef05d02848c59..c894c7aa18bed5ec2cac947c9090b004daac4ead 100644
--- a/src/neighborhood_rules/mooreNeighborhoodRule.cpp
+++ b/src/neighborhood_rules/mooreNeighborhoodRule.cpp
@@ -4,26 +4,19 @@ REGISTER_FACTORY_ENTRY(NeighborhoodRule, mooreNeighborhoodRule, "Moore");
 
 mooreNeighborhoodRule::mooreNeighborhoodRule(int _radius)
 {
-    radius.val = _radius;
+    current_format_radius = radius.val = _radius;
 
     if(_radius == 0)
         throw NeighborhoodException("Le rayon ne peut pas être égal à 0");
-    // Les coordonnées sont copiées dans le vecteur
-    // N(i,j) = {(k, l)|abs(k−i) ≤ r et abs(l−j) ≤ r} ;
-    Coord newCord;
-    for(int i = -_radius; i <= _radius; i++){
-        for(int j = -_radius; j <= _radius; j++){
-            newCord.x = i;
-            newCord.y = j;
-            if(!(newCord.x == 0 && newCord.y == 0)) {
-                format.positions.push_back(newCord);
-            }
-        }
-    }
+
+    update_format();
 }
 
 Neighborhood mooreNeighborhoodRule::getNeighborhood(const Grid& grid, Coord pos) const
 {
+    if (current_format_radius != radius.val)
+        update_format();
+
     Neighborhood newNeighborhood;
     // Coordonnées des voisins dans la grille
     Coord gridCoord;
@@ -40,8 +33,31 @@ Neighborhood mooreNeighborhoodRule::getNeighborhood(const Grid& grid, Coord pos)
 
 std::vector<NeighborhoodFormat> mooreNeighborhoodRule::getFormats() const
 {
+    if (current_format_radius != radius.val)
+        update_format();
+
     std::vector<NeighborhoodFormat> vector;
     vector.push_back(format);
     return vector;
 }
 
+void mooreNeighborhoodRule::update_format() const
+{
+    format.positions.clear();
+
+    // Les coordonnées sont copiées dans le vecteur
+    // N(i,j) = {(k, l)|abs(k−i) ≤ r et abs(l−j) ≤ r} ;
+    Coord newCord;
+    for(int i = -radius.val; i <= radius.val; i++){
+        for(int j = -radius.val; j <= radius.val; j++){
+            newCord.x = i;
+            newCord.y = j;
+            if(!(newCord.x == 0 && newCord.y == 0)) {
+                format.positions.push_back(newCord);
+            }
+        }
+    }
+
+    current_format_radius = radius.val;
+}
+
diff --git a/src/neighborhood_rules/vonNeumannNeighborhoodRule.cpp b/src/neighborhood_rules/vonNeumannNeighborhoodRule.cpp
index 59ce07087a79c59b172d59fd1fcc2577fb992875..2fbe3e5e7f45eb3a4ebe600d8182c204cfcfc67e 100644
--- a/src/neighborhood_rules/vonNeumannNeighborhoodRule.cpp
+++ b/src/neighborhood_rules/vonNeumannNeighborhoodRule.cpp
@@ -4,29 +4,19 @@ REGISTER_FACTORY_ENTRY(NeighborhoodRule, vonNeumannNeighborhoodRule, "Von Neuman
 
 vonNeumannNeighborhoodRule::vonNeumannNeighborhoodRule(int _radius)
 {
-    radius.val = _radius;
+    current_format_radius = radius.val = _radius;
 
     if(_radius == 0)
         throw NeighborhoodException("Le rayon ne peut pas être égal à 0");
-    // Les coordonnées sont copiées dans le vecteur
-    // J'ai repris l'implémentation du voisinage de Moore, sauf que les cellules qui ne respectent pas la formule sont exclues
-    // N(i,j) = {(k, l)|abs(k − i) + abs(l − j) ≤ r}
-    Coord newCord;
-    for(int i = -_radius; i <= _radius; i++){
-        for(int j = -_radius; j <= _radius; j++){
-            if( abs(i+j) <= _radius) {
-                newCord.x = i;
-                newCord.y = j;
-                if(!(newCord.x == 0 && newCord.y == 0)) {
-                    format.positions.push_back(newCord);
-                }
-            }
-        }
-    }
+
+    update_format();
 }
 
 Neighborhood vonNeumannNeighborhoodRule::getNeighborhood(const Grid& grid, Coord pos) const
 {
+    if (current_format_radius != radius.val)
+        update_format();
+
     Neighborhood newNeighborhood;
     // Coordonnées des voisins dans la grille
     Coord gridCoord;
@@ -43,8 +33,30 @@ Neighborhood vonNeumannNeighborhoodRule::getNeighborhood(const Grid& grid, Coord
 
 std::vector<NeighborhoodFormat> vonNeumannNeighborhoodRule::getFormats() const
 {
+    if (current_format_radius != radius.val)
+        update_format();
+
     std::vector<NeighborhoodFormat> vector;
     vector.push_back(format);
     return vector;
 }
 
+void vonNeumannNeighborhoodRule::update_format() const
+{
+    // Les coordonnées sont copiées dans le vecteur
+    // J'ai repris l'implémentation du voisinage de Moore, sauf que les cellules qui ne respectent pas la formule sont exclues
+    // N(i,j) = {(k, l)|abs(k − i) + abs(l − j) ≤ r}
+    Coord newCord;
+    for(int i = -radius.val; i <= radius.val; i++){
+        for(int j = -radius.val; j <= radius.val; j++){
+            if((abs(i) + abs(j)) <= radius.val) {
+                newCord.x = i;
+                newCord.y = j;
+                if(!(newCord.x == 0 && newCord.y == 0)) {
+                    format.positions.push_back(newCord);
+                }
+            }
+        }
+    }
+}
+
diff --git a/src/simulation.cpp b/src/simulation.cpp
index f72ac6f2117c060db5104b002b88df84cbeb2612..acc836b6532a5bd43726c8a41b813b9126f0674e 100644
--- a/src/simulation.cpp
+++ b/src/simulation.cpp
@@ -58,7 +58,7 @@ void Simulation::resize(size_t l,size_t c) {
     reset();
 }*/
 
-void Simulation::reset() {
+    void Simulation::reset() {
     automaton.setGrid(startGrid);
     time = 0;
     period = 0;
@@ -69,10 +69,10 @@ void Simulation::step() {
     if(!canRun) {
         return;
     }
+    ++time;
     hist.pushGrid(automaton.getGrid());
     automaton.runOnce();
-    automaton.getNeighborhoodRule()->step();
-    ++time;
+    automaton.getNeighborhoodRule()->update_generation(time);
     if(!period && startGrid == automaton.getGrid()) {
         period = time;
     }
@@ -81,10 +81,10 @@ void Simulation::step() {
 bool Simulation::back() {
     bool r=false;
     if(!hist.isEmpty()) {
+        --time;
         automaton.setGrid(hist.topGrid());
-        //automaton.getNeighborhoodRule()->back();
+        automaton.getNeighborhoodRule()->update_generation(time);
         hist.popGrid();
-        --time;
         r=true;
     }
     return r;
diff --git a/src/structurereader.cpp b/src/structurereader.cpp
index 20338b4b52e5e41bec4afbec49a68070c9c7fc2b..9420418a99f5f935341044cbc5341a7012b60eca 100644
--- a/src/structurereader.cpp
+++ b/src/structurereader.cpp
@@ -111,7 +111,7 @@ void StructureReader::read_white()
 unsigned RLEStructureReader::read_state()
 {
     char char_1 = read();
-    if (char_1 == 'b' || char_1 == 'B' || char_1 == '.')
+    if (char_1 == 'b' || char_1 == '.')
         return 0;
     else if (char_1 == 'o')
         return 1;
@@ -130,6 +130,7 @@ unsigned RLEStructureReader::read_state()
 void RLEStructureReader::read_comment_line(Structure &s)
 {
     std::string tag = read_word();
+    read_white();
     std::string line = read_line();
     if (tag == "C" || tag == "c")
     {
diff --git a/src/uibuildervisitor.cpp b/src/uibuildervisitor.cpp
index 44ba4ee15931d33a84684a84943058126182785e..8529205f5cdee278461ec256d509efaca7aafcd7 100644
--- a/src/uibuildervisitor.cpp
+++ b/src/uibuildervisitor.cpp
@@ -1,6 +1,6 @@
 #include "propertyvisitors.hpp"
 
-#include "neighborhoodDialog.hpp"
+
 
 #include <QGroupBox>
 #include <QPushButton>
@@ -185,19 +185,21 @@ void UIBuilderVisitor::visit(PropertyList &list)
                                      add_button->setEnabled(true);
                              }
                          });
-        QObject::connect(widgetGridNeighborhoodButton, &QPushButton::pressed, [&list]() {
-            NeighborhoodDialog* nw = new NeighborhoodDialog;
-            nw->exec();
-            /*
-            QObject::connect(validateButton, &QPushButton::pressed, [&list, &nw] () {
-                list.clear();
-                Neighborhood newNeighborhood = nw->getNeighborhood();
-                // TODO a finir
-                list.push_back();
-
-            });*/
-            // QObject::connect(validateButton, &QPushButton::pressed, nw, &QDialog::done );
+        QObject::connect(widgetGridNeighborhoodButton, &QPushButton::pressed, [this, &list, list_widget]() {
+            Neighborhood currentNeighborhood = list.to_neighborhood();
+            neighborhoodDialog = new NeighborhoodDialog(currentNeighborhood);
 
+            if( neighborhoodDialog->exec() ) {
+                std::cout << "sacreubleu" << endl;
+                fflush(stdout);
+                list.clear();
+                Neighborhood* newNeighborhood = neighborhoodDialog->getNeighborhood();
+                list.load_from_neighborhood(*newNeighborhood);
+                delete newNeighborhood;
+                UIBuilderVisitor visit(list_widget);
+                for (const auto& ptr : list.contents)
+                    ptr->accept(visit);
+            }
         });
     }
 }
diff --git a/tests/mooreNeighborhoodRule_test.cpp b/tests/mooreNeighborhoodRule_test.cpp
index 9dd3ff7ac8ec374fc7adaec599612cae517d2379..7e528f683d63f85021d50f96c3e3f92357e7f34c 100644
--- a/tests/mooreNeighborhoodRule_test.cpp
+++ b/tests/mooreNeighborhoodRule_test.cpp
@@ -3,6 +3,7 @@
 #include "cellulut_tests.hpp"
 
 #include "mooreNeighborhoodRule.hpp"
+#include "propertyvisitors.hpp"
 
 void CellulutTests::test_mooreNeighborhoodRule() {
 
@@ -19,7 +20,7 @@ void CellulutTests::test_mooreNeighborhoodRule() {
     Coord pos8={5,3};
     Coord pos9={3,5};
     Coord pos10={7,7};
-    Coord pos11={4,4};
+    Coord pos11={4,3};
     Coord pos12={6,7};
     Coord pos13={7,6};
     Coord pos14={3,6};
@@ -41,10 +42,15 @@ void CellulutTests::test_mooreNeighborhoodRule() {
     g.set_cell(pos13,4);
     g.set_cell(pos14,2);
 
+    // Tester que le chargement des propriétés depuis un JSON fonctionne bien
+    QJsonObject obj;
+    obj["radius"] = 2;
 
+    mooreNeighborhoodRule newMoore(1);
+    PropertyLoaderVisitor visit(obj);
+    for (auto& prop : newMoore.get_properties())
+        prop->accept(visit);
 
-
-    mooreNeighborhoodRule newMoore(2);
     Neighborhood v=newMoore.getNeighborhood(g,cellule);
     unsigned int nb_voi=v.getNb(3);
     unsigned int nb_voi2=v.getNb(5);
diff --git a/tests/structurewriter_tests.cpp b/tests/structurewriter_tests.cpp
index 295f8903522a3e767ec45c991be1a312d5ad80cd..32e38662d929aa8871e3693d439316e98a52d365 100644
--- a/tests/structurewriter_tests.cpp
+++ b/tests/structurewriter_tests.cpp
@@ -54,6 +54,42 @@ void CellulutTests::test_rle_structurewriter()
         fprintf(stderr, "Error is %s\n", ex.what());
         QFAIL("Exception thrown");
     }
+
+    std::vector<std::pair<Coord, unsigned>> coords;
+    coords.push_back({{0, 0}, 3});
+    coords.push_back({{1, 2}, 1});
+    coords.push_back({{5, 8}, 5});
+    coords.push_back({{1, 3}, 2});
+    coords.push_back({{5, 6}, 6});
+    coords.push_back({{3, 7}, 7});
+
+    try
+    {
+        Structure s{coords.begin(), coords.end()};
+        s.author = "Bob";
+        s.title = "Foo";
+        s.date = "28/07/2001";
+        s.desc = "Lorem ipsum";
+
+        RLEStructureWriter writer;
+        auto out = writer.save_structure(s);
+
+        //printf("%s\n", out.c_str());
+
+        RLEStructureReader reader(out);
+        Structure struct_out = reader.read_structure();
+
+        QVERIFY(std::is_permutation(struct_out.begin(), struct_out.end(), coords.begin()));
+        //QCOMPARE(struct_out.author, s.author);
+        //QCOMPARE(struct_out.date, s.date);
+        QCOMPARE(struct_out.desc, s.desc);
+        QCOMPARE(struct_out.title, s.title);
+    }
+    catch (const std::exception& ex)
+    {
+        fprintf(stderr, "Error is %s\n", ex.what());
+        QFAIL("Exception thrown");
+    }
 }
 
 void CellulutTests::test_json_structurewriter()