elementary_cellular_automaton_generalized.pl 1.9 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374
  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 ntheory qw(:all);
  18. use experimental qw(signatures);
  19. use Algorithm::Combinatorics qw(variations_with_repetition);
  20. sub automaton ($n, $k, $rule, $callback, $iter = 50, $cells = [1]) {
  21. my @states = variations_with_repetition([0 .. $n - 1], 2 * $k + 1);
  22. my @digits = reverse todigits($rule, $n);
  23. my @lookup;
  24. foreach my $i (0 .. $#states) {
  25. $lookup[fromdigits($states[$i], $n)] = $digits[$i] // 0;
  26. }
  27. my @padding = (0) x (($iter - scalar(@$cells)) >> 1);
  28. my @cells = (@padding, @$cells, @padding);
  29. my @neighbors_range = (-$k .. $k);
  30. my $len = scalar(@cells);
  31. for (1 .. ($iter >> 1)) {
  32. $callback->(@cells);
  33. @cells = @lookup[map {
  34. my $i = $_; fromdigits([map { $cells[($i + $_) % $len] } @neighbors_range], $n)
  35. } 0 .. $#cells];
  36. }
  37. return @cells;
  38. }
  39. my @chars = (' ', '*', '.', '#');
  40. say "\n=> 2x1 Automaton";
  41. automaton(2, 1, 90, sub (@row) {
  42. say join '', map { $chars[$_] } @row;
  43. });
  44. say "\n=> 3x1 Automaton";
  45. automaton(3, 1, "843693805713", sub (@row) {
  46. say join '', map { $chars[$_] } @row;
  47. });
  48. say "\n=> 3x2 Automaton";
  49. automaton(3, 2, "590193390821886729275563552433397050190", sub (@row) {
  50. say join '', map { $chars[$_] } @row;
  51. }, 80);