import numpy as np
import random
import math
import pyglet
from pyglet.gl import *

N = 256
M = 256
RULE = 110
SCALE=4

state = np.zeros(shape=(N,), dtype='uint8')
nstep = 0

rule = np.zeros(shape=(2,2,2), dtype='uint8')
for n in range(8):
    i = 1 if n & 4 else 0
    j = 1 if n & 2 else 0
    k = 1 if n & 1 else 0
    s = 1 if RULE & (1<<n) else 0
    rule[k,j,i] = s

def update_state():
    global nstep
    c = state
    ell = np.roll(state, -1, axis=0)
    r = np.roll(state, 1, axis=0)
    state[:] = rule[ell,c,r][:]
    nstep += 1
    
def init_state():
    state[:] = np.random.choice([0,1], size=N, p=(0.95,0.05))[:]

config = pyglet.gl.Config(double_buffer=True)
window = pyglet.window.Window(N*SCALE,M*SCALE,config=config,resizable=False)
window.set_caption('1D Cellular Automaton')

batch = pyglet.graphics.Batch()

tiles = np.empty(shape=(N,M),dtype='object')

def init_tiling():
    for i in range(N):
        for j in range(M):
            shape = pyglet.shapes.Rectangle(x=i*SCALE, y=j*SCALE, width=SCALE, height=SCALE, color=(0, 0, 0), batch=batch)
            tiles[i,j] = shape
    for i in range(N):
        if state[i]==0:
            tiles[i,0].color = (10,10,70)
        elif state[i]==1:
            tiles[i,0].color = (200,100,90)
        else: # owtherwise something went wrong...
            tiles[i,0].color = (255,255,0)

def update_tiling():
    for i in range(N):
        tiles[i,nstep%M].y = -nstep*SCALE
        if state[i]==0:
            tiles[i,nstep%M].color = (10,10,70)
        else:
            tiles[i,nstep%M].color = (200,100,90)

@window.event
def on_draw():
    window.clear()
    batch.draw()
    str = 'T={0:4d}'.format(nstep)
    label_time = pyglet.text.Label(str,font_name='Helvetica', color=(255,255,255,255), font_size=12, x=10, y=12 - nstep*SCALE)
    label_time.draw()

def update(deltat):
    update_state()
    update_tiling()
    window.view = window.view.translate((0, SCALE, 0))

init_state()        
init_tiling()
pyglet.clock.schedule_interval(update, 1/100.0)
pyglet.app.run()
