/* Conway's Game of Life in Picat. From Rosetta Code http://rosettacode.org/wiki/Conway%27s_Game_of_Life """ The Game of Life is a cellular automaton devised by the British mathematician John Horton Conway in 1970. It is the best-known example of a cellular automaton. Conway's game of life is described [http://en.wikipedia.org/wiki/Conway%27s_Game_of_Life] A cell C is represented by a 1 when alive or 0 when dead, in an m-by-m square array of cells. We calculate N - the sum of live cells in C's eight-location neighbourhood, then cell C is alive or dead in the next generation based on the following table: C N new C 1 0,1 -> 0 # Lonely 1 4,5,6,7,8 -> 0 # Overcrowded 1 2,3 -> 1 # Lives 0 3 -> 1 # It takes three to give birth! 0 0,1,2,4,5,6,7,8 -> 0 # Barren Assume cells beyond the boundary are always dead. The "game" is actually a zero-player game, meaning that its evolution is determined by its initial state, needing no input from human players. One interacts with the Game of Life by creating an initial configuration and observing how it evolves. Although you should test your implementation on more complex examples such as the glider in a larger universe, show the action of the blinker (three adjoining cells in a row all alive), over three generations, in a 3 by 3 grid. """ 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. go => Rows = 30, Cols = 30, Names = [blinker, p4, p5, glider, figure_eight], foreach(Name in Names ) pattern(Name, Pattern,I,J), writeln(Name), life(fill(Rows,Cols,Pattern,I,J)), nl end, nl. % random go2 => Rows = 20, Cols = 20, Grid = new_array(Rows,Cols), foreach(I in 1..Rows, J in 1..Cols) Grid[I,J] := random2() mod 2 end, life(Grid), nl. % larger example (to fit a Linux terminal) go3 => Rows = 52, Cols = 115, Grid = new_array(Rows,Cols), foreach(I in 1..Rows, J in 1..Cols) Grid[I,J] := random2() mod 2 end, life(Grid). fill(Rows, Cols, Obj) = fill(Rows, Cols, Obj,1,1). fill(Rows, Cols, Obj,OffsetI,OffsetJ) = Grid => Grid = new_array(Rows,Cols), bind_vars(Grid,0), foreach(I in 1..Obj.length, J in 1..Obj[1].length) Grid[I+OffsetI-1,J+OffsetJ-1] := Obj[I,J] end. % Note: we stop whenever a fixpoint/cycle is detected life(S) => Rows = S.length, Cols = S[1].length, writeln([rows=Rows, cols=Cols]), print_grid(S), Seen = new_map(), % detect fixpoint and cycle Count = 0, while (not Seen.has_key(S)) Seen.put(S,1), T = new_array(Rows,Cols), foreach(I in 1..Rows, J in 1..Cols) Sum = sum([S[I+A,J+B] : A in -1..1,B in -1..1, I+A > 0, J+B > 0, I+A =< Rows, J+B =< Cols]) - S[I,J], C = rules(S[I,J], Sum), T[I,J] := C end, print_grid(T), S := T, Count := Count + 1 end, printf("%d generations\n", Count). print_grid(G) => foreach(I in 1..G.length) foreach(J in 1..G[1].length) if G[I,J] == 1 then print("#") else print(".") end end, nl end, nl. rules(This,Sum) = 1, (This == 1, member(Sum,[2,3]); This == 0, Sum == 3) => true. rules(_This, _Sum) = 0 => true. % % The patterns % pattern(Name, Pattern, OffsetI, OffsetJ) % where Offset* is the recommended offsets in a % grid. % pattern(blinker, Pattern,I,J) ?=> Pattern = [[0,0,0], [1,1,1], [0,0,0]], I=5,J=5. pattern(p4, Pattern,I,J) ?=> Pattern = [[0,0,0,0], [1,1,1,1], [1,1,1,1], [0,0,0,0]], I=10,J=10. pattern(p5, Pattern,I,J) ?=> Pattern = [[0,0,0,0,0], [1,1,1,1,1], [1,1,1,1,1], [1,1,1,1,1], [0,0,0,0,0]], I=10,J=10. pattern(glider, Pattern,I,J) ?=> Pattern = [[0,0,1], [1,0,1], [0,1,1]], I=5,J=5. pattern(figure_eight, Pattern,I,J) => Pattern = [[1,1,1,0,0,0], [1,1,1,0,0,0], [1,1,1,0,0,0], [0,0,0,1,1,1], [0,0,0,1,1,1], [0,0,0,1,1,1]], I=10,J=10.