├── .gitignore ├── Cargo.lock ├── Cargo.toml ├── README.md ├── configs ├── basic2.yml ├── board.yml ├── crystal.yml ├── debian.yml ├── koch.yml ├── maze.yml ├── mega_donout.yml ├── rainbow.yml ├── sierpinski.yml ├── tree.yml └── triangle.yml ├── gifs ├── board.gif ├── crystal.gif ├── maze.png └── tree.png ├── make_video.sh └── src ├── lsystem.rs ├── main.rs ├── scripting.rs └── turtle.rs /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | **/*.rs.bk 3 | /images 4 | /videos -------------------------------------------------------------------------------- /Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | [[package]] 4 | name = "adler32" 5 | version = "1.0.3" 6 | source = "registry+https://github.com/rust-lang/crates.io-index" 7 | 8 | [[package]] 9 | name = "alga" 10 | version = "0.9.0" 11 | source = "registry+https://github.com/rust-lang/crates.io-index" 12 | dependencies = [ 13 | "approx 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", 14 | "libm 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", 15 | "num-complex 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", 16 | "num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", 17 | ] 18 | 19 | [[package]] 20 | name = "ansi_term" 21 | version = "0.11.0" 22 | source = "registry+https://github.com/rust-lang/crates.io-index" 23 | dependencies = [ 24 | "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", 25 | ] 26 | 27 | [[package]] 28 | name = "approx" 29 | version = "0.3.2" 30 | source = "registry+https://github.com/rust-lang/crates.io-index" 31 | dependencies = [ 32 | "num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", 33 | ] 34 | 35 | [[package]] 36 | name = "arrayvec" 37 | version = "0.4.8" 38 | source = "registry+https://github.com/rust-lang/crates.io-index" 39 | dependencies = [ 40 | "nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", 41 | ] 42 | 43 | [[package]] 44 | name = "atty" 45 | version = "0.2.13" 46 | source = "registry+https://github.com/rust-lang/crates.io-index" 47 | dependencies = [ 48 | "libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)", 49 | "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", 50 | ] 51 | 52 | [[package]] 53 | name = "autocfg" 54 | version = "0.1.2" 55 | source = "registry+https://github.com/rust-lang/crates.io-index" 56 | 57 | [[package]] 58 | name = "bitflags" 59 | version = "1.0.4" 60 | source = "registry+https://github.com/rust-lang/crates.io-index" 61 | 62 | [[package]] 63 | name = "byteorder" 64 | version = "1.2.7" 65 | source = "registry+https://github.com/rust-lang/crates.io-index" 66 | 67 | [[package]] 68 | name = "cfg-if" 69 | version = "0.1.6" 70 | source = "registry+https://github.com/rust-lang/crates.io-index" 71 | 72 | [[package]] 73 | name = "clap" 74 | version = "2.33.0" 75 | source = "registry+https://github.com/rust-lang/crates.io-index" 76 | dependencies = [ 77 | "ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", 78 | "atty 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)", 79 | "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", 80 | "strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", 81 | "textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", 82 | "unicode-width 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", 83 | "vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", 84 | ] 85 | 86 | [[package]] 87 | name = "cloudabi" 88 | version = "0.0.3" 89 | source = "registry+https://github.com/rust-lang/crates.io-index" 90 | dependencies = [ 91 | "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", 92 | ] 93 | 94 | [[package]] 95 | name = "color_quant" 96 | version = "1.0.1" 97 | source = "registry+https://github.com/rust-lang/crates.io-index" 98 | 99 | [[package]] 100 | name = "crc32fast" 101 | version = "1.2.0" 102 | source = "registry+https://github.com/rust-lang/crates.io-index" 103 | dependencies = [ 104 | "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", 105 | ] 106 | 107 | [[package]] 108 | name = "crossbeam-deque" 109 | version = "0.2.0" 110 | source = "registry+https://github.com/rust-lang/crates.io-index" 111 | dependencies = [ 112 | "crossbeam-epoch 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", 113 | "crossbeam-utils 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", 114 | ] 115 | 116 | [[package]] 117 | name = "crossbeam-epoch" 118 | version = "0.3.1" 119 | source = "registry+https://github.com/rust-lang/crates.io-index" 120 | dependencies = [ 121 | "arrayvec 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", 122 | "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", 123 | "crossbeam-utils 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", 124 | "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", 125 | "memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", 126 | "nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", 127 | "scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", 128 | ] 129 | 130 | [[package]] 131 | name = "crossbeam-utils" 132 | version = "0.2.2" 133 | source = "registry+https://github.com/rust-lang/crates.io-index" 134 | dependencies = [ 135 | "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", 136 | ] 137 | 138 | [[package]] 139 | name = "deflate" 140 | version = "0.7.19" 141 | source = "registry+https://github.com/rust-lang/crates.io-index" 142 | dependencies = [ 143 | "adler32 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", 144 | "byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)", 145 | ] 146 | 147 | [[package]] 148 | name = "dtoa" 149 | version = "0.4.4" 150 | source = "registry+https://github.com/rust-lang/crates.io-index" 151 | 152 | [[package]] 153 | name = "either" 154 | version = "1.5.0" 155 | source = "registry+https://github.com/rust-lang/crates.io-index" 156 | 157 | [[package]] 158 | name = "fuchsia-cprng" 159 | version = "0.1.1" 160 | source = "registry+https://github.com/rust-lang/crates.io-index" 161 | 162 | [[package]] 163 | name = "generic-array" 164 | version = "0.12.0" 165 | source = "registry+https://github.com/rust-lang/crates.io-index" 166 | dependencies = [ 167 | "typenum 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)", 168 | ] 169 | 170 | [[package]] 171 | name = "gif" 172 | version = "0.10.1" 173 | source = "registry+https://github.com/rust-lang/crates.io-index" 174 | dependencies = [ 175 | "color_quant 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", 176 | "lzw 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", 177 | ] 178 | 179 | [[package]] 180 | name = "image" 181 | version = "0.22.1" 182 | source = "registry+https://github.com/rust-lang/crates.io-index" 183 | dependencies = [ 184 | "byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)", 185 | "gif 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)", 186 | "jpeg-decoder 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)", 187 | "lzw 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", 188 | "num-iter 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)", 189 | "num-rational 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", 190 | "num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", 191 | "png 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)", 192 | "scoped_threadpool 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", 193 | "tiff 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", 194 | ] 195 | 196 | [[package]] 197 | name = "inflate" 198 | version = "0.4.3" 199 | source = "registry+https://github.com/rust-lang/crates.io-index" 200 | dependencies = [ 201 | "adler32 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", 202 | ] 203 | 204 | [[package]] 205 | name = "jpeg-decoder" 206 | version = "0.1.15" 207 | source = "registry+https://github.com/rust-lang/crates.io-index" 208 | dependencies = [ 209 | "byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)", 210 | "rayon 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", 211 | ] 212 | 213 | [[package]] 214 | name = "lazy_static" 215 | version = "1.2.0" 216 | source = "registry+https://github.com/rust-lang/crates.io-index" 217 | 218 | [[package]] 219 | name = "libc" 220 | version = "0.2.44" 221 | source = "registry+https://github.com/rust-lang/crates.io-index" 222 | 223 | [[package]] 224 | name = "libm" 225 | version = "0.1.2" 226 | source = "registry+https://github.com/rust-lang/crates.io-index" 227 | 228 | [[package]] 229 | name = "linked-hash-map" 230 | version = "0.5.2" 231 | source = "registry+https://github.com/rust-lang/crates.io-index" 232 | 233 | [[package]] 234 | name = "lystem" 235 | version = "0.1.0" 236 | dependencies = [ 237 | "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", 238 | "image 0.22.1 (registry+https://github.com/rust-lang/crates.io-index)", 239 | "nalgebra 0.18.0 (registry+https://github.com/rust-lang/crates.io-index)", 240 | "serde 1.0.98 (registry+https://github.com/rust-lang/crates.io-index)", 241 | "serde_yaml 0.8.9 (registry+https://github.com/rust-lang/crates.io-index)", 242 | ] 243 | 244 | [[package]] 245 | name = "lzw" 246 | version = "0.10.0" 247 | source = "registry+https://github.com/rust-lang/crates.io-index" 248 | 249 | [[package]] 250 | name = "matrixmultiply" 251 | version = "0.2.2" 252 | source = "registry+https://github.com/rust-lang/crates.io-index" 253 | dependencies = [ 254 | "rawpointer 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", 255 | ] 256 | 257 | [[package]] 258 | name = "memoffset" 259 | version = "0.2.1" 260 | source = "registry+https://github.com/rust-lang/crates.io-index" 261 | 262 | [[package]] 263 | name = "nalgebra" 264 | version = "0.18.0" 265 | source = "registry+https://github.com/rust-lang/crates.io-index" 266 | dependencies = [ 267 | "alga 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", 268 | "approx 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", 269 | "generic-array 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", 270 | "matrixmultiply 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", 271 | "num-complex 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", 272 | "num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", 273 | "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", 274 | "typenum 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)", 275 | ] 276 | 277 | [[package]] 278 | name = "nodrop" 279 | version = "0.1.13" 280 | source = "registry+https://github.com/rust-lang/crates.io-index" 281 | 282 | [[package]] 283 | name = "num-complex" 284 | version = "0.2.1" 285 | source = "registry+https://github.com/rust-lang/crates.io-index" 286 | dependencies = [ 287 | "num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", 288 | ] 289 | 290 | [[package]] 291 | name = "num-derive" 292 | version = "0.2.3" 293 | source = "registry+https://github.com/rust-lang/crates.io-index" 294 | dependencies = [ 295 | "num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", 296 | "proc-macro2 0.4.24 (registry+https://github.com/rust-lang/crates.io-index)", 297 | "quote 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", 298 | "syn 0.15.22 (registry+https://github.com/rust-lang/crates.io-index)", 299 | ] 300 | 301 | [[package]] 302 | name = "num-integer" 303 | version = "0.1.39" 304 | source = "registry+https://github.com/rust-lang/crates.io-index" 305 | dependencies = [ 306 | "num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", 307 | ] 308 | 309 | [[package]] 310 | name = "num-iter" 311 | version = "0.1.37" 312 | source = "registry+https://github.com/rust-lang/crates.io-index" 313 | dependencies = [ 314 | "num-integer 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)", 315 | "num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", 316 | ] 317 | 318 | [[package]] 319 | name = "num-rational" 320 | version = "0.2.1" 321 | source = "registry+https://github.com/rust-lang/crates.io-index" 322 | dependencies = [ 323 | "num-integer 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)", 324 | "num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", 325 | ] 326 | 327 | [[package]] 328 | name = "num-traits" 329 | version = "0.2.6" 330 | source = "registry+https://github.com/rust-lang/crates.io-index" 331 | 332 | [[package]] 333 | name = "num_cpus" 334 | version = "1.8.0" 335 | source = "registry+https://github.com/rust-lang/crates.io-index" 336 | dependencies = [ 337 | "libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)", 338 | ] 339 | 340 | [[package]] 341 | name = "png" 342 | version = "0.15.0" 343 | source = "registry+https://github.com/rust-lang/crates.io-index" 344 | dependencies = [ 345 | "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", 346 | "crc32fast 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", 347 | "deflate 0.7.19 (registry+https://github.com/rust-lang/crates.io-index)", 348 | "inflate 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", 349 | ] 350 | 351 | [[package]] 352 | name = "proc-macro2" 353 | version = "0.4.24" 354 | source = "registry+https://github.com/rust-lang/crates.io-index" 355 | dependencies = [ 356 | "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", 357 | ] 358 | 359 | [[package]] 360 | name = "quote" 361 | version = "0.6.10" 362 | source = "registry+https://github.com/rust-lang/crates.io-index" 363 | dependencies = [ 364 | "proc-macro2 0.4.24 (registry+https://github.com/rust-lang/crates.io-index)", 365 | ] 366 | 367 | [[package]] 368 | name = "rand" 369 | version = "0.6.5" 370 | source = "registry+https://github.com/rust-lang/crates.io-index" 371 | dependencies = [ 372 | "autocfg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", 373 | "libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)", 374 | "rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", 375 | "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", 376 | "rand_hc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", 377 | "rand_isaac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", 378 | "rand_jitter 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", 379 | "rand_os 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", 380 | "rand_pcg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", 381 | "rand_xorshift 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", 382 | "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", 383 | ] 384 | 385 | [[package]] 386 | name = "rand_chacha" 387 | version = "0.1.1" 388 | source = "registry+https://github.com/rust-lang/crates.io-index" 389 | dependencies = [ 390 | "autocfg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", 391 | "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", 392 | ] 393 | 394 | [[package]] 395 | name = "rand_core" 396 | version = "0.3.1" 397 | source = "registry+https://github.com/rust-lang/crates.io-index" 398 | dependencies = [ 399 | "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", 400 | ] 401 | 402 | [[package]] 403 | name = "rand_core" 404 | version = "0.4.0" 405 | source = "registry+https://github.com/rust-lang/crates.io-index" 406 | 407 | [[package]] 408 | name = "rand_hc" 409 | version = "0.1.0" 410 | source = "registry+https://github.com/rust-lang/crates.io-index" 411 | dependencies = [ 412 | "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", 413 | ] 414 | 415 | [[package]] 416 | name = "rand_isaac" 417 | version = "0.1.1" 418 | source = "registry+https://github.com/rust-lang/crates.io-index" 419 | dependencies = [ 420 | "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", 421 | ] 422 | 423 | [[package]] 424 | name = "rand_jitter" 425 | version = "0.1.3" 426 | source = "registry+https://github.com/rust-lang/crates.io-index" 427 | dependencies = [ 428 | "libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)", 429 | "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", 430 | "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", 431 | ] 432 | 433 | [[package]] 434 | name = "rand_os" 435 | version = "0.1.3" 436 | source = "registry+https://github.com/rust-lang/crates.io-index" 437 | dependencies = [ 438 | "cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", 439 | "fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", 440 | "libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)", 441 | "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", 442 | "rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", 443 | "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", 444 | ] 445 | 446 | [[package]] 447 | name = "rand_pcg" 448 | version = "0.1.2" 449 | source = "registry+https://github.com/rust-lang/crates.io-index" 450 | dependencies = [ 451 | "autocfg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", 452 | "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", 453 | ] 454 | 455 | [[package]] 456 | name = "rand_xorshift" 457 | version = "0.1.1" 458 | source = "registry+https://github.com/rust-lang/crates.io-index" 459 | dependencies = [ 460 | "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", 461 | ] 462 | 463 | [[package]] 464 | name = "rawpointer" 465 | version = "0.1.0" 466 | source = "registry+https://github.com/rust-lang/crates.io-index" 467 | 468 | [[package]] 469 | name = "rayon" 470 | version = "1.0.3" 471 | source = "registry+https://github.com/rust-lang/crates.io-index" 472 | dependencies = [ 473 | "crossbeam-deque 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", 474 | "either 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)", 475 | "rayon-core 1.4.1 (registry+https://github.com/rust-lang/crates.io-index)", 476 | ] 477 | 478 | [[package]] 479 | name = "rayon-core" 480 | version = "1.4.1" 481 | source = "registry+https://github.com/rust-lang/crates.io-index" 482 | dependencies = [ 483 | "crossbeam-deque 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", 484 | "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", 485 | "libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)", 486 | "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", 487 | ] 488 | 489 | [[package]] 490 | name = "rdrand" 491 | version = "0.4.0" 492 | source = "registry+https://github.com/rust-lang/crates.io-index" 493 | dependencies = [ 494 | "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", 495 | ] 496 | 497 | [[package]] 498 | name = "scoped_threadpool" 499 | version = "0.1.9" 500 | source = "registry+https://github.com/rust-lang/crates.io-index" 501 | 502 | [[package]] 503 | name = "scopeguard" 504 | version = "0.3.3" 505 | source = "registry+https://github.com/rust-lang/crates.io-index" 506 | 507 | [[package]] 508 | name = "serde" 509 | version = "1.0.98" 510 | source = "registry+https://github.com/rust-lang/crates.io-index" 511 | dependencies = [ 512 | "serde_derive 1.0.98 (registry+https://github.com/rust-lang/crates.io-index)", 513 | ] 514 | 515 | [[package]] 516 | name = "serde_derive" 517 | version = "1.0.98" 518 | source = "registry+https://github.com/rust-lang/crates.io-index" 519 | dependencies = [ 520 | "proc-macro2 0.4.24 (registry+https://github.com/rust-lang/crates.io-index)", 521 | "quote 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", 522 | "syn 0.15.22 (registry+https://github.com/rust-lang/crates.io-index)", 523 | ] 524 | 525 | [[package]] 526 | name = "serde_yaml" 527 | version = "0.8.9" 528 | source = "registry+https://github.com/rust-lang/crates.io-index" 529 | dependencies = [ 530 | "dtoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", 531 | "linked-hash-map 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", 532 | "serde 1.0.98 (registry+https://github.com/rust-lang/crates.io-index)", 533 | "yaml-rust 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", 534 | ] 535 | 536 | [[package]] 537 | name = "strsim" 538 | version = "0.8.0" 539 | source = "registry+https://github.com/rust-lang/crates.io-index" 540 | 541 | [[package]] 542 | name = "syn" 543 | version = "0.15.22" 544 | source = "registry+https://github.com/rust-lang/crates.io-index" 545 | dependencies = [ 546 | "proc-macro2 0.4.24 (registry+https://github.com/rust-lang/crates.io-index)", 547 | "quote 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", 548 | "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", 549 | ] 550 | 551 | [[package]] 552 | name = "textwrap" 553 | version = "0.11.0" 554 | source = "registry+https://github.com/rust-lang/crates.io-index" 555 | dependencies = [ 556 | "unicode-width 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", 557 | ] 558 | 559 | [[package]] 560 | name = "tiff" 561 | version = "0.3.1" 562 | source = "registry+https://github.com/rust-lang/crates.io-index" 563 | dependencies = [ 564 | "byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)", 565 | "lzw 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", 566 | "num-derive 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", 567 | "num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", 568 | ] 569 | 570 | [[package]] 571 | name = "typenum" 572 | version = "1.10.0" 573 | source = "registry+https://github.com/rust-lang/crates.io-index" 574 | 575 | [[package]] 576 | name = "unicode-width" 577 | version = "0.1.6" 578 | source = "registry+https://github.com/rust-lang/crates.io-index" 579 | 580 | [[package]] 581 | name = "unicode-xid" 582 | version = "0.1.0" 583 | source = "registry+https://github.com/rust-lang/crates.io-index" 584 | 585 | [[package]] 586 | name = "vec_map" 587 | version = "0.8.1" 588 | source = "registry+https://github.com/rust-lang/crates.io-index" 589 | 590 | [[package]] 591 | name = "winapi" 592 | version = "0.3.7" 593 | source = "registry+https://github.com/rust-lang/crates.io-index" 594 | dependencies = [ 595 | "winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", 596 | "winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", 597 | ] 598 | 599 | [[package]] 600 | name = "winapi-i686-pc-windows-gnu" 601 | version = "0.4.0" 602 | source = "registry+https://github.com/rust-lang/crates.io-index" 603 | 604 | [[package]] 605 | name = "winapi-x86_64-pc-windows-gnu" 606 | version = "0.4.0" 607 | source = "registry+https://github.com/rust-lang/crates.io-index" 608 | 609 | [[package]] 610 | name = "yaml-rust" 611 | version = "0.4.3" 612 | source = "registry+https://github.com/rust-lang/crates.io-index" 613 | dependencies = [ 614 | "linked-hash-map 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", 615 | ] 616 | 617 | [metadata] 618 | "checksum adler32 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7e522997b529f05601e05166c07ed17789691f562762c7f3b987263d2dedee5c" 619 | "checksum alga 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a033171acc255e6d0c6490e701097632377c2435fdf084a2a4c0cbeb9e1395ac" 620 | "checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b" 621 | "checksum approx 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f0e60b75072ecd4168020818c0107f2857bb6c4e64252d8d3983f6263b40a5c3" 622 | "checksum arrayvec 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "f405cc4c21cd8b784f6c8fc2adf9bc00f59558f0049b5ec21517f875963040cc" 623 | "checksum atty 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)" = "1803c647a3ec87095e7ae7acfca019e98de5ec9a7d01343f611cf3152ed71a90" 624 | "checksum autocfg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a6d640bee2da49f60a4068a7fae53acde8982514ab7bae8b8cea9e88cbcfd799" 625 | "checksum bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "228047a76f468627ca71776ecdebd732a3423081fcf5125585bcd7c49886ce12" 626 | "checksum byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "94f88df23a25417badc922ab0f5716cc1330e87f71ddd9203b3a3ccd9cedf75d" 627 | "checksum cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "082bb9b28e00d3c9d39cc03e64ce4cea0f1bb9b3fde493f0cbc008472d22bdf4" 628 | "checksum clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5067f5bb2d80ef5d68b4c87db81601f0b75bca627bc2ef76b141d7b846a3c6d9" 629 | "checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" 630 | "checksum color_quant 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0dbbb57365263e881e805dc77d94697c9118fd94d8da011240555aa7b23445bd" 631 | "checksum crc32fast 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ba125de2af0df55319f41944744ad91c71113bf74a4646efff39afe1f6842db1" 632 | "checksum crossbeam-deque 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f739f8c5363aca78cfb059edf753d8f0d36908c348f3d8d1503f03d8b75d9cf3" 633 | "checksum crossbeam-epoch 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "927121f5407de9956180ff5e936fe3cf4324279280001cd56b669d28ee7e9150" 634 | "checksum crossbeam-utils 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2760899e32a1d58d5abb31129f8fae5de75220bc2176e77ff7c627ae45c918d9" 635 | "checksum deflate 0.7.19 (registry+https://github.com/rust-lang/crates.io-index)" = "8a6abb26e16e8d419b5c78662aa9f82857c2386a073da266840e474d5055ec86" 636 | "checksum dtoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "ea57b42383d091c85abcc2706240b94ab2a8fa1fc81c10ff23c4de06e2a90b5e" 637 | "checksum either 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3be565ca5c557d7f59e7cfcf1844f9e3033650c929c6566f511e8005f205c1d0" 638 | "checksum fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" 639 | "checksum generic-array 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3c0f28c2f5bfb5960175af447a2da7c18900693738343dc896ffbcabd9839592" 640 | "checksum gif 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "dd4bca55ac1f213920ce3527ccd62386f1f15fa3f1714aeee1cf93f2c416903f" 641 | "checksum image 0.22.1 (registry+https://github.com/rust-lang/crates.io-index)" = "663a975007e0b49903e2e8ac0db2c432c465855f2d65f17883ba1476e85f0b42" 642 | "checksum inflate 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "6f53b811ee8e2057ccf9643ca6b4277de90efaf5e61e55fd5254576926bb4245" 643 | "checksum jpeg-decoder 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)" = "c8b7d43206b34b3f94ea9445174bda196e772049b9bddbc620c9d29b2d20110d" 644 | "checksum lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a374c89b9db55895453a74c1e38861d9deec0b01b405a82516e9d5de4820dea1" 645 | "checksum libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)" = "10923947f84a519a45c8fefb7dd1b3e8c08747993381adee176d7a82b4195311" 646 | "checksum libm 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "03c0bb6d5ce1b5cc6fd0578ec1cbc18c9d88b5b591a5c7c1d6c6175e266a0819" 647 | "checksum linked-hash-map 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "ae91b68aebc4ddb91978b11a1b02ddd8602a05ec19002801c5666000e05e0f83" 648 | "checksum lzw 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7d947cbb889ed21c2a84be6ffbaebf5b4e0f4340638cba0444907e38b56be084" 649 | "checksum matrixmultiply 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dcfed72d871629daa12b25af198f110e8095d7650f5f4c61c5bac28364604f9b" 650 | "checksum memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0f9dc261e2b62d7a622bf416ea3c5245cdd5d9a7fcc428c0d06804dfce1775b3" 651 | "checksum nalgebra 0.18.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8e12856109b5cb8e2934b5e45e4624839416e1c6c1f7d286711a7a66b79db29d" 652 | "checksum nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "2f9667ddcc6cc8a43afc9b7917599d7216aa09c463919ea32c59ed6cac8bc945" 653 | "checksum num-complex 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "107b9be86cd2481930688277b675b0114578227f034674726605b8a482d8baf8" 654 | "checksum num-derive 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8af1847c907c2f04d7bfd572fb25bbb4385c637fe5be163cf2f8c5d778fe1e7d" 655 | "checksum num-integer 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)" = "e83d528d2677f0518c570baf2b7abdcf0cd2d248860b68507bdcb3e91d4c0cea" 656 | "checksum num-iter 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)" = "af3fdbbc3291a5464dc57b03860ec37ca6bf915ed6ee385e7c6c052c422b2124" 657 | "checksum num-rational 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4e96f040177bb3da242b5b1ecf3f54b5d5af3efbbfb18608977a5d2767b22f10" 658 | "checksum num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "0b3a5d7cc97d6d30d8b9bc8fa19bf45349ffe46241e8816f50f62f6d6aaabee1" 659 | "checksum num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c51a3322e4bca9d212ad9a158a02abc6934d005490c054a2778df73a70aa0a30" 660 | "checksum png 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8422b27bb2c013dd97b9aef69e161ce262236f49aaf46a0489011c8ff0264602" 661 | "checksum proc-macro2 0.4.24 (registry+https://github.com/rust-lang/crates.io-index)" = "77619697826f31a02ae974457af0b29b723e5619e113e9397b8b82c6bd253f09" 662 | "checksum quote 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)" = "53fa22a1994bd0f9372d7a816207d8a2677ad0325b073f5c5332760f0fb62b5c" 663 | "checksum rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "6d71dacdc3c88c1fde3885a3be3fbab9f35724e6ce99467f7d9c5026132184ca" 664 | "checksum rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "556d3a1ca6600bfcbab7c7c91ccb085ac7fbbcd70e008a98742e7847f4f7bcef" 665 | "checksum rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b" 666 | "checksum rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d0e7a549d590831370895ab7ba4ea0c1b6b011d106b5ff2da6eee112615e6dc0" 667 | "checksum rand_hc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7b40677c7be09ae76218dc623efbf7b18e34bced3f38883af07bb75630a21bc4" 668 | "checksum rand_isaac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ded997c9d5f13925be2a6fd7e66bf1872597f759fd9dd93513dd7e92e5a5ee08" 669 | "checksum rand_jitter 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7b9ea758282efe12823e0d952ddb269d2e1897227e464919a554f2a03ef1b832" 670 | "checksum rand_os 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7b75f676a1e053fc562eafbb47838d67c84801e38fc1ba459e8f180deabd5071" 671 | "checksum rand_pcg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "abf9b09b01790cfe0364f52bf32995ea3c39f4d2dd011eac241d2914146d0b44" 672 | "checksum rand_xorshift 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cbf7e9e623549b0e21f6e97cf8ecf247c1a8fd2e8a992ae265314300b2455d5c" 673 | "checksum rawpointer 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ebac11a9d2e11f2af219b8b8d833b76b1ea0e054aa0e8d8e9e4cbde353bdf019" 674 | "checksum rayon 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "373814f27745b2686b350dd261bfd24576a6fb0e2c5919b3a2b6005f820b0473" 675 | "checksum rayon-core 1.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b055d1e92aba6877574d8fe604a63c8b5df60f60e5982bf7ccbb1338ea527356" 676 | "checksum rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2" 677 | "checksum scoped_threadpool 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "1d51f5df5af43ab3f1360b429fa5e0152ac5ce8c0bd6485cae490332e96846a8" 678 | "checksum scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "94258f53601af11e6a49f722422f6e3425c52b06245a5cf9bc09908b174f5e27" 679 | "checksum serde 1.0.98 (registry+https://github.com/rust-lang/crates.io-index)" = "7fe5626ac617da2f2d9c48af5515a21d5a480dbd151e01bb1c355e26a3e68113" 680 | "checksum serde_derive 1.0.98 (registry+https://github.com/rust-lang/crates.io-index)" = "01e69e1b8a631f245467ee275b8c757b818653c6d704cdbcaeb56b56767b529c" 681 | "checksum serde_yaml 0.8.9 (registry+https://github.com/rust-lang/crates.io-index)" = "38b08a9a90e5260fe01c6480ec7c811606df6d3a660415808c3c3fa8ed95b582" 682 | "checksum strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" 683 | "checksum syn 0.15.22 (registry+https://github.com/rust-lang/crates.io-index)" = "ae8b29eb5210bc5cf63ed6149cbf9adfc82ac0be023d8735c176ee74a2db4da7" 684 | "checksum textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" 685 | "checksum tiff 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d7b7c2cfc4742bd8a32f2e614339dd8ce30dbcf676bb262bd63a2327bc5df57d" 686 | "checksum typenum 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "612d636f949607bdf9b123b4a6f6d966dedf3ff669f7f045890d3a4a73948169" 687 | "checksum unicode-width 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "7007dbd421b92cc6e28410fe7362e2e0a2503394908f417b68ec8d1c364c4e20" 688 | "checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" 689 | "checksum vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "05c78687fb1a80548ae3250346c3db86a80a7cdd77bda190189f2d0a0987c81a" 690 | "checksum winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "f10e386af2b13e47c89e7236a7a14a086791a2b88ebad6df9bf42040195cf770" 691 | "checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" 692 | "checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" 693 | "checksum yaml-rust 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "65923dd1784f44da1d2c3dbbc5e822045628c590ba72123e1c73d3c230c4434d" 694 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "lystem" 3 | version = "0.1.0" 4 | authors = ["Piripant "] 5 | edition = "2018" 6 | 7 | [dependencies] 8 | image = "0.22.1" 9 | nalgebra = "0.18.0" 10 | serde = { version = "1.0.98", features = ["derive"] } 11 | serde_yaml = "0.8.9" 12 | clap = "2.33.0" -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Lystem 2 | Lystem is cross platform command line application to render L-System interpreted as turtle instructins. The program renders a series of images, one for each instruction (or more). It does not directly make a video, for that you can use something like ffmpeg with: 3 | ``` 4 | ffmpeg -r 60 -i images/out%d.png output.mp4 5 | ``` 6 | 7 | The LSystem generator is made to occupy as little memory as possible, so it can run on limited devices too. 8 | 9 | Contributions are welcome and at the start of `src/main.rs` you can find a TODO list. 10 | 11 | ## Usage 12 | You can build the project with `cargo` 13 | ``` 14 | cargo run --release -- [ARGS] 15 | ``` 16 | 17 | There are two required parameters, the input configuration, and the number of generations to simulate 18 | ``` 19 | cargo run --release -- configs/maze.yml 3 20 | ``` 21 | This will render the images of the 3rd generation of maze.yml, interpreted by the turtle as specified in the file. 22 | 23 | Optional parameters are: 24 | * `-l` which sets the program to only render the last frame (when all the turtle instruction have been executed) 25 | * `-s` which sets how many turtle instructions should be executed in each frame (translates to the playback speed, there more instruction you interpret per frame, the faster the video will be) 26 | 27 | ## Configuration files 28 | The L-System axiom and rules, along with the instructions to interpret the characters as turtle commands are written in yaml files. You can find many examples in the `configs` directory. 29 | 30 | ```yml 31 | axiom: F+F+F+F 32 | 33 | start_state: 34 | 'color_r': 255 35 | 'color_b': 255 36 | 'step': 1 37 | 'turning_angle': 90 38 | 39 | rules: 40 | 'F': FF+F+F+F+FF 41 | 42 | commands: 43 | 'F': 44 | - forward 45 | - add color_r -1 46 | '+': 47 | - clockwise 48 | ``` 49 | 50 | * `axiom` indicates the system axiom, each character is interpreted as a single symbol, only ASCII character are supported 51 | * `start_state` describes the turtle initial state, there are many variables accessible: 52 | * `color_r`, `color_g`, `color_b` to indicate the r,g,b values of the turtle drawing color, from 0 to 255 53 | * `step` which sets how far the turtle travels each time it goes forward 54 | * `turning_angle` turning angle of the turle used by the `clockwise` and `counterclockwise` commands 55 | * `rotation` the initial rotation of the turtle 56 | 57 | * `rules` tells how each symbol evolves 58 | * `commands` says how to interpret the symbol as a turtle command 59 | * `forward` makes the turtle go foward by `step` 60 | * `clockwise`/`counterclockwise` makes the turtle turn clockwise/counterclockwise by `turning_angle` 61 | * `push_stack` pushed the current turtle state on the stack 62 | * `pop_stack` pops the stack on the current turtle state 63 | * `add`/`multiply`/`set` are functions which take two arguments, the variable to change and the value to apply. A variable can also be used as a value: `add turning_angle step` adds the value of step to the turning_angle. An integer can also handle operations with a decimal number (`multiply color_r 1.5`), being rounded toward -infinity after the calculations. 64 | 65 | ## Lystem in action 66 | ![from configs/board.yml](gifs/board.gif) 67 | 68 | ![from configs/crystal.yml](gifs/crystal.gif) 69 | 70 | ![from configs/maze.yml (this one is not a gif)](gifs/maze.png) 71 | 72 | ![from configs/tree.yml (this one is not a gif either)](gifs/tree.png) -------------------------------------------------------------------------------- /configs/basic2.yml: -------------------------------------------------------------------------------- 1 | axiom: F+F+F+F 2 | 3 | start_state: 4 | 'color_r': 255 5 | 'step': 7 6 | 7 | rules: 8 | 'F': FF+F-F+F+FF 9 | 10 | commands: 11 | 'F': 12 | - forward 13 | - add color_r -1 14 | - add color_g 2 15 | - add color_b 4 16 | '+': 17 | - clockwise 18 | '-': 19 | - counterclockwise -------------------------------------------------------------------------------- /configs/board.yml: -------------------------------------------------------------------------------- 1 | axiom: F+F+F+F 2 | 3 | start_state: 4 | 'color_r': 255 5 | 'color_b': 255 6 | 'step': 1 7 | 'turning_angle': 90 8 | 9 | rules: 10 | 'F': FF+F+F+F+FF 11 | 12 | commands: 13 | 'F': 14 | - forward 15 | - add color_r -1 16 | '+': 17 | - clockwise -------------------------------------------------------------------------------- /configs/crystal.yml: -------------------------------------------------------------------------------- 1 | axiom: F+F+F+F 2 | 3 | start_state: 4 | 'color_r': 255 5 | 'color_b': 255 6 | 'step': 1 7 | 'turning_angle': 90 8 | 9 | rules: 10 | 'F': FF+F++F+F 11 | 12 | commands: 13 | 'F': 14 | - forward 15 | - add color_r -1 16 | '+': 17 | - clockwise 18 | '-': 19 | - counterclockwise -------------------------------------------------------------------------------- /configs/debian.yml: -------------------------------------------------------------------------------- 1 | # run this with 5 generations to get the debian logo 2 | # or with 9 generation to get a double debian logo 3 | 4 | axiom: F 5 | 6 | start_state: 7 | 'color_r': 215 8 | 'color_g': 7 9 | 'color_b': 81 10 | 11 | 'step': 15 12 | 'rotation': -130 13 | 'turning_angle': 0 14 | 15 | rules: 16 | F: F+F 17 | 18 | commands: 19 | 'F': 20 | - forward 21 | '+': 22 | - add turning_angle 1 23 | - clockwise -------------------------------------------------------------------------------- /configs/koch.yml: -------------------------------------------------------------------------------- 1 | axiom: F 2 | 3 | start_state: 4 | 'color_r': 255 5 | 'step': 5 6 | 'turning_angle': 90 7 | 8 | rules: 9 | F: F+F-F-F+F 10 | 11 | commands: 12 | 'F': 13 | - forward 14 | '+': 15 | - counterclockwise 16 | '-': 17 | - clockwise -------------------------------------------------------------------------------- /configs/maze.yml: -------------------------------------------------------------------------------- 1 | axiom: '-YF' 2 | 3 | start_state: 4 | 'color_r': 255 5 | 'color_b': 127 6 | 'step': 5 7 | 'turning_angle': 90.0 8 | 9 | rules: 10 | 'X': 'XFX-YF-YF+FX+FX-YF-YFFX+YF+FXFXYF-FX+YF+FXFX+YF-FXYF-YF-FX+FX+YFYF-' 11 | 'Y': '+FXFX-YF-YF+FX+FXYF+FX-YFYF-FX-YF+FXYFYF-FX-YFFX+FX+YF-YF-FX+FX+YFY' 12 | 13 | commands: 14 | 'F': 15 | - forward 16 | '+': 17 | - clockwise 18 | - set color_r 127 19 | - set color_b 255 20 | '-': 21 | - counterclockwise 22 | - set color_r 255 23 | - set color_b 127 -------------------------------------------------------------------------------- /configs/mega_donout.yml: -------------------------------------------------------------------------------- 1 | axiom: F+F+F+F 2 | 3 | start_state: 4 | 'color_r': 0 5 | 'color_g': 0 6 | 'color_b': 1 7 | 'step': 1 8 | 9 | rules: 10 | 'F': FF+F-F+F+FF 11 | 12 | commands: 13 | 'F': 14 | - forward 15 | - multiply color_b 3 16 | '+': 17 | - clockwise 18 | - set step 10 19 | '-': 20 | - counterclockwise 21 | - set step 2 -------------------------------------------------------------------------------- /configs/rainbow.yml: -------------------------------------------------------------------------------- 1 | axiom: F+F+F+F 2 | 3 | start_state: 4 | 'color_r': 255 5 | 'step': 5 6 | 7 | rules: 8 | 'F': F+F-F-FF+F+F-F 9 | 10 | commands: 11 | 'F': 12 | - forward 13 | - add color_r -1 14 | - add color_g 2 15 | - add color_b 3 16 | '+': 17 | - clockwise 18 | '-': 19 | - counterclockwise -------------------------------------------------------------------------------- /configs/sierpinski.yml: -------------------------------------------------------------------------------- 1 | axiom: F+XF+F+XF 2 | 3 | start_state: 4 | 'color_r': 255 5 | 'step': 10 6 | 'turning_angle': 60 7 | 8 | rules: 9 | X: XF-F+F-XF+F+XF-F+F-X 10 | 11 | commands: 12 | 'F': 13 | - forward 14 | '+': 15 | - counterclockwise 16 | '-': 17 | - clockwise -------------------------------------------------------------------------------- /configs/tree.yml: -------------------------------------------------------------------------------- 1 | axiom: X 2 | 3 | rules: 4 | 'F': FF 5 | 'X': F-[[X]+X]+F[+FX]-X 6 | 7 | start_state: 8 | 'color_r': 255 9 | 'color_g': 175 10 | 'turning_angle': 22.5 11 | 'step': 5 12 | 'rotation': 270 13 | 14 | commands: 15 | 'F': 16 | - forward 17 | - add color_r -1 18 | '[': 19 | - push_stack 20 | ']': 21 | - pop_stack 22 | # by doing this we are making the branches lean like they have wind blowing 23 | # - add turning_angle 4 24 | '+': 25 | - clockwise 26 | '-': 27 | - counterclockwise -------------------------------------------------------------------------------- /configs/triangle.yml: -------------------------------------------------------------------------------- 1 | axiom: F+F+F 2 | 3 | start_state: 4 | 'color_r': 255 5 | 'step': 10 6 | 'turning_angle': 120 7 | 8 | rules: 9 | F: F-F+F 10 | 11 | commands: 12 | 'F': 13 | - forward 14 | '+': 15 | - clockwise 16 | '-': 17 | - counterclockwise -------------------------------------------------------------------------------- /gifs/board.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Piripant/Lystem/ca2ae55b1faf79b0c2a73c6fdb7c6c6e0794aa9f/gifs/board.gif -------------------------------------------------------------------------------- /gifs/crystal.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Piripant/Lystem/ca2ae55b1faf79b0c2a73c6fdb7c6c6e0794aa9f/gifs/crystal.gif -------------------------------------------------------------------------------- /gifs/maze.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Piripant/Lystem/ca2ae55b1faf79b0c2a73c6fdb7c6c6e0794aa9f/gifs/maze.png -------------------------------------------------------------------------------- /gifs/tree.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Piripant/Lystem/ca2ae55b1faf79b0c2a73c6fdb7c6c6e0794aa9f/gifs/tree.png -------------------------------------------------------------------------------- /make_video.sh: -------------------------------------------------------------------------------- 1 | rm images/* 2 | cargo run --release -- "$@" 3 | ffmpeg -r 60 -y -i images/out%d.png test.mp4 -------------------------------------------------------------------------------- /src/lsystem.rs: -------------------------------------------------------------------------------- 1 | use std::collections::HashMap; 2 | 3 | /// Defines the rules used by a system 4 | pub struct SystemRules { 5 | rules: HashMap>, 6 | } 7 | 8 | impl SystemRules { 9 | pub fn new() -> SystemRules { 10 | SystemRules { 11 | rules: HashMap::new(), 12 | } 13 | } 14 | 15 | pub fn add_rule(&mut self, original: u8, transformation: Vec) { 16 | self.rules.insert(original, transformation); 17 | } 18 | 19 | /// Return the next generation of a symbol according to the rules 20 | fn get_future(&self, symbol: u8) -> Vec { 21 | if let Some(next_gen) = self.rules.get(&symbol) { 22 | next_gen.clone() 23 | } else { 24 | // If there are no rules for this symbol it stays the same 25 | vec![symbol] 26 | } 27 | } 28 | } 29 | 30 | /// We simulate the L-System one symbol at a time 31 | /// ```text 32 | /// axiom: A 33 | /// / \ 34 | /// n=1: A B 35 | /// /| \ 36 | /// n=2: A B A 37 | /// / | | | \ 38 | /// n=3: A B A A B 39 | /// / | | | \ | \ \ 40 | /// n=4: A B A A B A B A 41 | /// ``` 42 | /// This diagram inlustrates the evolution of an L-System (courtesy of wikipedia) 43 | /// 44 | /// `generations` stores how many generations there are (4 in this case) 45 | /// 46 | /// `indexes` has length of generations, and indicates what was the last symbol we reached during our calculations 47 | /// 48 | /// `indexes[0]` will be at most 0, because we only have one symbol in the axiom 49 | /// 50 | /// `indexes[1]` will be at most 1, bacuase we have two symbols in the first generation 51 | /// 52 | /// `indexes[2]` will be at most 2, because we have three symbos in the second generation etc... 53 | /// 54 | /// `iterate_next` recounstructs each time the L-System tree, incrementing the last indexes 55 | /// to give us the next symbols in the last generation 56 | /// `increment` increments the indexes, staring from the last generation, and is called at the end of `interate_next` 57 | 58 | pub struct LSystem { 59 | generations: usize, 60 | // Length is always == generations 61 | indexes: Vec, 62 | axiom: Vec, 63 | } 64 | 65 | impl LSystem { 66 | pub fn new(axiom: Vec, generations: usize) -> LSystem { 67 | assert!(generations > 0); 68 | LSystem { 69 | generations, 70 | indexes: vec![0; generations], 71 | axiom, 72 | } 73 | } 74 | 75 | fn increment(&mut self, lengths: &[usize]) { 76 | self.indexes[self.generations - 1] += 1; 77 | 78 | for i in (0..self.generations).rev() { 79 | if i > 0 && self.indexes[i] >= lengths[i] { 80 | self.indexes[i] = 0; 81 | self.indexes[i - 1] += 1; 82 | } 83 | } 84 | } 85 | 86 | /// Gets the last generation's symbols, as an iterator (not an std one) 87 | pub fn iterate_over(&mut self, rules: &SystemRules) -> Option> { 88 | let mut sys = self.axiom.clone(); 89 | 90 | // We have simulated the entire generation 91 | if self.indexes[0] >= sys.len() { 92 | return None; 93 | } 94 | 95 | // How many symbols does each generation contain 96 | let mut lengths = vec![0; self.generations]; 97 | for (n, len) in lengths.iter_mut().enumerate() { 98 | // Get the last index we arrived upon 99 | let index = self.indexes[n]; 100 | // How the system evolves 101 | let future = rules.get_future(sys[index]); 102 | // Set the length of this generation 103 | *len = sys.len(); 104 | // The next generation will be the one we do calculations on 105 | sys = future; 106 | } 107 | 108 | self.increment(&lengths); 109 | Some(sys) 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /src/main.rs: -------------------------------------------------------------------------------- 1 | // to render: ffmpeg -r 60 -y -i images/out%d.png output.mp4 2 | // to resize: -vf scale=iw*2:ih*2 -sws_flags neighbor 3 | 4 | // TODO: 5 | // Invisible forward 6 | // Draw point on turtle position 7 | // Line widths (I think we havo to switch line drawing algorithm) 8 | // Make the user choose the number of still frames at the end of the video with a cli parameter 9 | // Maybe use macros to autogenerate &str -> Variable -> &mut self.xyz 10 | 11 | mod lsystem; 12 | mod scripting; 13 | mod turtle; 14 | 15 | use clap::{App, Arg}; 16 | use nalgebra::Vector2; 17 | use serde::Deserialize; 18 | use std::collections::HashMap; 19 | use std::fs::File; 20 | 21 | type Vector2f = Vector2; 22 | 23 | /// Parses the config yml files 24 | #[derive(Debug, PartialEq, Deserialize)] 25 | struct Config { 26 | axiom: String, 27 | rules: HashMap, 28 | commands: HashMap>, 29 | start_state: HashMap, 30 | } 31 | 32 | fn main() { 33 | let matches = App::new("Lystem") 34 | .version("0.1") 35 | .author("Piripant ") 36 | .about("Simulates and draws L-Systems") 37 | .arg( 38 | Arg::with_name("CONFIG") 39 | .help("Sets the L-system config file to use") 40 | .required(true) 41 | .index(1), 42 | ) 43 | .arg( 44 | Arg::with_name("GENERATIONS") 45 | .help("The number of generations to simulate") 46 | .required(true) 47 | .index(2), 48 | ) 49 | .arg( 50 | Arg::with_name("last_frame") 51 | .help("Only renders the last frame") 52 | .short("l") 53 | .long("last") 54 | .takes_value(false), 55 | ) 56 | .arg( 57 | Arg::with_name("steps") 58 | .help("How many steps per frame are rendered") 59 | .short("s") 60 | .long("steps") 61 | .takes_value(true), 62 | ) 63 | .get_matches(); 64 | 65 | let config_name = matches.value_of("CONFIG").unwrap(); 66 | let config_file = File::open(config_name).unwrap(); 67 | let config: Config = serde_yaml::from_reader(config_file).unwrap(); 68 | 69 | // Retrive all the L-system rules and axiom 70 | let mut rules = lsystem::SystemRules::new(); 71 | for (to, from) in config.rules { 72 | if !to.is_ascii() || !from.is_ascii() { 73 | panic!("Only ASCII character are allowed (non ASCII found in the config file)"); 74 | } 75 | rules.add_rule(to as u8, from.as_bytes().to_vec()); 76 | } 77 | if !config.axiom.is_ascii() { 78 | panic!("Only ASCII character are allowed (non ASCII found in the config file)"); 79 | } 80 | 81 | let axiom = config.axiom.as_bytes().to_vec(); 82 | let generations = matches.value_of("GENERATIONS").unwrap().parse().unwrap(); 83 | let mut system_generations = lsystem::LSystem::new(axiom, generations); 84 | 85 | // Retrive the turtle settings / commands 86 | let mut pen = turtle::PenState::new(); 87 | pen.load_config(&config.start_state).unwrap(); 88 | let mut turtle = turtle::Turtle::new(pen); 89 | turtle.load_config(&config.commands).unwrap(); 90 | 91 | // Start the Simulation 92 | let mut strokes = vec![]; 93 | 94 | let mut xmin = std::f32::MAX; 95 | let mut ymin = std::f32::MAX; 96 | let mut xmax = std::f32::MIN; 97 | let mut ymax = std::f32::MIN; 98 | 99 | while let Some(symbols) = system_generations.iterate_over(&rules) { 100 | for symbol in symbols { 101 | let mut new_strokes = turtle.update(symbol); 102 | if !new_strokes.is_empty() { 103 | // Find the global max/min to later generate 104 | // An image of the right size 105 | for (from, to, _) in &mut new_strokes { 106 | xmin = xmin.min(from.x).min(to.x); 107 | ymin = ymin.min(from.y).min(to.y); 108 | 109 | xmax = xmax.max(from.x).max(to.x); 110 | ymax = ymax.max(from.y).max(to.y); 111 | } 112 | 113 | strokes.extend(new_strokes); 114 | } 115 | } 116 | } 117 | 118 | // Start the drawing 119 | let last_frame = matches.is_present("last_frame"); 120 | 121 | // We will use min to make the coordinates all positive 122 | // And in this way transform them to image pixel coordinates 123 | let min = Vector2f::new(xmin, ymin); 124 | let mut img = image::ImageBuffer::new((xmax - xmin) as u32 + 1, (ymax - ymin) as u32 + 1); 125 | 126 | let step = matches.value_of("steps").map_or(1, |s| s.parse().unwrap()); 127 | for i in (0..strokes.len()).step_by(step) { 128 | for j in 0..step { 129 | if i + j >= strokes.len() { 130 | break; 131 | } 132 | 133 | let (from, to, color) = strokes[i + j]; 134 | draw_line(&mut img, color, from - min, to - min); 135 | } 136 | 137 | if !last_frame { 138 | img.save(format!("images/out{}.png", i / step)).unwrap(); 139 | if i % (step * 4) == 0 { 140 | println!("Saved {}/{}", i / step + 1, strokes.len() / step); 141 | } 142 | } 143 | } 144 | 145 | // Draw 240 still frames at the end of the video 146 | // Or just one if the user requested only the last frame 147 | let still_frames = if last_frame { 1 } else { 240 }; 148 | for i in 0..still_frames { 149 | img.save(format!("images/out{}.png", strokes.len() / step + i)) 150 | .unwrap(); 151 | 152 | if last_frame { 153 | println!( 154 | "last image saved on images/out{}.png", 155 | strokes.len() / step + i 156 | ); 157 | } 158 | } 159 | } 160 | 161 | type Vector2i = Vector2; 162 | fn draw_line(img: &mut image::RgbImage, color: [u8; 3], from: Vector2f, to: Vector2f) { 163 | let mut from = Vector2i::new(from.x as i32, from.y as i32); 164 | let to = Vector2i::new(to.x as i32, to.y as i32); 165 | 166 | let dx = (to.x - from.x).abs(); 167 | let sx = if from.x < to.x { 1 } else { -1 }; 168 | let dy = -(to.y - from.y).abs(); 169 | let sy = if from.y < to.y { 1 } else { -1 }; 170 | let mut err = dx + dy; 171 | 172 | loop { 173 | img.put_pixel(from.x as u32, from.y as u32, image::Rgb(color)); 174 | 175 | if from.x == to.x && from.y == to.y { 176 | break; 177 | } 178 | let e2 = 2 * err; 179 | if e2 >= dy { 180 | err += dy; 181 | from.x += sx; 182 | } 183 | if e2 <= dx { 184 | err += dx; 185 | from.y += sy; 186 | } 187 | } 188 | } -------------------------------------------------------------------------------- /src/scripting.rs: -------------------------------------------------------------------------------- 1 | use std::str::FromStr; 2 | 3 | // This trait is implemented for types that have to interact with the config files 4 | // Scripts for now only use floating point numbers 5 | // from_num() cannot return Self because then 6 | // we wouldn't be able to make ScriptVariable into a trait object 7 | pub trait ScriptVariable { 8 | fn from_num(&mut self, value: f64); 9 | fn to_num(&self) -> f64; 10 | } 11 | 12 | impl ScriptVariable for u8 { 13 | fn from_num(&mut self, value: f64) { 14 | *self = ((value + 256.0) % 256.0) as u8; 15 | } 16 | fn to_num(&self) -> f64 { 17 | f64::from(*self) 18 | } 19 | } 20 | 21 | impl ScriptVariable for f32 { 22 | fn from_num(&mut self, value: f64) { 23 | *self = value as f32; 24 | } 25 | fn to_num(&self) -> f64 { 26 | f64::from(*self) 27 | } 28 | } 29 | 30 | // TODO: maybe have a separate error for Variable/Token/Command 31 | use std::{error, fmt}; 32 | 33 | #[derive(Debug)] 34 | pub struct ParseError { 35 | name: String, 36 | } 37 | 38 | impl error::Error for ParseError {} 39 | impl fmt::Display for ParseError { 40 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 41 | write!( 42 | f, 43 | "Error parsing {}, token/variable/command not recognised", 44 | self.name 45 | ) 46 | } 47 | } 48 | 49 | #[derive(Copy, Clone, Debug)] 50 | pub enum Variable { 51 | Rotation, 52 | ColorR, 53 | ColorG, 54 | ColorB, 55 | TurningAngle, 56 | Step, 57 | } 58 | 59 | // Parsing is made with Rust std FromStr trait 60 | impl FromStr for Variable { 61 | type Err = ParseError; 62 | fn from_str(text: &str) -> Result { 63 | match text { 64 | "rotation" => Ok(Variable::Rotation), 65 | "color_r" => Ok(Variable::ColorR), 66 | "color_g" => Ok(Variable::ColorG), 67 | "color_b" => Ok(Variable::ColorB), 68 | "turning_angle" => Ok(Variable::TurningAngle), 69 | "step" => Ok(Variable::Step), 70 | _ => Err(ParseError { 71 | name: text.to_string(), 72 | }), 73 | } 74 | } 75 | } 76 | 77 | #[derive(Copy, Clone, Debug)] 78 | pub enum Token { 79 | Variable(Variable), 80 | Number(f64), 81 | } 82 | 83 | // Parsing is made with Rust std FromStr trait 84 | impl FromStr for Token { 85 | type Err = ParseError; 86 | fn from_str(text: &str) -> Result { 87 | // Try to parse the number as a f64 88 | // And if it fails try to parse it as a Variable 89 | Ok(match text.parse::() { 90 | Ok(n) => Token::Number(n), 91 | Err(_) => Token::Variable(text.parse()?), 92 | }) 93 | } 94 | } 95 | 96 | #[derive(Debug)] 97 | pub enum Command { 98 | Forward, 99 | ClockWise, 100 | CounterClockWise, 101 | PushStack, 102 | PopStack, 103 | 104 | Add(Variable, Token), 105 | Multiply(Variable, Token), 106 | Set(Variable, Token), 107 | } 108 | 109 | // Parsing is made with Rust std FromStr trait 110 | impl FromStr for Command { 111 | type Err = ParseError; 112 | fn from_str(text: &str) -> Result { 113 | let parsed: Vec<&str> = text.split_whitespace().collect(); 114 | let command = parsed[0]; 115 | match command { 116 | "forward" => Ok(Command::Forward), 117 | "clockwise" => Ok(Command::ClockWise), 118 | "counterclockwise" => Ok(Command::CounterClockWise), 119 | "push_stack" => Ok(Command::PushStack), 120 | "pop_stack" => Ok(Command::PopStack), 121 | "add" => { 122 | let left = parsed[1].parse()?; 123 | let right = parsed[2].parse()?; 124 | Ok(Command::Add(left, right)) 125 | } 126 | "multiply" => { 127 | let left = parsed[1].parse()?; 128 | let right = parsed[2].parse()?; 129 | Ok(Command::Multiply(left, right)) 130 | } 131 | "set" => { 132 | let left = parsed[1].parse()?; 133 | let right = parsed[2].parse()?; 134 | Ok(Command::Set(left, right)) 135 | } 136 | _ => Err(ParseError { 137 | name: command.to_string(), 138 | }), 139 | } 140 | } 141 | } 142 | -------------------------------------------------------------------------------- /src/turtle.rs: -------------------------------------------------------------------------------- 1 | use crate::scripting::{Command, ParseError, ScriptVariable, Token, Variable}; 2 | use crate::Vector2f; 3 | use std::collections::HashMap; 4 | 5 | /// Used to store the turtle state 6 | /// Does not interpret any commands on it's own 7 | #[derive(Clone, Debug, PartialEq)] 8 | pub struct PenState { 9 | position: Vector2f, 10 | color: [u8; 3], 11 | rotation: f32, 12 | 13 | step: f32, 14 | turning_angle: f32, 15 | } 16 | 17 | impl PenState { 18 | pub fn new() -> PenState { 19 | PenState { 20 | position: Vector2f::new(0.0, 0.0), 21 | color: [0, 0, 0], 22 | rotation: 0.0, 23 | step: 1.0, 24 | turning_angle: 90.0, 25 | } 26 | } 27 | 28 | pub fn load_config(&mut self, config: &HashMap) -> Result<(), ParseError> { 29 | use std::str::FromStr; 30 | for (var, value) in config { 31 | let var = Variable::from_str(var)?; 32 | self.get_variable(var).from_num(*value); 33 | } 34 | Ok(()) 35 | } 36 | 37 | fn set_rotation(&mut self, new_rotation: f32) { 38 | self.rotation = (new_rotation + 360.0) % 360.0; 39 | } 40 | 41 | fn get_direction(&self) -> Vector2f { 42 | let x = self.rotation.to_radians().cos(); 43 | let y = self.rotation.to_radians().sin(); 44 | Vector2f::new(x * self.step, y * self.step) 45 | } 46 | 47 | /// Maps the Variable enumumerator to actual variables 48 | fn get_variable(&mut self, var: Variable) -> &mut dyn ScriptVariable { 49 | match var { 50 | Variable::Rotation => &mut self.rotation, 51 | Variable::ColorR => &mut self.color[0], 52 | Variable::ColorG => &mut self.color[1], 53 | Variable::ColorB => &mut self.color[2], 54 | Variable::TurningAngle => &mut self.turning_angle, 55 | Variable::Step => &mut self.step, 56 | } 57 | } 58 | 59 | /// Returns the value of a Token as number 60 | /// If the Token contains a variable, it gets its value as a number 61 | fn get_token_num(&mut self, token: &Token) -> f64 { 62 | match token { 63 | Token::Number(n) => *n, 64 | Token::Variable(var) => self.get_variable(*var).to_num(), 65 | } 66 | } 67 | } 68 | 69 | /// Responsible of moving interpreting the commands 70 | /// And binding together the scripting and L-System 71 | /// Only tells the strokes and colors to use, does not draw to any image 72 | pub struct Turtle { 73 | pen: PenState, 74 | stack: Vec, 75 | commands: HashMap>, 76 | } 77 | 78 | impl Turtle { 79 | pub fn new(pen: PenState) -> Turtle { 80 | Turtle { 81 | pen, 82 | stack: Vec::new(), 83 | commands: HashMap::new(), 84 | } 85 | } 86 | 87 | pub fn update(&mut self, symbol: u8) -> Vec<(Vector2f, Vector2f, [u8; 3])> { 88 | let mut strokes = Vec::new(); 89 | if !self.commands.contains_key(&symbol) { 90 | return strokes; 91 | } 92 | 93 | let commands = &self.commands[&symbol]; 94 | for command in commands { 95 | match command { 96 | Command::Forward => { 97 | let n_pos = self.pen.position + self.pen.get_direction(); 98 | strokes.push((self.pen.position, n_pos, self.pen.color)); 99 | self.pen.position = n_pos; 100 | } 101 | Command::ClockWise => { 102 | self.pen 103 | .set_rotation(self.pen.rotation + self.pen.turning_angle); 104 | } 105 | Command::CounterClockWise => { 106 | self.pen 107 | .set_rotation(self.pen.rotation - self.pen.turning_angle); 108 | } 109 | Command::PushStack => { 110 | self.stack.push(self.pen.clone()); 111 | } 112 | Command::PopStack => { 113 | self.pen = self 114 | .stack 115 | .pop() 116 | .expect("A stack pop was invoked but there are no states on the stack"); 117 | } 118 | Command::Add(x, y) => { 119 | let b = self.pen.get_token_num(y); 120 | let a = self.pen.get_variable(*x); 121 | a.from_num(a.to_num() + b); 122 | } 123 | Command::Multiply(x, y) => { 124 | let b = self.pen.get_token_num(y); 125 | let a = self.pen.get_variable(*x); 126 | a.from_num(a.to_num() * b); 127 | } 128 | Command::Set(x, y) => { 129 | let b = self.pen.get_token_num(y); 130 | let a = self.pen.get_variable(*x); 131 | a.from_num(b); 132 | } 133 | } 134 | } 135 | 136 | strokes 137 | } 138 | 139 | pub fn load_config(&mut self, config: &HashMap>) -> Result<(), ParseError> { 140 | for (symbol, commands) in config { 141 | let mut list = Vec::new(); 142 | for command in commands { 143 | let cmd = command.parse()?; 144 | list.push(cmd); 145 | } 146 | self.commands.insert(*symbol as u8, list); 147 | } 148 | 149 | Ok(()) 150 | } 151 | } 152 | --------------------------------------------------------------------------------