From 16c95ecc6c813998a692d4e6e1be2fd0aa5954ea Mon Sep 17 00:00:00 2001 From: Eleftheria Chatziargyriou Date: Tue, 30 Apr 2019 15:40:40 +0300 Subject: [PATCH 1/2] Parse life-like automata rules --- metadata.json | 5 +-- plugin.cpp | 87 ++++++++++++++++++++++++++++++++++++++++++++------- plugin.h | 3 ++ 3 files changed, 82 insertions(+), 13 deletions(-) diff --git a/metadata.json b/metadata.json index 52615a4..2a02fee 100644 --- a/metadata.json +++ b/metadata.json @@ -3,9 +3,10 @@ "uid": "gameOfLife", "title": "Conway's Game of Life", "version": 1, - "author": "Ethan Padden and Marcos Cardinot", + "author": "Ethan Padden, Marcos Cardinot and Eleftheria Chatziargyriou", "description": "This implements Conway's Game Of Life cellular automaton.", - + "supportedGraphs": ["squareGrid"], + "pluginAttributesScope": [ {"rules": "string"} ], "nodeAttributesScope": [ {"live": "bool"} ] } diff --git a/plugin.cpp b/plugin.cpp index 04a93f2..e7c370e 100644 --- a/plugin.cpp +++ b/plugin.cpp @@ -10,10 +10,80 @@ namespace evoplex { +QStringList GameOfLife::parseCmd(const QString &cmd) +{ + if (cmd.isEmpty()) + { + qWarning() << "The command cannot be empty"; + return QStringList(); + } + + QStringList _cmds; + QString _cmd1, _cmd2; + + bool isInt1 = false; + bool isInt2 = false; + + if (cmd.indexOf("/") == -1) + { + qWarning() << "Commands must be of the form B{number of neighbors for cell birth} / S{number of neighbors for cell survival"; + return QStringList(); + } + + _cmds = cmd.split("/"); + + if (!_cmds.at(0).startsWith("B") || !_cmds.at(1).startsWith("S")) + { + qWarning() << "Commands must be of the form B{number of neighbors for cell birth} / S{number of neighbors for cell survival"; + return QStringList(); + } + + _cmd1 = _cmds.at(0); + _cmd1.remove(0, 1); + _cmd2 = _cmds.at(1); + _cmd2.remove(0, 1); + + int intRule1 = _cmd2.toInt(&isInt1); + int intRule2 = _cmd1.toInt(&isInt2); + + // check if rules are integers + if (!isInt1 || !isInt2) + { + qWarning() << "Unable to parse command. Make sure you give a valid integer."; + return QStringList(); + } + // check if the rulestring has unique integers + qWarning() << _cmd1.split("") << _cmd1 << QSet::fromList(_cmd2.split("")) << _cmd2; + if (QSet::fromList(_cmd1.split("")).count() != _cmd1.size() + 1 || QSet::fromList(_cmd2.split("")).count() != _cmd2.size() + 1) + { + qWarning() << "Integers can't appear more than once on each rule."; + return QStringList(); + } + return QStringList() << _cmd1 << _cmd2; +} + bool GameOfLife::init() { + qWarning() <<"started"; // gets the id of the `live` node's attribute, which is the same for all nodes m_liveAttrId = node(0).attrs().indexOf("live"); + // parses the ruleset + + if (attrExists("rules")){ + m_ruleset = attr("rules").toQString(); + } + else{ + qWarning() << "missing attributes."; + return false; + } + + m_rulesetLst = parseCmd(m_ruleset); + + if (m_rulesetLst.isEmpty()) + { + return false; + } + return m_liveAttrId >= 0; } @@ -31,20 +101,15 @@ bool GameOfLife::algorithmStep() } if (node.attr(m_liveAttrId).toBool()) { - if (liveNeighbourCount < 2) { // Dies due to underpopulation - nextStates.emplace_back(false); - } else if (liveNeighbourCount < 4) { // Lives to next state - nextStates.emplace_back(true); - } else { // Dies due to overpopulation - nextStates.emplace_back(false); - } + // If the node is alive, then it only survives if its number of neighbors is specified in the rulestring. + // Otherwise, it dies from under/overpopulation + nextStates.emplace_back(m_rulesetLst.at(1).contains(QString::number(liveNeighbourCount))); } else { - // Any dead node with exactly three live neighbors - // becomes a live node, as if by reproduction. - nextStates.emplace_back(liveNeighbourCount == 3); + // Any dead cell can become alive if its number of neighbors matches the one specified in the rulestring. + // Otherwise, it remains dead. + nextStates.emplace_back(m_rulesetLst.at(0).contains(QString::number(liveNeighbourCount))); } } - // For each node, load the next state into the current state size_t i = 0; for (Node node : nodes()) { diff --git a/plugin.h b/plugin.h index a04bb04..17add8b 100644 --- a/plugin.h +++ b/plugin.h @@ -17,9 +17,12 @@ class GameOfLife: public AbstractModel public: bool init() override; bool algorithmStep() override; + QStringList parseCmd(const QString &cmd); private: int m_liveAttrId; // the id of the 'live' node's attribute + QString m_ruleset; // the model's ruleset (B/S format) + QStringList m_rulesetLst; }; } // evoplex #endif // GAME_OF_LIFEL_H From 442201082d09856cf512e7d44ab8113c02893a8e Mon Sep 17 00:00:00 2001 From: Eleftheria Chatziargyriou Date: Tue, 30 Apr 2019 15:57:10 +0300 Subject: [PATCH 2/2] Formatting fix --- metadata.json | 3 +-- plugin.cpp | 6 ++---- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/metadata.json b/metadata.json index 2a02fee..3faad7b 100644 --- a/metadata.json +++ b/metadata.json @@ -4,8 +4,7 @@ "title": "Conway's Game of Life", "version": 1, "author": "Ethan Padden, Marcos Cardinot and Eleftheria Chatziargyriou", - "description": "This implements Conway's Game Of Life cellular automaton.", - + "description": "This implements life-like cellular automata.", "supportedGraphs": ["squareGrid"], "pluginAttributesScope": [ {"rules": "string"} ], "nodeAttributesScope": [ {"live": "bool"} ] diff --git a/plugin.cpp b/plugin.cpp index e7c370e..0ee810e 100644 --- a/plugin.cpp +++ b/plugin.cpp @@ -53,7 +53,6 @@ QStringList GameOfLife::parseCmd(const QString &cmd) return QStringList(); } // check if the rulestring has unique integers - qWarning() << _cmd1.split("") << _cmd1 << QSet::fromList(_cmd2.split("")) << _cmd2; if (QSet::fromList(_cmd1.split("")).count() != _cmd1.size() + 1 || QSet::fromList(_cmd2.split("")).count() != _cmd2.size() + 1) { qWarning() << "Integers can't appear more than once on each rule."; @@ -64,11 +63,10 @@ QStringList GameOfLife::parseCmd(const QString &cmd) bool GameOfLife::init() { - qWarning() <<"started"; // gets the id of the `live` node's attribute, which is the same for all nodes m_liveAttrId = node(0).attrs().indexOf("live"); - // parses the ruleset - + + // parses the ruleset if (attrExists("rules")){ m_ruleset = attr("rules").toQString(); }