/* One-dimensional cellular automata in Picat. From Rosetta Code: http://rosettacode.org/wiki/One-dimensional_cellular_automata """ Assume an array of cells with an initial distribution of live and dead cells, and imaginary cells off the end of the array having fixed values. Cells in the next generation of the array are calculated based on the value of the cell and its left and right nearest neighbours in the current generation. If, in the following table, a live cell is represented by 1 and a dead cell by 0 then to generate the value of the cell at a particular index in the array of cellular values you use the following table: 000 -> 0 # 001 -> 0 # 010 -> 0 # Dies without enough neighbours 011 -> 1 # Needs one neighbour to survive 100 -> 0 # 101 -> 1 # Two neighbours giving birth 110 -> 1 # Needs one neighbour to survive 111 -> 0 # Starved to death. """ Compare with my K solution http://rosettacode.org/wiki/One-dimensional_cellular_automata#K This Picat model was created by Hakan Kjellerstrand, hakank@gmail.com See also my Picat page: http://www.hakank.org/picat/ */ % import util. % import cp. main => go. % The test instance go => % _ # # # _ # # _ # _ # _ # _ # _ _ # _ _ S = [0,1,1,1,0,1,1,0,1,0,1,0,1,0,1,0,0,1,0,0], All = ca(S), foreach(A in All) println(A.convert()) end, writeln(len=All.length), nl. % some random instances go2 => foreach(N in [5,10,20,50,75,100]) ca_rand(N), nl end. go3 => N = 40, Ns = [0 : _ in 1..N], S = Ns ++ [1] ++ Ns, All = ca_30(S), foreach(A in All) println(A.convert()) end, writeln(len=All.length), nl. go4 => foreach(N in [5,10,20,50,75,100]) ca30_rand(N), nl end. % % create the 1-D CA % ca(S) = All => Len = S.length, All := [S], Seen = new_map(), % detect fixpoint and cycle while (not Seen.has_key(S)) Seen.put(S,1), T = [S[1]] ++ [rule(slice(S,I-1,I+1)) : I in 2..Len-1] ++ [S[Len]], All := All ++ [T], S := T end. ca_rand(N) => S = [random2() mod 2 : _I in 1..N], All = ca(S), foreach(A in All) println(A.convert()) end, writeln(len=All.length), nl. % % Rule 30: % http://en.wikipedia.org/wiki/Rule_30 % ca_30(S) = All => Len = S.length, All := [S], Seen = new_map(), % detect fixpoint and cycle while (not Seen.has_key(S)) Seen.put(S,1), T = [S[1]] ++ [rule30(slice(S,I-1,I+1)) : I in 2..Len-1] ++ [S[Len]], All := All ++ [T], S := T end. ca30_rand(N) => S = [random2() mod 2 : _I in 1..N], All = ca_30(S), foreach(A in All) println(A.convert()) end, writeln(len=All.length), nl. % for presentation convert(L) = Res => B = "_#", Res = [B[L[I]+1] : I in 1..L.length]. % the rules index(+) rule([0,0,0]) = 0. % rule([0,0,1]) = 0. % rule([0,1,0]) = 0. % Dies without enough neighbours rule([0,1,1]) = 1. % Needs one neighbour to survive rule([1,0,0]) = 0. % rule([1,0,1]) = 1. % Two neighbours giving birth rule([1,1,0]) = 1. % Needs one neighbour to survive rule([1,1,1]) = 0. % Starved to death. % the rules index(+) rule30([0,0,0]) = 0. rule30([0,0,1]) = 1. rule30([0,1,0]) = 1. rule30([0,1,1]) = 1. rule30([1,0,0]) = 1. rule30([1,0,1]) = 0. rule30([1,1,0]) = 0. rule30([1,1,1]) = 0.