I would like to code Langton’s Ant in Codea [ http://en.wikipedia.org/wiki/Langton’s_ant ], and it would seem like the easiest way to do this would be to use retained backing and some getPixelColor function. It seems like Codea lacks the latter, is there any chance it could be added?
I’d say you could do it just by drawing to an image - the image class has both get() and set() methods.
Ah, thank you. That should work
I couldn’t help but have a go at this myself. I’ve got a direction wrong somewhere though, as my resulting image is rotated 90° from the image on Wikipedia!
function setup()
-- set up parameters and watch
Steps=0
watch("Steps")
parameter("Delay",0,1.0,0.1)
parameter("StepsPerDraw",1,1000,1)
-- create our image to work on
noSmooth()
img = image(WIDTH/4,HEIGHT/4)
setContext(img)
fill(255, 255, 255, 255)
noStroke()
rect(0,0,img.width,img.height)
setContext()
-- inital ant position and direction
antpos = vec2(img.width/2, img.height/2)
dir = vec2(0,1)
end
-- move the ant on
function step()
if not onscreen() then
return
end
-- find the current colour
local r,g,b,a = img:get(antpos.x, antpos.y)
if r == 255 then
-- if white left
img:set(antpos.x, antpos.y, color(0,0,0,255))
if dir.x == 1 then
dir = vec2(0,-1)
elseif dir.x == -1 then
dir = vec2(0,1)
elseif dir.y == 1 then
dir = vec2(1,0)
elseif dir.y == -1 then
dir = vec2(-1,0)
end
else
-- if black right
img:set(antpos.x, antpos.y, color(255,255,255,255))
if dir.x == 1 then
dir = vec2(0,1)
elseif dir.x == -1 then
dir = vec2(0,-1)
elseif dir.y == 1 then
dir = vec2(-1,0)
elseif dir.y == -1 then
dir = vec2(1,0)
end
end
antpos = antpos + dir
Steps = Steps + 1
end
counter = 0
function draw()
counter = counter + DeltaTime
if counter > Delay then
for i = 1,StepsPerDraw do
step()
end
counter = 0
end
spriteMode(CORNER)
sprite(img, 0, 0, WIDTH, HEIGHT)
end
function onscreen()
if antpos.x > 0 and antpos.x < img.width and
antpos.y > 0 and antpos.y < img.height then
return true
else
return false
end
end
I believe this may help you:
http://twolivesleft.com/Codea/Reference/#detail/index/vec2.rotate
http://twolivesleft.com/Codea/Reference/#detail/index/vec2.rotate90
Im pursuing an OO model, so I can change the ant’s rules, add multiple ants, etc.
EDIT: This is what the code looks like so far. Ants will ignore any colors they do not recognize.
Main: http://pastebin.com/jiAwXbTy
Ant Class: http://pastebin.com/1YL6J1tx
Something interesting happens if you play with default settings, in portrait mode, on an iPad 1!
Couldn’t resist. Here’s a mesh implementation.
function setup()
--RANDOM = true
landscape = mesh()
grid = {}
grain = 10
w = math.floor(WIDTH/grain)
h = math.floor(HEIGHT/grain)
local i
for x=1,w do
grid[x] = {}
for y=1,h do
i = landscape:addRect(
(x-.5)*grain,
(y-.5)*grain,
grain,
grain
)
grid[x][y] = i
if RANDOM and math.random(0,1) == 0 then
landscape:setRectColor(i,color(255,255,255))
else
landscape:setRectColor(i,color(0,0,0))
end
if i%500 == 499 then
landscape:addRect(0,0,0,0)
end
end
end
ant = mesh()
ant.texture = "Tyrian Remastered:Space Bug Right"
local i =ant:addRect(0,0,grain,grain)
ant:setRectTex(i,0,0,1,1)
x = math.floor(w/2)
y = math.floor(h/2)
d = 0
rate = .1
parameter("rate",0,1,rate)
UpdateTime = 0
iterations = 0
watch("iterations")
watch("math.floor(1/DeltaTime)")
end
function draw()
background(40, 40, 50)
landscape:draw()
translate(grain*(x-.5),grain*(y-.5))
rotate(d*90)
ant:draw()
if ElapsedTime - UpdateTime > rate then
UpdateTime = ElapsedTime
iterations = iterations + 1
local c = landscape:color(6*grid[x][y])
if c.r == 255 then
d = (d-1)%4
landscape:setRectColor(grid[x][y],color(0,0,0))
else
d = (d+1)%4
landscape:setRectColor(grid[x][y],color(255,255,255))
end
if d%2 == 0 then
x = x - d + 1
else
y = y - d + 2
end
if x == w+1 then
x = 1
end
if x == 0 then
x = w
end
if y == h+1 then
y = 1
end
if y == 0 then
y = h
end
end
end
Put it on a torus so I didn’t have to worry about the edges (try a Klein bottle next!).
@Simeon I got odd behaviour on rendering the 500th rectangles (and 1000th etc). Try commenting out the lines if i %500 ...
and set RANDOM to true (so that the behaviour is obvious).
Very nice!
A couple of suggestions:
- use noSmooth() before the sprite command
- draw the board on the neighbouring screens as well (so you can pan and zoom on the corners of the screen as well)
for i=-1,1 do
for j=-1,1 do
sprite(board, i*WIDTH,j*HEIGHT)
end
end
- use my Zoom library (so you can pinch to zoom) http://twolivesleft.com/Codea/Talk/discussion/550/zoom-library