computational craft

totalistic code 976

rosettaposter

Rosetta

This is an example of the same algorithm written in three different coding environments (Rhinoscript, Grasshopper .NET & Processing). It’s useful to examine the dirent structures & syntax.

two-dimensional cellular automaton starting from a random condition; totalistic code 976. Music from lovebrain’s new album “color out of sound”.

Behavior of a two dimensional cellular automaton starting from a random initial condition. At each step, each cell looks at the total number of black cells in the 9-cell neighborhood consisting of the cell itself and the 8 cells adjacent to it (including diagonals). If the total is less than 4, then the cell becomes white on the next step, while if the total is greater than 6, it becomes black. If the total is exactly 5, then the cell becomes white, and if the total is exactly 4, then it becomes black. (The rule has totalistic code 976.) The video below shows that on a large scale, the rule leads to regions of black and white whose boundaries behave in a seemingly smooth and continuous way.

Stephen Wolfram, New Kind of Science p.336

Code in RhinoScript

Option Explicit
'Script written by Ezio Blasetti
'Script copyrighted by algorithmicdesign.net
'Script version Friday, September 25, 2009 4:44:59 PM

Call Main()
Sub Main()

    Dim intLength : intLength = 50
    Dim intWidth  : intWidth  = 50
    Dim intGen    : intGen    = 15
   
    ReDim arrSize(intLength,intWidth)
    Dim arrValues : arrValues = randomizeArray01(arrSize)
    Dim arrMeshes : arrMeshes = render(arrValues)
    Dim i,j
    For i=0 To intGen
        arrValues = applyTotalistic976(arrValues)
        'arrValues = applyGOL(arrValues)
        Call update(arrMeshes, arrValues)
    Next
    'Call DeleteObjects2dArray(arrMeshes)
End Sub

Function applyTotalistic976(arrValues)
    applyTotalistic976 = Null
    Dim i,j
    Dim arrNewValues : arrNewValues = arrValues
    For j=0 To Ubound(arrValues,2)
        For i=0 To Ubound(arrValues,1)
            Dim dblSum : dblSum = sumNeighbors(arrValues, i, j, True)
            If dblSum < 4 Then
                arrNewValues(i,j) = 0
            ElseIf dblSum > 5 Then
                arrNewValues(i,j) = 1
            ElseIf dblSum = 5 Then
                arrNewValues(i,j) = 0
            ElseIf dblSum = 4 Then
                arrNewValues(i,j) = 1
            Else
                arrNewValues(i,j) = arrValues(i,j)
            End If
           
        Next
    Next
    applyTotalistic976 = arrnewValues
End Function

Function applyGOL(arrValues)
    applyGOL = Null
    Dim i,j
    Dim arrNewValues : arrNewValues = arrValues
    For j=0 To Ubound(arrValues,2)
        For i=0 To Ubound(arrValues,1)
            Dim dblSum : dblSum = sumNeighbors(arrValues, i, j, False)
            If arrValues(i,j) = 1 Then
                If dblSum < 2 Then
                    arrNewValues(i,j) = 0
                ElseIf dblSum > 3 Then
                    arrNewValues(i,j) = 0
                Else
                    arrNewValues(i,j) = 1
                End If
            Else
                If dblSum = 3 Then
                    arrNewValues(i,j) = 1
                Else
                    arrNewValues(i,j) = 0
                End If
            End If
        Next
    Next
    applyGOL = arrNewValues
End Function

