# rule30image.py
# Copyright (C) 2002  Frank Buß (fb@frank-buss.de)
# Thanks to Carl Banks, Sean Richards and others for the optimisation tips
# Uses Numeric and the Python Imaging Library

from Numeric import *

# This class calculates one line with of Rule 30:
# If the cell and its righthand neighbour were white on
# the previous step, then take the new colour to be whatever
# the previous colour of its lefthand neighbour was, otherwise take 
# the new colour to be the opposite of that 
class Rule30:
  def __init__(self, length):
    # create arrays
    self.current = zeros(length, Int)
    self.workspace = zeros(length - 2, Int)
    
    # create slices
    self.left = self.current[:-2]
    self.right = self.current[2:]
  
  def step(self):
    # calculate the new values using bitwise operators
    self.workspace[:] = self.left ^ (self.current[1:-1] | self.right)

    # update current
    self.current[1:-1] = self.workspace


from Tkinter import *
from ImageTk import PhotoImage
import Image

# create the Rule 30 object and init the middle to 1
length = 500
rule30 = Rule30(length)
rule30.current[length / 2] = 1

# create the image array
lines = length / 2
imageArray = zeros((lines, length), Int)
for step in range(lines):
  imageArray[step, :] = rule30.current
  rule30.step()

# init tk
root = Tk()
root.title('Rule 30')

# convert the image array into a PIL image and display it
img = Image.fromstring('L', (length, lines), ((1 - imageArray) * 255).astype(Int8).tostring())
photo = PhotoImage(image = img)
label = Label(image = photo)
label.pack()
root.mainloop()

