Utopia 2
Framework for studying models of complex & adaptive systems.
Loading...
Searching...
No Matches
GameOfLife.hh
Go to the documentation of this file.
1#ifndef UTOPIA_MODELS_GAMEOFLIFE_HH
2#define UTOPIA_MODELS_GAMEOFLIFE_HH
3
4// standard library includes
5#include <random>
6#include <string>
7#include <algorithm>
8
9// third-party library includes
10
11// Utopia-related includes
12#include <utopia/core/model.hh>
14#include <utopia/core/apply.hh>
15#include <utopia/core/select.hh>
17
19{
20// ++ Type definitions ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
21
24{
26 bool living;
27
29
37};
38
40
47
50
51// ++ Model definition ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
52
54
56class GameOfLife : public Model<GameOfLife, ModelTypes>
57{
58 public:
61
63 using DataGroup = typename Base::DataGroup;
64
66 using DataSet = typename Base::DataSet;
67
70 // NOTE that it requires the model's type as second template argument
71
73 using NbLifeRule = std::unordered_set<unsigned short>;
74
76
84
85 private:
86 // Base members: _time, _name, _cfg, _hdfgrp, _rng, _monitor, _log, _space
87 // ... but you should definitely check out the documentation ;)
88
89 // -- Members -------------------------------------------------------------
92
94 const std::string _rule;
95
98
101
102 // .. Temporary objects ...................................................
103
104 // .. Datasets ............................................................
106 std::shared_ptr<DataSet> _dset_living;
107
108 public:
109 // -- Model Setup ---------------------------------------------------------
111
114 template<class ParentModel>
115 GameOfLife(const std::string name, ParentModel& parent) :
116 // Initialize first via base model
117 Base(name, parent),
118
119 // Now initialize the cell manager
120 _cm(*this),
121
122 // Initialize the rule and extract the number of neighbors required
123 // for birth and survival
124 _rule(get_as<std::string>("rule", this->_cfg)),
127
128 // Datasets
129 // For setting up datasets that store CellManager data, you can use the
130 // helper functions to take care of setting them up:
132 {
133 // Select the cells that should be set to living
134 const auto living = this->_cm.select_cells(
135 get_as<DataIO::Config>("living", this->_cfg));
136 for (const auto& living_cell : living) {
137 living_cell->state.living = true;
138 }
139
140 // Initialization should be finished here.
141 this->_log->debug("{} model fully set up.", this->_name);
142 }
143
144 private:
145 // .. Setup functions .....................................................
148 {
149 const std::string delimiter = "/";
150 const std::string birth_s = _rule.substr(0, _rule.find(delimiter));
151
153 for (auto b_char : birth_s) {
154 // Subtracting '0' is needed to get from the ASCII number stored as
155 // char to the corresponding unsigned short value.
156 auto b = static_cast<unsigned short>(b_char - '0');
157 birth.emplace(b);
158 }
159 return birth;
160 }
161
164 {
165 // Get the substring specifying `survive` which is the substring that
166 // starts after the delimiter and ends with the end of the rule string.
167 const std::string delimiter = "/";
168 const auto pos_delimiter = _rule.find(delimiter);
169 const std::string survive_s =
170 _rule.substr(pos_delimiter + 1, _rule.size() - pos_delimiter);
171
173 for (auto b_char : survive_s) {
174 // Subtracting '0' is needed to get from the ASCII number stored as
175 // char to the corresponding unsigned short value.
176 auto b = static_cast<unsigned short>(b_char - '0');
177 survive.emplace(b);
178 }
179 return survive;
180 }
181
182 // .. Helper functions ....................................................
183
186 {
187 double sum = 0.;
188 for (const auto& cell : _cm.cells()) {
189 sum += cell->state.living;
190 }
191 return sum / _cm.cells().size();
192 }
193
194 // .. Rule functions ......................................................
196 const RuleFunc _life_rule = [this](const auto& cell) {
197 // Get the current state of the cell
198 auto state = cell->state;
199
200 // Calculate the number of living neighbors
201 auto num_living_nbs {0u};
202 for (auto nb : this->_cm.neighbors_of(cell)) {
203 if (nb->state.living) {
205 }
206 }
207
208 const bool survive =
209 std::find(_survive.begin(), _survive.end(), num_living_nbs) !=
210 _survive.end();
211 // Die if the number of living neighbors is not in the survival
212 // container
213 if (not survive) {
214 state.living = false;
215 }
216
217 // Give birth if the number of living neighbors is in the birth
218 // container
219 const bool birth =
220 std::find(_birth.begin(), _birth.end(), num_living_nbs) !=
221 _birth.end();
222 if (birth) {
223 state.living = true;
224 }
225
226 // Return the new cell state
227 return state;
228 };
229
230 public:
231 // -- Public Interface ----------------------------------------------------
232 // .. Simulation Control ..................................................
233
236 {
237 // Apply the rules to all cells, first the interaction, then the update
239 }
240
242
250 void monitor()
251 {
252 this->_monitor.set_entry("living_cell_density",
254 }
255
257
262 {
263 // Write out the some_state of all cells
264 _dset_living->write(_cm.cells().begin(),
265 _cm.cells().end(),
266 [](const auto& cell) {
267 return static_cast<char>(cell->state.living);
268 });
269 }
270
271 // .. Getters and setters .................................................
272 // Add getters and setters here to interface with other models
273};
274
275} // namespace Utopia::Models::GameOfLife
276
277#endif // UTOPIA_MODELS_GAMEOFLIFE_HH
typename std::function< CellState(const std::shared_ptr< Cell > &)> RuleFunc
The type of a rule function acting on cells of this cell manager.
Definition cell_manager.hh:84
CellContainer< Cell > select_cells(Args &&... args) const
Select cells using the Utopia::select_entities interface.
Definition cell_manager.hh:342
CellContainer< Cell > neighbors_of(const Cell &cell) const
Retrieve the given cell's neighbors.
Definition cell_manager.hh:458
const CellContainer< Cell > & cells() const
Return const reference to the managed CA cells.
Definition cell_manager.hh:219
Base class interface for Models using the CRT Pattern.
Definition model.hh:112
std::shared_ptr< DataSet > create_cm_dset(const std::string name, const CellManager &cm, const std::size_t compression_level=1, const std::vector< hsize_t > chunksize={})
Create a dataset storing data from a CellManager.
Definition model.hh:849
Monitor _monitor
The monitor.
Definition model.hh:188
typename ModelTypes::DataSet DataSet
Data type that is used for storing data.
Definition model.hh:125
const Config _cfg
Config node belonging to this model instance.
Definition model.hh:158
const std::string _name
Name of the model instance.
Definition model.hh:149
typename ModelTypes::DataGroup DataGroup
Data type that is used for storing datasets.
Definition model.hh:122
const std::shared_ptr< spdlog::logger > _log
The (model) logger.
Definition model.hh:164
The GameOfLife Model.
Definition GameOfLife.hh:57
const NbLifeRule _birth
The number of neighbors required to get born.
Definition GameOfLife.hh:97
const NbLifeRule _survive
The number of neighbors required to survive.
Definition GameOfLife.hh:100
std::shared_ptr< DataSet > _dset_living
A dataset for storing all cells living or dead status.
Definition GameOfLife.hh:106
const std::string _rule
The rule in Mirek's Cellebration notation.
Definition GameOfLife.hh:94
double calculate_living_cell_density() const
Calculate the mean of all cells' some_state.
Definition GameOfLife.hh:185
typename Base::DataGroup DataGroup
Data type of the group to write model data to, holding datasets.
Definition GameOfLife.hh:63
typename Base::DataSet DataSet
Data type for a dataset.
Definition GameOfLife.hh:66
const RuleFunc _life_rule
Implement the general life-like rule.
Definition GameOfLife.hh:196
NbLifeRule extract_birth_from_rule()
Extract the number of neighbors required for birth from the rule.
Definition GameOfLife.hh:147
CellManager _cm
The cell manager.
Definition GameOfLife.hh:91
NbLifeRule extract_survive_from_rule()
Extract the number of neighbors required to survive from the rule.
Definition GameOfLife.hh:163
typename CellManager::RuleFunc RuleFunc
Extract the type of the rule function from the CellManager.
Definition GameOfLife.hh:83
void monitor()
Monitor model information.
Definition GameOfLife.hh:250
std::unordered_set< unsigned short > NbLifeRule
Type of container to store the number of neighbors for the life rule.
Definition GameOfLife.hh:73
void perform_step()
Iterate a single step.
Definition GameOfLife.hh:235
void write_data()
Write data.
Definition GameOfLife.hh:261
GameOfLife(const std::string name, ParentModel &parent)
Construct the GameOfLife model.
Definition GameOfLife.hh:115
ReturnType get_as(const std::string &key, const DataIO::Config &node)
This function is a wrapper around the yaml-cpp YAML::Node::as function.
Definition cfg_utils.hh:158
Container select_entities(const Manager &mngr, const DataIO::Config &sel_cfg)
Select entities according to parameters specified in a configuration.
Definition select.hh:213
Definition GameOfLife.hh:19
Definition parallel.hh:235
The entity traits struct gathers types to be used for specializing an entity.
Definition entity.hh:49
Wrapper struct for defining model class data types.
Definition model.hh:92
The type of a cell's state.
Definition GameOfLife.hh:24
CellState()
Construct the cell state with all dead cells as default.
Definition GameOfLife.hh:36
bool living
Whether a cell lives or not.
Definition GameOfLife.hh:26