C++ Mathematical Expression Toolkit (ExprTk) release
Loading...
Searching...
No Matches
exprtk_game_of_life.cpp
Go to the documentation of this file.
1/*
2 **************************************************************
3 * C++ Mathematical Expression Toolkit Library *
4 * *
5 * ExprTk Conway's Game Of Life *
6 * Author: Arash Partow (1999-2024) *
7 * URL: https://www.partow.net/programming/exprtk/index.html *
8 * *
9 * Copyright notice: *
10 * Free use of the Mathematical Expression Toolkit Library is *
11 * permitted under the guidelines and in accordance with the *
12 * most current version of the MIT License. *
13 * https://www.opensource.org/licenses/MIT *
14 * SPDX-License-Identifier: MIT *
15 * *
16 **************************************************************
17*/
18
19
20#include <algorithm>
21#include <array>
22#include <chrono>
23#include <cstdio>
24#include <random>
25#include <string>
26#include <thread>
27
28#include "exprtk.hpp"
29
30
31template <typename T>
32struct rnd_01 final : public exprtk::ifunction<T>
33{
34 using exprtk::ifunction<T>::operator();
35
37 : exprtk::ifunction<T>(0)
38 {
39 std::random_device device;
40 std::array<unsigned int,std::mt19937::state_size> seed;
41 std::generate_n(seed.data(), seed.size(), std::ref(device));
42 std::seed_seq seq(std::begin(seed), std::end(seed));
43 generator.seed(seq);
44 }
45
46 inline T operator()() override
47 {
48 return distribution(generator);
49 }
50
51 std::mt19937 generator;
52 std::uniform_real_distribution<T> distribution{T(0),T(1)};
53};
54
55template <typename T>
57{
58 typedef exprtk::symbol_table<T> symbol_table_t;
59 typedef exprtk::expression<T> expression_t;
60 typedef exprtk::parser<T> parser_t;
61 typedef exprtk::function_compositor<T> compositor_t;
62 typedef typename compositor_t::function function_t;
63
64 const std::size_t width = 80;
65 const std::size_t height = 40;
66
67 std::vector<T> world(width * height, T(0));
68 rnd_01<T> rnd01;
70
71 symbol_table_t symbol_table;
72 symbol_table.add_constant("width" , static_cast<T>(width ));
73 symbol_table.add_constant("height", static_cast<T>(height));
74 symbol_table.add_vector ("world" , world);
75 symbol_table.add_package (io_package);
76 symbol_table.add_function("random", rnd01);
77
78 symbol_table.
79 add_function("sleep",
80 [](T time_ms) -> T
81 {
82 std::this_thread::sleep_for(
83 std::chrono::milliseconds(static_cast<std::size_t>(time_ms)));
84 return T(1);
85 });
86
87 symbol_table.
88 add_function("clear",
89 [](T full) -> T
90 {
91 printf("%s\033[H", full == T(1) ? "" : "\033[2J");
92 std::fflush(stdout);
93 return T(1);
94 });
95
96 compositor_t compositor(symbol_table);
97
98 compositor.load_variables(true);
99 compositor.load_vectors (true);
100
101 compositor.add(
102 function_t("point")
103 .vars("x","y")
104 .expression
105 (
106 " world[y * width + x]; "
107 ));
108
109 compositor.add(
110 function_t("set_point")
111 .vars("x", "y", "value")
112 .expression
113 (
114 " if ( "
115 " (x >= 0) and (y >= 0) and "
116 " (x < width) and (y < height) "
117 " ) "
118 " { "
119 " world[y * width + x] := value; "
120 " } "
121 ));
122
123 compositor.add(
124 function_t("set_glider")
125 .vars("x", "y")
126 .expression
127 (
128 " set_point(x + 1, y, 1); "
129 " set_point(x + 2, y + 1, 1); "
130 " set_point(x, y + 2, 1); "
131 " set_point(x + 1, y + 2, 1); "
132 " set_point(x + 2, y + 2, 1); "
133 ));
134
135 compositor.add(
136 function_t("render")
137 .expression
138 (
139 " print('+'); "
140 " for (var x := 0; x < width; x += 1) { print('-'); } "
141 " println('+'); "
142 " "
143 " for (var y := 0; y < height; y += 1) "
144 " { "
145 " print('|'); "
146 " for (var x := 0; x < width; x += 1) "
147 " { "
148 " print( point(x,y) ? '*' : ' ' ); "
149 " }; "
150 " println('|'); "
151 " }; "
152 " "
153 " print('+'); "
154 " for (var x := 0; x < width; x += 1) { print('-'); } "
155 " println('+'); "
156 ));
157
158 compositor.add(
159 function_t("evolve")
160 .expression
161 (
162 " var next_world[world[]] := [0]; "
163 " "
164 " for (var y := 0; y < height; y += 1) "
165 " { "
166 " for (var x := 0; x < width; x += 1) "
167 " { "
168 " var alive_count := point(x,y) ? -1 : 0; "
169 " "
170 " for (var y1 := y - 1; y1 <= y + 1; y1 += 1) "
171 " { "
172 " var curr_y := (y1 + height) % height; "
173 " "
174 " for (var x1 := x - 1; x1 <= x + 1; x1 += 1) "
175 " { "
176 " var curr_x := (x1 + width) % width; "
177 " "
178 " if (point(curr_x,curr_y)) "
179 " { "
180 " alive_count += 1; "
181 " } "
182 " } "
183 " }; "
184 " "
185 " next_world[y * width + x] := "
186 " switch "
187 " { "
188 " case alive_count == 2 and point(x,y) : 1; "
189 " case alive_count == 3 : 1; "
190 " default : 0; "
191 " }; "
192 " } "
193 " }; "
194 " "
195 " world := next_world; "
196 ));
197
198 const std::string game_of_life_driver =
199 " /* Setup the initial state of the world */ "
200 " for (var x := 0; x < width; x += 1) "
201 " { "
202 " for (var y := 0; y < height; y += 1) "
203 " { "
204 " switch "
205 " { "
206 " case (random() < 0.10) : set_glider(x,y); "
207 " case (random() < 0.10) : set_point (x,y,1); "
208 " }; "
209 " } "
210 " }; "
211 " "
212 " var num_generations := 1000; "
213 " "
214 " for (var i := 0; i < num_generations; i += 1) "
215 " { "
216 " clear(i % 50 == 0); "
217 " println('Generation: ', i); "
218 " render(); "
219 " evolve(); "
220 " sleep(10); "
221 " } ";
222
223 expression_t expression;
224 expression.register_symbol_table(symbol_table);
225
226 parser_t parser;
227 parser.compile(game_of_life_driver,expression);
228
229 expression.value();
230}
231
232int main()
233{
234 game_of_life<double>();
235 return 0;
236}
ifunction(const std::size_t &pc)
Definition exprtk.hpp:19784
int main()
void game_of_life()
std::uniform_real_distribution< T > distribution
std::mt19937 generator
T operator()() override