//Cellular Automata (1-Dimensional) Realization by Dave Matthews // For reference, see http://mathworld.wolfram.com/ElementaryCellularAutomaton.html // This array builds from bottom up, rather than top down, as in // the Mathworld examples. //Several Necessary Macros //This first macro converts a number (R_N) from 0 to 255 to entries in an array. //(The array should be initialized to all //zeros, and the lowest place value starts at entry 0, to highest at entry 7.) #macro Fill_Rule (R_array, R_N) #local Place = 0; #local Quot = R_N; #while (Place < 8 & Quot > 0) #declare R_array[Place]=mod(Quot,2); #local Quot = (Quot - R_array[Place])/2; #local Place = Place + 1; #end #end //This next macro uses a state array (O_A) of length _Len, and a rule array (R_A) to //create the next state array (N_A). The convention is used that the end cells are deadened by permanent zero cells. #macro Next_Gen (O_A,N_A,_Len,R_A) #local Place = 2*O_A[0] + O_A[1]; #declare N_A[0]=R_A[Place]; #local J = 1; #while (J < _Len-1) #local Place = 4*O_A[J-1] + 2*O_A[J] + O_A[J+1]; #declare N_A[J] = R_A[Place]; #local J = J + 1; #end #local Place = 4*O_A[_Len-2]+2*O_A[_Len-1]; #declare N_A[_Len-1] = R_A[Place]; #end //Here we create a colored array of boxes, //with the color defined by // //in each generation. I know, it calculates one more row than it uses, the "interested reader" can fix that. #macro Box_Realization (_Init_Array,_L,N_of_G,Rule_Number) union { #declare Obj = box {0, 1}; #declare Rule_Array = array[8]; #local Dum = 0; #while (Dum < 8) #declare Rule_Array[Dum] = 0; #local Dum = Dum + 1; #end Fill_Rule(Rule_Array, Rule_Number) #declare _Old_Array = _Init_Array; #declare _New_Array = _Init_Array; #local Which_Gen = 0; #while (Which_Gen < N_of_G) object { Obj pigment { color rgb <0, _New_Array[0], _New_Array[1]>*2 } translate <0, 0, Which_Gen>} #local K = 1; #while (K < _L - 1) object { Obj pigment { color rgb <_New_Array[K-1], _New_Array[K], _New_Array[K+1]>*2 } translate } #local K = K + 1; #end object { Obj pigment { color rgb <_New_Array[_L-2], _New_Array[_L-1], 0>*2 } translate <_L-1,0,Which_Gen> } #declare _Old_Array = _New_Array; Next_Gen(_Old_Array,_New_Array,_L,Rule_Array) #local Which_Gen = Which_Gen + 1; #end } #end // Here we make the initializations // This is where the fun parts come in! // Just enter a rule number -- must be an integer, 0 - 255, I didn't trap for errors! #declare Rule = 73; // This is the width of your array #declare Number_Of_Cells = 101; #declare Initial_State = array[Number_Of_Cells]; // Here's where the initial state array is filled. You can do this manually, or according to a // pattern of your choice. A common approach is to just put one live cell in the middle of the array. #local Fill = 0; #while (Fill < Number_Of_Cells) #if (Fill=23 | Fill=27 | Fill=62 | Fill=63) #declare Initial_State[Fill] = 1; #else #declare Initial_State[Fill] = 0; #end #local Fill = Fill+1; #end // Here's the "height" of the array. Note that since the edge conditions are "always dead after the edge" // they can cause "interference" as the number of generations increases. #declare Number_Of_Generations = 100; // Here's the picture! object { Box_Realization(Initial_State,Number_Of_Cells,Number_Of_Generations,Rule) } // background { color rgb 0.7 } light_source { 1000 rgb 1 } camera { angle 70 right x*image_width/image_height up y location look_at }