elementary_cellular_automaton_generalized.pl 2.6 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889
  1. #!/usr/bin/perl
  2. # Daniel "Trizen" Șuteu
  3. # Date: 16 October 2019
  4. # https://github.com/trizen
  5. # Generalization of the elementary cellular automaton, by using `n` color-states and looking at `k` neighbors left-to-right.
  6. # For example, a value of `n = 3` and `k = 2` uses three different color-states and looks at 2 neighbors to the left and 2 neighbors to the right.
  7. # See also:
  8. # https://en.wikipedia.org/wiki/Cellular_automaton
  9. # https://en.wikipedia.org/wiki/Elementary_cellular_automaton
  10. # https://rosettacode.org/wiki/Elementary_cellular_automaton
  11. # YouTube lectures:
  12. # https://www.youtube.com/watch?v=S3tYzCPuVsA
  13. # https://www.youtube.com/watch?v=pGGIE5uhPRQ
  14. use 5.020;
  15. use strict;
  16. use warnings;
  17. use Imager;
  18. use ntheory qw(:all);
  19. use experimental qw(signatures);
  20. use Algorithm::Combinatorics qw(variations_with_repetition);
  21. sub automaton ($n, $k, $iter, $rule, $cells = [1]) {
  22. my %colors = (
  23. 0 => 'black',
  24. 1 => 'white',
  25. 2 => 'red',
  26. 3 => 'blue',
  27. 4 => 'green',
  28. 5 => 'yellow',
  29. );
  30. say "Generating $n x $k with rule $rule.";
  31. my $size = $iter;
  32. my $img = Imager->new(xsize => $size, ysize => $size >> 1);
  33. my @states = variations_with_repetition([0 .. $n - 1], 2 * $k + 1);
  34. my @digits = reverse todigits($rule, $n);
  35. my @lookup;
  36. foreach my $i (0 .. $#states) {
  37. $lookup[fromdigits($states[$i], $n)] = $digits[$i] // 0;
  38. }
  39. my @padding = (0) x (($iter - scalar(@$cells)) >> 1);
  40. my @cells = (@padding, @$cells, @padding);
  41. my @neighbors_range = (-$k .. $k);
  42. my $len = scalar(@cells);
  43. for my $i (0 .. ($iter >> 1) - 1) {
  44. foreach my $j (0 .. $#cells) {
  45. if ($cells[$j]) {
  46. $img->setpixel(
  47. y => $i,
  48. x => $j,
  49. color => $colors{$cells[$j]},
  50. );
  51. }
  52. }
  53. @cells = @lookup[
  54. map {
  55. my $i = $_;
  56. fromdigits([map { $cells[($i + $_) % $len] } @neighbors_range], $n)
  57. } 0 .. $#cells
  58. ];
  59. }
  60. return $img;
  61. }
  62. automaton(2, 1, 1000, "30")->write(file => "rule_30.png");
  63. automaton(3, 1, 1000, "3760220742240")->write(file => "sierpinski_3x1.png");
  64. automaton(3, 1, 1000, "2646595889467")->write(file => "random_3x1-1.png");
  65. automaton(3, 1, 1000, "4018294395539")->write(file => "random_3x1-2.png");
  66. automaton(3, 1, 1000, "5432098941", [2])->write(file => "random_2x2-3.png");
  67. automaton(2, 2, 1000, "413000741")->write(file => "random_2x2.png");