Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions metadata.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@
"uid": "gameOfLife",
"title": "Conway's Game of Life",
"version": 1,
"author": "Ethan Padden and Marcos Cardinot",
"description": "This implements Conway's Game Of Life cellular automaton.",

"author": "Ethan Padden, Marcos Cardinot and Eleftheria Chatziargyriou",
"description": "This implements life-like cellular automata.",
"supportedGraphs": ["squareGrid"],
"pluginAttributesScope": [ {"rules": "string"} ],
"nodeAttributesScope": [ {"live": "bool"} ]
}
85 changes: 74 additions & 11 deletions plugin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,78 @@

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
if (QSet<QString>::fromList(_cmd1.split("")).count() != _cmd1.size() + 1 || QSet<QString>::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()
{
// 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;
}

Expand All @@ -31,20 +99,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()) {
Expand Down
3 changes: 3 additions & 0 deletions plugin.h
Original file line number Diff line number Diff line change
Expand Up @@ -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