Function sumNeighbors(arrValues, i, j, blnSelf)
    sumNeighbors = Null

    Dim iplus1  : iplus1  = i+1
    Dim iminus1 : iminus1 = i-1
    If i = 0 Then iminus1 = Ubound(arrValues,1)
    If i = Ubound(arrValues,1) Then iplus1 = 0
    Dim jplus1  : jplus1  = j+1
    Dim jminus1 : jminus1 = j-1
    If j = 0 Then jminus1 = Ubound(arrValues,2)
    If j = Ubound(arrValues,2) Then jplus1 = 0 
    Dim dblSum  : dblSum  = 0
    dblSum = dblSum + arrValues(iminus1,jminus1)
    dblSum = dblSum + arrValues(i      ,jminus1)
    dblSum = dblSum + arrValues(iplus1 ,jminus1)
    dblSum = dblSum + arrValues(iminus1,j      )
    If blnSelf Then dblSum = dblSum + arrValues(i,j)
    dblSum = dblSum + arrValues(iplus1 ,j      )
    dblSum = dblSum + arrValues(iminus1,jplus1 )
    dblSum = dblSum + arrValues(i      ,jplus1 )
    dblSum = dblSum + arrValues(iplus1 ,jplus1 )
    sumNeighbors = dblSum
End Function

Function render(arrValues)
    render = Null
    Call Rhino.EnableRedraw(vbFalse)
    Dim arrMeshes : arrMeshes = arrValues
    Dim i,j
    For j=0 To Ubound(arrValues,2)
        For i=0 To Ubound(arrValues,1)
            Dim arrPoints : arrPoints = array(array((i-0.5),(Ubound(arrValues,2)-j-0.5),0),_
                array((i+0.5),(Ubound(arrValues,2)-j-0.5),0),_
                array((i+0.5),(Ubound(arrValues,2)-j+0.5),0),_
                array((i-0.5),(Ubound(arrValues,2)-j+0.5),0))
            arrMeshes(i,j) = addMeshQuad(arrPoints)
            Call colorMeshQuad(arrMeshes(i,j), arrValues(i,j))
        Next
    Next   
    Call Rhino.EnableRedraw(vbTrue)
    render = arrMeshes
End Function


Function update(arrMeshes, arrValues)
    update = Null
    Call Rhino.EnableRedraw(vbFalse)
    Dim i,j
    For j=0 To Ubound(arrValues,2)
        For i=0 To Ubound(arrValues,1)
            Call colorMeshQuad(arrMeshes(i,j), arrValues(i,j))
        Next
    Next   
    Call Rhino.EnableRedraw(vbTrue)
    update = arrMeshes
End Function

Sub DeleteObjects2dArray(arrObjects)
    Call Rhino.EnableRedraw(vbFalse)
    Dim i,j
    For j=0 To Ubound(arrObjects,2)
        For i=0 To Ubound(arrObjects,1)
            Call Rhino.DeleteObject(arrObjects(i,j))
        Next
    Next   
    Call Rhino.EnableRedraw(vbTrue)
End Sub

Function randomizeArray(arr)
    randomizeArray = Null
    Dim i,j
    For j=0 To Ubound(arr,2)
        For i=0 To Ubound(arr,1)
            arr(i,j) = rnd 
        Next
    Next
    randomizeArray = arr
End Function

Function randomizeArray01(arr)
    randomizeArray01 = Null
    Dim i,j
    For j=0 To Ubound(arr,2)
        For i=0 To Ubound(arr,1)
            If rnd-0.5<0 Then
                arr(i,j) = 0
            Else
                arr(i,j) = 1
            End If 
        Next
    Next
    randomizeArray01 = arr
End Function

Function addMeshQuad(arrPoints)
    Dim arrFaceVertices(0)
    arrFaceVertices(0) = Array(0,1,2,3)
    addMeshQuad = Rhino.AddMesh (arrPoints, arrFaceVertices)
End Function

Sub colorMeshQuad(strMesh, dblValue)
    Dim lngColor : lngColor = RGB(255-dblValue*255,255-dblValue*255,255-dblValue*255)
    Call Rhino.ObjectColor(strMesh, lngColor)
    Dim intMaterialIndex : intMaterialIndex = Rhino.AddMaterialToObject (strMesh)
    Call Rhino.MaterialColor(intMaterialIndex, lngColor)
End Sub

Definition in Grasshopper

976Grasshopper

