Commit accff21e authored by Yann Boucher's avatar Yann Boucher
Browse files

Implemented the basis for dynamic configuration of transition and neighborhood rules

parent 4ea831f3
Pipeline #78347 passed with stages
in 17 seconds
......@@ -283,6 +283,19 @@ pattern recorded :</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QSpinBox" name="widthSpinBox">
<property name="minimum">
<number>1</number>
</property>
<property name="maximum">
<number>9999</number>
</property>
<property name="value">
<number>10</number>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="heightLabel">
<property name="text">
......@@ -293,16 +306,6 @@ pattern recorded :</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QPushButton" name="validateGridDim">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>OK</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QSpinBox" name="heightSpinBox">
<property name="minimum">
......@@ -316,16 +319,13 @@ pattern recorded :</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QSpinBox" name="widthSpinBox">
<property name="minimum">
<number>1</number>
</property>
<property name="maximum">
<number>9999</number>
<item row="2" column="1">
<widget class="QPushButton" name="validateGridDim">
<property name="enabled">
<bool>false</bool>
</property>
<property name="value">
<number>10</number>
<property name="text">
<string>OK</string>
</property>
</widget>
</item>
......@@ -411,30 +411,15 @@ pattern recorded :</string>
<string>Neighborhood :</string>
</property>
<property name="buddy">
<cstring>neighborhoodComboBox</cstring>
<cstring>neighborhood_list</cstring>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QComboBox" name="neighborhoodComboBox">
<widget class="QComboBox" name="neighborhood_list">
<property name="currentIndex">
<number>0</number>
</property>
<item>
<property name="text">
<string>Von Neumann</string>
</property>
</item>
<item>
<property name="text">
<string>Moore</string>
<number>-1</number>
</property>
</item>
<item>
<property name="text">
<string>Custom</string>
</property>
</item>
</widget>
</item>
<item row="0" column="2">
......@@ -522,18 +507,26 @@ pattern recorded :</string>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QLabel" name="transitionFunctionLabel">
<property name="text">
<string>Transition function :</string>
</property>
<property name="buddy">
<cstring>transitionFunctionTextEdit</cstring>
</property>
</widget>
</item>
<item>
<widget class="QPlainTextEdit" name="transitionFunctionTextEdit"/>
<widget class="QComboBox" name="transition_list"/>
</item>
</layout>
</item>
<item>
<widget class="QGroupBox" name="rule_settings_area">
<property name="title">
<string>Transition rule settings</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="informationLabel">
......
......@@ -20,7 +20,7 @@ Fichier contenant la class singleton template Factory, à qui on peut associer d
namespace detail
{
template <typename _Base, typename Child>
bool register_to_factory();
bool register_to_factory(const char* name);
}
/**
......@@ -33,7 +33,7 @@ template <typename Base>
class Factory
{
template <typename _Base, typename Child>
friend bool detail::register_to_factory();
friend bool detail::register_to_factory(const char* name);
public:
//! \brief Retourne un objet créé à partir de choice
......@@ -70,9 +70,9 @@ private:
}
template <typename Child>
bool register_child()
bool register_child(const char* name)
{
child_register[Child::name()] = []() -> std::unique_ptr<Base>{ return std::make_unique<Child>(); };
child_register[name] = []() -> std::unique_ptr<Base>{ return std::make_unique<Child>(); };
return true;
}
......@@ -86,21 +86,21 @@ private:
//! \param child Le type de classe dérivée de base que la fabrique devra pouvoir construire.
//! Ajoute la classe child à la liste des objets fabriquables par Factory<base>.
//! Le nom de la classe tel que considéré par factory est obtenu par un appel à Child::name(), il est donc nécéssaire que l'enfant possède une méthode statique de signature 'static std::string name()'.
#define REGISTER_FACTORY_ENTRY(base, child) \
#define REGISTER_FACTORY_ENTRY(base, child, name) \
namespace detail { \
/* nécéssaire pour que la transition soit enregistrée parmis la liste de classes de transitions*/ \
/* variable globale static permettant seulement de forcer l'enregistrement d'une telle classe dans la factory, 'static' permettant l'instantiation de cette variable dans des fichiers .cpp différents lors de l'inclusion*/ \
static bool const fact_##base##_##child##_registered = register_to_factory<base, child>(); \
static bool const fact_##base##_##child##_registered = register_to_factory<base, child>(name); \
}
//! \internal namespace contenant les détails d'implémentation de Factory
namespace detail
{
template <typename Base, typename Child>
inline bool register_to_factory()
inline bool register_to_factory(const char* name)
{
static_assert (std::is_base_of<Base, Child>::value, "Le type Child doit être dérivé de Base");
return Factory<Base>::get().template register_child<Child>();
return Factory<Base>::get().template register_child<Child>(name);
}
}
......
......@@ -37,7 +37,7 @@ private slots:
void on_openRuleButton_clicked();
//! \brief Envoie un signal lors du changement de voisinage. Lorsque Custom est sélectionné, le bouton "Custom Neighborhood" est actif
void on_neighborhoodComboBox_currentTextChanged(const QString &arg1);
void on_neighborhood_list_currentTextChanged(const QString &arg1);
//! \brief Envoie le signal que la dimension de la grille a été modifié
void on_validateGridDim_clicked();
......@@ -64,6 +64,13 @@ private slots:
//! \brief Copie la structure choisie dans la bibliothèque dans le presse-papier du GridView
void copy_structure_clicked(const Structure& s);
private:
//! \brief Initialiser la liste des transitions et voisinages disponibles
void init_transition_neighborhood_list();
//! \brief Mets à jour le widget contenant les paramètres pour la règle de transition choisie
void update_transition_settings();
private:
Ui::MainWindow *ui;
};
......
......@@ -14,16 +14,16 @@ Représente un voisinage arbitraire, défini par l'utilisateur.
#include "neighborhoodrule.hpp"
#include "property.hpp"
class ArbitraryNeighborhoodRule : public HasUserProperties
class ArbitraryNeighborhoodRule : public NeighborhoodRule, public HasUserProperties
{
public:
virtual Neighborhood getNeighborhood(const Grid& grid, Coord pos) const;
Neighborhood getNeighborhood(const Grid& grid, Coord pos) const override;
virtual std::vector<NeighborhoodFormat> getFormats() const;
std::vector<NeighborhoodFormat> getFormats() const override;
public:
DEFINE_CONFIGURABLE_DYNLIST (CoordinateProperty, neighbors, "neighbors", ());
};
REGISTER_FACTORY_ENTRY(NeighborhoodRule, ArbitraryNeighborhoodRule, "Arbitrary");
#endif // ARBITRARYNEIGHBORHOODRULE_HPP
......@@ -29,5 +29,6 @@ public:
//! \return Retourne les formats de voisinage possible dans un std::vector.
std::vector<NeighborhoodFormat> getFormats() const;
};
REGISTER_FACTORY_ENTRY(NeighborhoodRule, mooreNeighborhoodRule, "Moore");
#endif // MOORENEIGHBOURHOODRULE_HPP
......@@ -30,5 +30,6 @@ public:
//! \return Retourne les formats de voisinage possible dans un std::vector.
std::vector<NeighborhoodFormat> getFormats() const;
};
REGISTER_FACTORY_ENTRY(NeighborhoodRule, vonNeumannNeighborhoodRule, "Von Neumann");
#endif // VONNEUMANNNEIGHBORHOODRULE_HPP
......@@ -18,6 +18,7 @@ Cette classe peut aussi fournir l'ensemble des positions de voisins qu'elle peut
#include "coord.hpp"
#include "grid.h"
#include "neighborhood.hpp"
#include "factory.hpp"
/**
\struct NeighborhoodFormat
......
......@@ -3,28 +3,19 @@
#include "transitionrule.hpp"
#include "property.hpp"
// http://joatdev.fr/CyclicAutomaton
class CircularTransition : public TransitionRule, public HasUserProperties
class CircularTransition : public TransitionRule
{
public:
bool acceptFormat(const std::vector<NeighborhoodFormat>&) const override
{ return true; }
unsigned getState(unsigned cell, const Neighborhood& neighborhood) const override
{
unsigned next_state = (cell+1) % states.val;
unsigned next_state_neighbors = neighborhood.getNb(next_state);
if ((int)next_state_neighbors >= thresold.val)
return next_state;
else
return cell;
}
unsigned getState(unsigned cell, const Neighborhood& neighborhood) const override;
private:
DEFINE_CONFIGURABLE_PROPERTY(IntegerProperty, states, "Nombre d'états", 1);
DEFINE_CONFIGURABLE_PROPERTY(IntegerProperty, thresold, "Seuil");
};
REGISTER_FACTORY_ENTRY(TransitionRule, CircularTransition, "Circular");
#endif // CIRCULARTRANSITION_HPP
......@@ -3,12 +3,13 @@
#include "transitionrule.hpp"
class LifeGameTransition : TransitionRule
class LifeGameTransition : public TransitionRule
{
public:
LifeGameTransition();
bool acceptFormat(const std::vector<NeighborhoodFormat>&) const;
unsigned int getState(unsigned int, const Neighborhood &) const;
};
REGISTER_FACTORY_ENTRY(TransitionRule, LifeGameTransition, "Game of Life");
#endif // LIFEGAMETRANSITION_H
......@@ -12,10 +12,12 @@ Cette classe représente une règle de transition.
#include <vector>
#include "coord.hpp"
#include "neighborhood.hpp"
#include "factory.hpp"
#include "property.hpp"
struct NeighborhoodFormat;
class TransitionRule {
class TransitionRule : public HasUserProperties {
private:
......
......@@ -2,8 +2,11 @@
#include "ui_interface.h"
#include "structuresavingdialog.hpp"
#include "structurewriter.hpp"
#include "factory.hpp"
#include "transitionrule.hpp"
#include "neighborhoodrule.hpp"
#include "propertyvisitors.hpp"
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
......@@ -11,9 +14,14 @@ MainWindow::MainWindow(QWidget *parent)
{
ui->setupUi(this);
init_transition_neighborhood_list();
update_transition_settings();
connect(ui->action_save_struct, &QAction::triggered, this, &MainWindow::afficher_interface_sauvegarde_structure);
connect(ui->struct_library, &StructureLibraryView::structure_copied, this, &MainWindow::copy_structure_clicked);
connect(ui->grid_view, &GridView::zoom_changed, ui->struct_library, &StructureLibraryView::update_cell_pixel_size);
connect(ui->transition_list, QOverload<int>::of(&QComboBox::currentIndexChanged), this, [this](int)
{ update_transition_settings(); });
ui->struct_library->update_cell_pixel_size(ui->grid_view->cell_pixel_size());
}
......@@ -53,19 +61,15 @@ void MainWindow::on_openRuleButton_clicked()
// Indiquer qu'une nouvelle règle vient d'être ouverte. La règle est sauvegardé, donc on peut lancer la simulation
}
void MainWindow::on_neighborhoodComboBox_currentTextChanged(const QString &arg1)
void MainWindow::on_neighborhood_list_currentTextChanged(const QString &arg1)
{
if(arg1 == "Von Neumann"){
ui->cusumNeighborhoodButton->setEnabled(false);
// Utiliser la règle de voisinage VonNeumann
}
if(arg1 == "Moore"){
ui->cusumNeighborhoodButton->setEnabled(false);
// Utiliser la règle de voisinage Moore
}
if(arg1 == "Custom"){
ui->cusumNeighborhoodButton->setEnabled(true);
}
else
{
ui->cusumNeighborhoodButton->setEnabled(false);
}
}
void MainWindow::on_widthSpinBox_valueChanged(int)
......@@ -228,3 +232,35 @@ void MainWindow::copy_structure_clicked(const Structure &s)
ui->grid_view->set_clipboard(s);
statusBar()->showMessage("Structure copied.", 5000);
}
void MainWindow::init_transition_neighborhood_list()
{
for (const auto& transition : Factory<TransitionRule>::list_choices())
{
ui->transition_list->addItem(QString::fromStdString(transition));
}
for (const auto& rule : Factory<NeighborhoodRule>::list_choices())
{
ui->neighborhood_list->addItem(QString::fromStdString(rule));
}
}
void MainWindow::update_transition_settings()
{
std::string selected = ui->transition_list->currentText().toStdString();
auto rule = Factory<TransitionRule>::make(selected);
if (!rule)
return;
if (rule->get_properties().size() == 0)
ui->rule_settings_area->hide();
else
{
ui->rule_settings_area->show();
UIBuilderVisitor visit(ui->rule_settings_area);
for (auto& prop : rule->get_properties())
prop->accept(visit);
}
}
......@@ -16,6 +16,7 @@ SOURCES += \
neighborhood_rules/arbitraryneighborhoodrule.cpp \
automaton.cpp \
gridview.cpp \
transition_rules/circulartransition.cpp \
transition_rules/lifegametransition.cpp \
main.cpp \
neighborhood_rules/mooreNeighborhoodRule.cpp \
......
#include "circulartransition.hpp"
unsigned CircularTransition::getState(unsigned cell, const Neighborhood &neighborhood) const
{
unsigned next_state = (cell+1) % states.val;
unsigned next_state_neighbors = neighborhood.getNb(next_state);
if ((int)next_state_neighbors >= thresold.val)
return next_state;
else
return cell;
}
......@@ -11,24 +11,20 @@ public:
class LifeLikeTransition : public Transition
{
public:
static std::string name()
{ return "life-like"; }
virtual std::string say_hi()
{ return "Life hi!\n"; }
};
REGISTER_FACTORY_ENTRY(Transition, LifeLikeTransition);
REGISTER_FACTORY_ENTRY(Transition, LifeLikeTransition, "life-like");
class GenerationsTransition : public Transition
{
public:
static std::string name()
{ return "generations"; }
virtual std::string say_hi()
{ return "Generations hi!\n"; }
};
REGISTER_FACTORY_ENTRY(Transition, GenerationsTransition);
REGISTER_FACTORY_ENTRY(Transition, GenerationsTransition, "generations");
void CellulutTests::test_factory()
......
......@@ -23,6 +23,7 @@ SOURCES += \
../src/grid.cpp \
../src/neighborhood_rules/mooreNeighborhoodRule.cpp \
../src/transition_rules/lifegametransition.cpp \
../src/transition_rules/circulartransition.cpp \
alphabet_test.cpp \
arbitraryneighborhoodrule_test.cpp \
circulartransition_test.cpp \
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment