Commit 4ea831f3 authored by Yann Boucher's avatar Yann Boucher
Browse files

Implemented tests for the transition rules we have; Implemented a circular transition rule

parent eb413934
Pipeline #78346 passed with stages
in 17 seconds
...@@ -66,16 +66,15 @@ private: ...@@ -66,16 +66,15 @@ private:
/** /**
\class PropertySaverVisitor \class PropertySaverVisitor
Cette classe permet de sauvegarder un ensemble de Property dans un fichier JSON donné. Cette classe permet de sauvegarder un ensemble de Property dans un object JSON donné.
**/ **/
class PropertySaverVisitor : public PropertyVisitor class PropertySaverVisitor : public PropertyVisitor
{ {
public: public:
//! Construit le PropertySaverVisitor. //! Construit le PropertySaverVisitor.
PropertySaverVisitor(); PropertySaverVisitor();
//! Sauvegarde les données des Property visitées au format JSON dans le fichier. //! Sauvegarde les données des Property visitées au format JSON dans un QJsonObject.
//! \param filename Le nom du fichier. QJsonObject save();
void save(const std::string& filename);
private: private:
QVariant& current(); QVariant& current();
...@@ -96,14 +95,13 @@ private: ...@@ -96,14 +95,13 @@ private:
/** /**
\class PropertyLoaderVisitor \class PropertyLoaderVisitor
Cette classe permet de charger un ensemble de Property depuis un fichier JSON donné. Cette classe permet de charger un ensemble de Property depuis un pbject JSON donné.
**/ **/
class PropertyLoaderVisitor : public PropertyVisitor class PropertyLoaderVisitor : public PropertyVisitor
{ {
public: public:
//! Construit le PropertyLoaderVisitor à partir des données contenues dans un fichier JSON. //! Construit le PropertyLoaderVisitor à partir d'un QJsonObject.
//! \param filename Le nom du fichier. PropertyLoaderVisitor(const QJsonObject& root);
PropertyLoaderVisitor(const std::string& filename);
private: private:
QJsonValue& current(); QJsonValue& current();
......
#ifndef CIRCULARTRANSITION_HPP
#define CIRCULARTRANSITION_HPP
#include "transitionrule.hpp"
#include "property.hpp"
// http://joatdev.fr/CyclicAutomaton
class CircularTransition : public TransitionRule, public HasUserProperties
{
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;
}
private:
DEFINE_CONFIGURABLE_PROPERTY(IntegerProperty, states, "Nombre d'états", 1);
DEFINE_CONFIGURABLE_PROPERTY(IntegerProperty, thresold, "Seuil");
};
#endif // CIRCULARTRANSITION_HPP
...@@ -183,24 +183,9 @@ PropertySaverVisitor::PropertySaverVisitor() ...@@ -183,24 +183,9 @@ PropertySaverVisitor::PropertySaverVisitor()
push_object(); push_object();
} }
void PropertySaverVisitor::save(const std::string &filename) QJsonObject PropertySaverVisitor::save()
{ {
//6. Create a QByteArray and fill it with QJsonDocument (json formatted) return current().toJsonObject();
QByteArray byteArray;
byteArray = QJsonDocument(current().toJsonObject()).toJson();
//7. Open a QFile and write the byteArray filled with json formatted data
//thanks to the QJsonDocument() Class to the file
QFile file;
file.setFileName(filename.c_str());
if(!file.open(QIODevice::WriteOnly)){
qDebug() << "No write access for json file";
return;
}
//8. finally write the file and close it
file.write(byteArray);
file.close();
} }
QVariant &PropertySaverVisitor::current() QVariant &PropertySaverVisitor::current()
...@@ -275,31 +260,9 @@ void PropertySaverVisitor::visit(PropertyList &list) ...@@ -275,31 +260,9 @@ void PropertySaverVisitor::visit(PropertyList &list)
save_value(list, array); save_value(list, array);
} }
PropertyLoaderVisitor::PropertyLoaderVisitor(const std::string &filename) PropertyLoaderVisitor::PropertyLoaderVisitor(const QJsonObject& root)
{ {
//1. Open the QFile and write it to a byteArray and close the file m_current_hierarchy.push(root);
QFile file;
file.setFileName(filename.c_str());
if(!file.open(QIODevice::ReadOnly)){
qDebug() << "Json filef couldn't be opened/found";
return;
}
QByteArray byteArray;
byteArray = file.readAll();
file.close();
//2. Format the content of the byteArray as QJsonDocument
//and check on parse Errors
QJsonParseError parseError;
QJsonDocument jsonDoc;
jsonDoc = QJsonDocument::fromJson(byteArray, &parseError);
if(parseError.error != QJsonParseError::NoError){
qWarning() << "Parse error at " << parseError.offset << ":" << parseError.errorString();
return;
}
m_current_hierarchy.push(jsonDoc.object());
} }
QJsonValue &PropertyLoaderVisitor::current() QJsonValue &PropertyLoaderVisitor::current()
......
...@@ -56,7 +56,8 @@ HEADERS += \ ...@@ -56,7 +56,8 @@ HEADERS += \
../include/history.h \ ../include/history.h \
../include/structuresavingdialog.hpp \ ../include/structuresavingdialog.hpp \
../include/structurelibraryview.hpp \ ../include/structurelibraryview.hpp \
../include/transitionrule.hpp ../include/transitionrule.hpp \
../include/transition_rules/circulartransition.hpp \
FORMS += \ FORMS += \
../forms/interface.ui \ ../forms/interface.ui \
......
...@@ -15,7 +15,17 @@ bool LifeGameTransition::acceptFormat(const std::vector<NeighborhoodFormat>& for ...@@ -15,7 +15,17 @@ bool LifeGameTransition::acceptFormat(const std::vector<NeighborhoodFormat>& for
return true; return true;
} }
unsigned int LifeGameTransition::getState(unsigned int, const Neighborhood & neighborhood) const { unsigned int LifeGameTransition::getState(unsigned int state, const Neighborhood & neighborhood) const {
unsigned int nb = neighborhood.getNb(1); unsigned int live = neighborhood.getNb(1);
return (nb<=1||nb>=4)?0:1; if (state == 0)
{
return live == 3 ? 1 : 0;
}
else
{
if (live == 2 || live == 3)
return 1;
else
return 0;
}
} }
...@@ -26,7 +26,8 @@ private slots: ...@@ -26,7 +26,8 @@ private slots:
void test_alphabet(); void test_alphabet();
void test_circulartransition();
void test_lifegametransition();
}; };
#endif // CELLULUT_TESTS_HPP #endif // CELLULUT_TESTS_HPP
#include "cellulut_tests.hpp"
#include "circulartransition.hpp"
#include "propertyvisitors.hpp"
void CellulutTests::test_circulartransition()
{
QJsonObject obj;
obj["Nombre d'états"] = 4;
obj["Seuil"] = 3;
CircularTransition rule; // load
{
PropertyLoaderVisitor visit(obj);
for (auto& prop : rule.get_properties())
prop->accept(visit);
}
// En dessous du seuil
{
Neighborhood n;
n.addNeighbor({0, 1}, 1);
n.addNeighbor({0, -1}, 0);
n.addNeighbor({1, 0}, 0);
n.addNeighbor({-1, 0}, 1);
unsigned next = rule.getState(0, n);
QCOMPARE(next, 0);
}
// >= au seuil
{
Neighborhood n;
n.addNeighbor({0, 1}, 1);
n.addNeighbor({0, -1}, 1);
n.addNeighbor({1, 0}, 1);
n.addNeighbor({-1, 0}, 0);
unsigned next = rule.getState(0, n);
QCOMPARE(next, 1);
}
// 1 -> 2
{
Neighborhood n;
n.addNeighbor({0, 1}, 2);
n.addNeighbor({0, -1}, 2);
n.addNeighbor({1, 0}, 2);
n.addNeighbor({-1, 0}, 0);
unsigned next = rule.getState(1, n);
QCOMPARE(next, 2);
}
// Vérification du modulo pour le nombre d'états
{
Neighborhood n;
n.addNeighbor({0, 1}, 0);
n.addNeighbor({0, -1}, 0);
n.addNeighbor({1, 0}, 0);
n.addNeighbor({-1, 0}, 0);
unsigned next = rule.getState(3, n);
QCOMPARE(next, 0);
}
}
#include "cellulut_tests.hpp"
#include "lifegametransition.h"
void CellulutTests::test_lifegametransition()
{
LifeGameTransition rule;
// Pas de naissance
{
Neighborhood n;
n.addNeighbor({0, 1}, 1);
n.addNeighbor({0, -1}, 0);
n.addNeighbor({1, 0}, 0);
n.addNeighbor({-1, 0}, 1);
unsigned next = rule.getState(0, n);
QCOMPARE(next, 0);
}
// Naissance
{
Neighborhood n;
n.addNeighbor({0, 1}, 1);
n.addNeighbor({0, -1}, 1);
n.addNeighbor({1, 0}, 0);
n.addNeighbor({-1, 0}, 1);
unsigned next = rule.getState(0, n);
QCOMPARE(next, 1);
}
// Survie
{
Neighborhood n;
n.addNeighbor({0, 1}, 1);
n.addNeighbor({0, -1}, 1);
n.addNeighbor({1, 0}, 0);
n.addNeighbor({-1, 0}, 0);
unsigned next = rule.getState(1, n);
QCOMPARE(next, 1);
}
// Sur-population
{
Neighborhood n;
n.addNeighbor({0, 1}, 1);
n.addNeighbor({0, -1}, 1);
n.addNeighbor({1, 0}, 1);
n.addNeighbor({-1, 0}, 1);
n.addNeighbor({-1, -1}, 1);
unsigned next = rule.getState(1, n);
QCOMPARE(next, 0);
}
// Sous-population
{
Neighborhood n;
n.addNeighbor({0, 1}, 0);
n.addNeighbor({0, -1}, 0);
n.addNeighbor({1, 0}, 1);
n.addNeighbor({-1, 0}, 0);
unsigned next = rule.getState(1, n);
QCOMPARE(next, 0);
}
}
...@@ -30,19 +30,20 @@ void CellulutTests::test_loader_saver_visitor() ...@@ -30,19 +30,20 @@ void CellulutTests::test_loader_saver_visitor()
prop2.c.x = 0; prop2.c.y = -3; prop2.c.x = 0; prop2.c.y = -3;
QJsonObject json;
// save // save
{ {
PropertySaverVisitor visit; PropertySaverVisitor visit;
for (auto& prop : ex.get_properties()) for (auto& prop : ex.get_properties())
prop->accept(visit); prop->accept(visit);
visit.save("test.json"); json = visit.save();
} }
Example ex_loaded; Example ex_loaded;
// load // load
{ {
PropertyLoaderVisitor visit("test.json"); PropertyLoaderVisitor visit(json);
for (auto& prop : ex_loaded.get_properties()) for (auto& prop : ex_loaded.get_properties())
prop->accept(visit); prop->accept(visit);
} }
......
...@@ -22,12 +22,15 @@ SOURCES += \ ...@@ -22,12 +22,15 @@ SOURCES += \
../src/history.cpp \ ../src/history.cpp \
../src/grid.cpp \ ../src/grid.cpp \
../src/neighborhood_rules/mooreNeighborhoodRule.cpp \ ../src/neighborhood_rules/mooreNeighborhoodRule.cpp \
../src/transition_rules/lifegametransition.cpp \
alphabet_test.cpp \ alphabet_test.cpp \
arbitraryneighborhoodrule_test.cpp \ arbitraryneighborhoodrule_test.cpp \
circulartransition_test.cpp \
coord_tests.cpp \ coord_tests.cpp \
factory_tests.cpp \ factory_tests.cpp \
grid_test.cpp \ grid_test.cpp \
history_test.cpp \ history_test.cpp \
lifegametransition_test.cpp \
mooreNeighborhoodRule_test.cpp \ mooreNeighborhoodRule_test.cpp \
property_test.cpp \ property_test.cpp \
propertyvisitors_test.cpp \ propertyvisitors_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