All the 1-D cellular automata


Here's every possible rule for a one-dimensional (neighborhood-1) cellular automaton. All on a single infinite surface you can pan and zoom around on your touchscreen device. In 100 lines.

T = 100  -- number of time steps to simulate for each rule
Data = {}
function initial_row()  -- same for all rules
  local result = {}
  for _=1,T do table.insert(result, false) end
  table.insert(result, true)
  for _=1,T do table.insert(result, false) end
  return result
end
function step_rule(rule, arr)
  local result = {}
  table.insert(result, false)  -- border is fixed
  for i=2,#arr-1 do
    local r = bits_to_int(arr, i)
    table.insert(result, lookup_rule(rule, r))
  end
  table.insert(result, false)
  return result
end
-- take an array of 3 bits, and turn it into a number
function bits_to_int(arr, idx)
  local r = arr[idx-1] and 1 or 0
  r = r*2 + (arr[idx] and 1 or 0)
  r = r*2 + (arr[idx+1] and 1 or 0)
  return r
end
function lookup_rule(rule, r)
  for _=1,r do rule = floor(rule/2) end
  return bit.band(rule, 1) == 1
end
for rule=0,255 do
  Data[rule+1] = {}
  local arr = initial_row()
  table.insert(Data[rule+1], arr)
  for i=1,T do
    arr = step_rule(rule, arr)
    table.insert(Data[rule+1], arr)
  end
end
function car.draw()
  local side = 8
  for y=0,15 do
    for x=0,15 do
      draw_rule(y*16+x, x*T*2*(side+1), y*T*(side+1), side)
    end end
  color(0.8, 0.8, 0.8)
  for _,touch in ipairs(touches()) do
    if curr[touch] then
      circle('fill', curr[touch].x, curr[touch].y, 10)
    end end
end
function draw_rule(rule, left,top, square_side)
  if not Data[rule+1] then return end
  if vx(left) > Safe_width then return end
  if vx(left+(2*T+1)*square_side) < 0 then return end
  if vy(top) > Safe_height then return end
  if vy(top+T*square_side) < 0 then return end
  color(0.75, 0.75, 0.75)
  for y=1,#Data[rule+1] do
    for x,cell in ipairs(Data[rule+1][y]) do
      if cell then
        rect('fill', vx(left+(x-1)*square_side), vy(top+(y-1)*square_side), scale(square_side-1), scale(square_side-1))
      end end end
  color(0,0,1, 0.3)
  g.print(rule, vx(left),vy(top), --[[rotate]] 0, --[[scale]] 1.5)
end
-- pan/zoom surface
v ={x=0, y=0, w=Safe_width, h=Safe_height, zoom=1.0}
f,s = nil  -- ids of first and second touches
start, curr = {}, {}  -- coords of touches
initzoom = nil
initpos = nil -- for panning
function car.touchpressed(id, x,y, ...)
  if f == nil then
    f = id
    initpos = {x=v.x, y=v.y}
  else
    s = id
    initzoom = v.zoom
  end
  start[id] = {x=x, y=y}
  curr[id] = {x=x, y=y}
end
function car.touchreleased(id, x,y, ...)
  f,s = nil
  start, curr = {}, {}
  initzoom = nil
  initpos = nil
end
function car.touchmoved(id, x,y, ...)
  if start[id] then
    curr[id] = {x=x, y=y}
    if s then
      local oldzoom = v.zoom
      v.zoom = dist(curr[f], curr[s])/dist(start[f], start[s])*initzoom
      adjust_viewport(oldzoom, v.zoom)
    elseif f then
      v.x = initpos.x + iscale(start[f].x - x)
      v.y = initpos.y + iscale(start[f].y - y)
    end end end
function adjust_viewport(oldzoom, zoom)
  -- ensure centroid of fingers remains in view
  local c = centroid(curr[f], curr[s])
  v.x = v.x + c.x/oldzoom - c.x/zoom
  v.y = v.y + c.y/oldzoom - c.y/zoom
end
function centroid(a, b)
  return{x=(a.x+b.x)/2, y=(a.y+b.y)/2}
end
function vx(sx) return scale(sx-v.x) end
function vy(sy) return scale(sy-v.y) end
function scale(d) return d*v.zoom end
function iscale(d) return d/v.zoom end
function dist(p1, p2)
  return ((p2.x-p1.x)^2 + (p2.y-p1.y)^2) ^ 0.5
end

If you try pasting this program into Lua Carousel, remember to first run the abbreviations on one of the example screens. Or if you've deleted that screen, here are the abbreviations I used in this post:

g = love.graphics
rect, circle = g.rectangle, g.circle
color = g.setColor
min, max, floor = math.min, math.max, math.floor
touches = love.touch.getTouches
touch = love.touch.getPosition

Files

carousel-bh.love 117 kB
64 days ago
carousel-bh-safe.love 117 kB
64 days ago

Get Lua Carousel

Leave a comment

Log in with itch.io to leave a comment.