Inside the main .net node:

  Sub RunScript(ByVal InitStates As List(Of Integer), ByVal xNum As Integer, ByVal yNum As Integer, ByVal Gen As Double)
   
    'Generate 2D grid of points
   Dim Grid(,) As On3dPoint
    ReDim Grid(xNum, yNum)
    GenerateGrid(xNum, yNum, Grid)
   
    'Generate 2D grid of state
   Dim SGrid(xNum, yNum) As Integer
    GenerateStateGrid(InitStates, xNum, yNum, SGrid)
   
    'Get state at the defined generation
   Dim i,j As Integer
    For i = 0 To Gen
      NewGeneration(SGrid, xNum, yNum)
    Next
   
    'Make a list of points
   Dim LPoints As New List(Of On3dPoint )
    For i = 0 To xNum - 1
      For j = 0 To yNum - 1
        LPoints.Add(Grid(i, j))
      Next
    Next
    'Make a list of states
   Dim LStates As New List(Of Integer )
    For i = 0 To xNum - 1
      For j = 0 To yNum - 1
        LStates.Add(SGrid(i, j))
      Next
    Next
    'print(InitStates.Count())
   outPoints = LPoints
    outStates = LStates
  End Sub

#Region "Additional methods and Type declarations"
  Sub GenerateGrid(ByVal xNum As Integer, ByVal yNum As Integer, ByRef Grid As On3dPoint(,))
    Dim i,j As Integer
    Dim x,y As Integer  
    x = 0
    y = 0
   
    'Create rows
   For i = 0 To xNum - 1
      y = 0
      For j = 0 To yNum - 1
        Dim pt As New On3dPoint(i, j, 0)
        Grid(x, y) = pt
        y = y + 1
      Next
      x = x + 1
    Next
   
  End Sub
 
  Sub GenerateStateGrid(ByVal State As List(Of Integer), ByVal xNum As Integer, ByVal yNum As Integer, ByRef SGrid As Integer(,))
    Dim i,j As Integer
    Dim x,y As Integer  
    x = 0
    y = 0
   
    'Create rows
   For i = 0 To State.Count() - 1 Step yNum
      y = 0
      For j = i To i + yNum - 1
        Dim st As Integer
        st = State(j)
        SGrid(x, y) = st
        y = y + 1
      Next
      x = x + 1
    Next
   
  End Sub
 
  Sub NewGeneration(ByRef States As Integer(,), ByVal xNum As Integer, ByVal yNum As Integer)
    Dim i,j As Integer
    Dim intLCount As Integer
    Dim SNewGrid(xNum, yNum) As Integer
    For i = 0 To xNum - 1
      For j = 0 To yNum - 1
        SNewGrid(i, j) = States(i, j)
      Next
    Next
    Dim prev_i, next_i, prev_j, next_j As Integer
   
    For i = 0 To (xNum - 1)
      'First index
     If i = 0 Then
        'Take last index
       prev_i = xNum - 1
      Else
        prev_i = i - 1
      End If
       
      'Last index
     If i = xNum - 1 Then
        'Take first index
       next_i = 0
      Else
        next_i = i + 1

      End If
       
      For j = 0 To (yNum - 1)
        If j = 0 Then
          prev_j = yNum - 1
        Else
          prev_j = j - 1   
        End If
           
        'Check next col
       If j = yNum - 1 Then
          next_j = 0
        Else
          next_j = j + 1
        End If
           
        'Zero the living cells count
        intLCount = 0  
           
        'Count number of live neighbors (8 of them)
        intLCount = intLCount + States(next_i, j)  
        intLCount = intLCount + States(prev_i, j)  
        intLCount = intLCount + States(i, next_j)  
        intLCount = intLCount + States(i, prev_j)  
        intLCount = intLCount + States(i, j)   
        intLCount = intLCount + States(next_i, next_j) 
        intLCount = intLCount + States(next_i, prev_j) 
        intLCount = intLCount + States(prev_i, next_j) 
        intLCount = intLCount + States(prev_i, prev_j) 

        If intLCount < 4 Then
          SNewGrid(i, j) = 0
        ElseIf intLCount > 5 Then
          SNewGrid(i, j) = 1
        ElseIf intLCount = 5 Then
          SNewGrid(i, j) = 0
        ElseIf intLCount = 4 Then
          SNewGrid(i, j) = 1
        Else
          SNewGrid(i, j) = States(i, j)
        End If
      Next
    Next
    States = SnewGrid
  End Sub

