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

Implémentation de la sauvegarde de structure (au format JSON)

parent 2fe19a9d
Pipeline #77936 passed with stages
in 17 seconds
......@@ -16,6 +16,7 @@ Fichier contenant la classe Structure, représentant un ensemble de cellules con
#include <functional>
#include <map>
#include <type_traits>
#include <algorithm>
#include "coord.hpp"
......@@ -57,6 +58,14 @@ public:
else
m_cells[it->first] = it->second;
}
auto minmax_width = std::minmax_element(m_cells.begin(), m_cells.end(), [](const auto& a, const auto& b)
{ return a.first.x < b.first.x; });
m_width = minmax_width.second->first.x - minmax_width.first->first.x + 1;
auto minmax_height = std::minmax_element(m_cells.begin(), m_cells.end(), [](const auto& a, const auto& b)
{ return a.first.y < b.first.y; });
m_height = minmax_width.second->first.y - minmax_width.first->first.y + 1;
}
//! \brief Fonction vidant la structure, la laissant vide.
void clear()
......@@ -68,6 +77,14 @@ public:
size_t size() const
{ return m_cells.size(); }
//! \brief retourne la largeur (en cellules) de la structure
size_t width() const
{ return m_width; }
//! \brief retourne la hauteur (en cellules) de la structure
size_t height() const
{ return m_height; }
//! \class Structure::iterator
//! \brief iterator représentant un itérateur constant vers le contenu de la structure.
class iterator
......@@ -102,6 +119,7 @@ public:
iterator end() const { return iterator(m_cells.end()); }
private:
std::map<Coord, unsigned> m_cells;
size_t m_width = 0, m_height = 0;
};
#endif // STRUCTURE_HPP
/**
\file structurewrite.hpp
\date 13/05/2021
\author Yann Boucher
\version 1
\brief StructureWriter
Fichier contenant la classe StructureWrite et ses filles, permettant de sauvegarder une Structure sous différents formats de fichier.
**/
#ifndef STRUCTUREWRITER_HPP
#define STRUCTUREWRITER_HPP
#include <string>
class Structure;
//! \class StructureWrite
//! Classe abstraite permettant de sauvegarder une Structure sous différents formats de fichier.
class StructureWriter
{
public:
//! \brief Constructeur prenant en argument les données du fichier à lire sous forme de std::string
StructureWriter(const Structure& in_struct):
m_struct(in_struct)
{}
//! \brief Sauvegarde la structure sous forme d'un std::string.
virtual std::string save_structure() const = 0;
protected:
//! \brief Référence constante vers la structure à sauvegarder
const Structure& m_struct;
};
//! \class RLEStructureWrite
//! Sauvegarde une structure au format Extended RLE de Golly (https://www.conwaylife.com/wiki/Run_Length_Encoded)
class RLEStructureWriter : public StructureWriter
{
public:
RLEStructureWriter(const Structure& in_struct):
StructureWriter(in_struct)
{}
virtual std::string save_structure() const;
private:
std::string state_to_str(unsigned state);
};
//! \class JSONStructureWrite
//! Sauvegarde une structure au format JSON
class JSONStructureWriter : public StructureWriter
{
public:
JSONStructureWriter(const Structure& in_struct):
StructureWriter(in_struct)
{}
virtual std::string save_structure() const;
};
#endif // STRUCTUREWRITER_HPP
......@@ -20,7 +20,8 @@ SOURCES += \
structurereader.cpp \
interface.cpp \
grid.cpp \
history.cpp
history.cpp \
structurewriter.cpp
HEADERS += \
../include/coord.hpp \
......
......@@ -162,12 +162,6 @@ Structure RLEStructureReader::read_structure()
//char tag = read();
std::string line = read_line();
}
// end of structure line
else if (accept("$"))
{
x = 0;
++y;
}
// end of data
else if (accept("!"))
{
......@@ -181,12 +175,21 @@ Structure RLEStructureReader::read_structure()
// <run_count> is > 1
if (isdigit(peek()))
run_count = read_int();
state = read_state();
for (unsigned i = 0; i < run_count; ++i)
// end of structure line
if (accept("$"))
{
data.push_back({{x, y}, state});
++x;
x = 0;
y += run_count;
}
else
{
state = read_state();
for (unsigned i = 0; i < run_count; ++i)
{
data.push_back({{x, y}, state});
++x;
}
}
}
}
......
/**
\file structurewriter.cpp
\date 13/05/2021
\author Yann Boucher
\version 1
\brief StructureWriter
**/
#include "structurewriter.hpp"
#include "structure.hpp"
#include <QJsonObject>
#include <QJsonArray>
#include <QJsonDocument>
std::string JSONStructureWriter::save_structure() const
{
QJsonObject root;
QJsonArray cells;
for (const auto& pair : m_struct)
{
QJsonObject entry;
entry.insert("x", pair.first.x);
entry.insert("y", pair.first.y);
entry.insert("state", (int)pair.second);
cells.append(entry);
}
root.insert("cells", cells);
QJsonDocument doc(root);
return doc.toJson().toStdString();
}
std::string RLEStructureWriter::save_structure() const
{
std::string result;
result += "x = " + std::to_string(m_struct.width()) + ", ";
result += "y = " + std::to_string(m_struct.height()) + "\n";
// TODO : implement
return "<unimplemented>";
}
std::string RLEStructureWriter::state_to_str(unsigned state)
{
if (state == 0)
return "b";
if (state == 1)
return "o";
if (state >= 1 && state <= 24)
return std::string(1, state-1 + 'A');
else
{
char page_char = ((state-25)/24) + 'p';
char offset_char = (state-25)%24 + 'A';
return std::string(1, page_char) + std::string(1, offset_char);
}
}
......@@ -17,6 +17,8 @@ private slots:
void test_rle_structurereader();
void test_json_structurereader();
void test_rle_structurewriter();
void test_json_structurewriter();
void test_arbitrary_neighborhood_rule();
......
......@@ -10,7 +10,7 @@ void CellulutTests::test_structure()
{
std::vector<std::pair<Coord, unsigned>> coords;
std::vector<std::pair<Coord, unsigned>> empty;
coords.push_back({{1, 2}, 3});
coords.push_back({{1, 3}, 3});
coords.push_back({{-1, 2}, 1});
{
......@@ -23,19 +23,25 @@ void CellulutTests::test_structure()
QVERIFY(std::is_permutation(coords.begin(), coords.end(), s1.begin()));
QVERIFY(std::is_permutation(coords.begin(), coords.end(), s2.begin()));
QCOMPARE(s1.width(), 3);
QCOMPARE(s1.height(), 2);
s1.load(empty.begin(), empty.end());
QVERIFY(s1.size() == 0);
}
std::vector<std::pair<Coord, unsigned>> coords_with_zero;
coords_with_zero.push_back({{1, 2}, 3});
coords_with_zero.push_back({{1, 3}, 3});
coords_with_zero.push_back({{-1, 2}, 1});
coords_with_zero.push_back({{-1, 2}, 0});
coords_with_zero.push_back({{-2, 2}, 0});
{
Structure s1(coords_with_zero.begin(), coords_with_zero.end());
QCOMPARE(s1.size(), 2); // 2 cellules non nulles, on ignore les cellules à zéro qui sont toujours implicites
QVERIFY(std::is_permutation(coords.begin(), coords.end(), s1.begin()));
QCOMPARE(s1.width(), 3);
QCOMPARE(s1.height(), 2);
}
}
#include <QtTest/QtTest>
#include <algorithm>
#include "cellulut_tests.hpp"
#include "structure.hpp"
#include "structurewriter.hpp"
#include "structurereader.hpp"
void CellulutTests::test_rle_structurewriter()
{
// TODO : écrire ces tests
}
void CellulutTests::test_json_structurewriter()
{
std::vector<std::pair<Coord, unsigned>> coords;
coords.push_back({{1, 2}, 3});
coords.push_back({{-1, 2}, 1});
{
JSONStructureWriter writer(Structure{coords.begin(), coords.end()});
auto out = writer.save_structure();
//printf("%s\n", out.c_str());
JSONStructureReader reader(out);
Structure struct_out = reader.read_structure();
QVERIFY(std::is_permutation(struct_out.begin(), struct_out.end(), coords.begin()));
}
}
......@@ -16,6 +16,7 @@ INCLUDEPATH += ../include
SOURCES += \
../src/propertyvisitors.cpp \
../src/structurereader.cpp \
../src/structurewriter.cpp \
../src/neighborhood.cpp \
../src/arbitraryneighborhoodrule.cpp \
../src/history.cpp \
......@@ -29,7 +30,8 @@ SOURCES += \
propertyvisitors_test.cpp \
cellulut_tests.cpp \
structure_test.cpp \
structurereader_tests.cpp
structurereader_tests.cpp \
structurewriter_tests.cpp
HEADERS += \
cellulut_tests.hpp
......
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