Code in Processing

//Script written by Ezio Blasetti for algorithmicdesign.net

import processing.opengl.*;

int intHeightCells   = 100;
int intWidthCells    = 190;
int height           = 500;
int width            = 950;
float [][] arrValues = new float [intWidthCells][intHeightCells];

void setup ()
{
  size(width,height, OPENGL);
  randomizeArray(arrValues);
}

void draw(){
  render(arrValues);
  arrValues = applyTotalisitc976(arrValues);
//arrValues = applyGOL(arrValues);
}


float [][] randomizeArray(float arr[][]){
  for (int j=0; j<intHeightCells; j++) {
    for (int i=0; i<intWidthCells; i++) {
      arr[i][j] = round(random(0,1));
      //print (arr[i][j]);
    }
  }
  return arr;
}


void render(float arrValues[][]){
  for (int j=0; j<intHeightCells; j++) {
    for (int i=0; i<intWidthCells; i++) {
      fill(255-arrValues[i][j]*255);
      noStroke();
      rect(i*(width/intWidthCells), j*(height/intHeightCells), width/intWidthCells, height/intHeightCells);
    }
  }
}

float [][] applyTotalisitc976(float arrValues[][]){
  float [][] arrNewValues = new float [intWidthCells][intHeightCells];
  for (int j=0; j<intHeightCells; j++) {
    for (int i=0; i<intWidthCells; i++) {
      float dblSum = sumNeighbors(arrValues,i,j, true);
      if (dblSum<4){
        arrNewValues[i][j] = 0;
      }
      else if(dblSum>5){
        arrNewValues[i][j] = 1;
      }
      else if(dblSum==5){
        arrNewValues[i][j] = 0;
      }
      else if(dblSum==4){
        arrNewValues[i][j] = 1;
      }
      else{
        arrNewValues[i][j] = arrValues[i][j];
      }
    }
  }
  return arrNewValues;
}

float [][] applyGOL(float arrValues[][]){
  float [][] arrNewValues = new float [intWidthCells][intHeightCells];
  for (int j=0; j<intHeightCells; j++) {
    for (int i=0; i<intWidthCells; i++) {
      float dblSum = sumNeighbors(arrValues,i,j, false);
      if (arrValues[i][j] == 1){
        if (dblSum<2){
          arrNewValues[i][j] = 0;
        }
        else if (dblSum>3){
          arrNewValues[i][j] = 0;
        }
        else {
          arrNewValues[i][j] = 1;
        }
      }
      else {
        if (dblSum==3) {
          arrNewValues[i][j] = 1;
        }
        else {
          arrNewValues[i][j] = 0;
        }
      }
    }
  }
  return arrNewValues;
}

float sumNeighbors(float arrValues[][], int i, int j, boolean blnSelf){
  int iplus1  = i + 1;
  int iminus1 = i - 1;
  if (i == 0) {
    iminus1 = intWidthCells-1;
  }
  if (i == intWidthCells-1) {
    iplus1 = 0;
  }
  int jplus1  = j + 1 ;
  int jminus1 = j - 1 ;
  if (j == 0) {
    jminus1 = intHeightCells-1;
  }
  if (j == intHeightCells-1) {
    jplus1 = 0;
  }
  float dblSum = 0;
  dblSum = dblSum + arrValues[iminus1][jminus1];
  dblSum = dblSum + arrValues[i      ][jminus1];
  dblSum = dblSum + arrValues[iplus1 ][jminus1];
  dblSum = dblSum + arrValues[iminus1][j      ];
  if (blnSelf) {
      dblSum = dblSum + arrValues[i  ][j      ];
  }
  dblSum = dblSum + arrValues[iplus1 ][j      ];
  dblSum = dblSum + arrValues[iminus1][jplus1 ];
  dblSum = dblSum + arrValues[i      ][jplus1 ];
  dblSum = dblSum + arrValues[iplus1 ][jplus1 ];
  return dblSum;
}