Langton's ant
You are encouraged to solve this task according to the task description, using any language you may know.
Langton's ant models an ant sitting on a plane of cells, all of which are white initially, facing in one of four directions. Each cell can either be black or white. The ant moves according to the color of the cell it is currently sitting in, with the following rules:
- If the cell is black, it changes to white and the ant turns left;
- If the cell is white, it changes to black and the ant turns right;
- The Ant then moves forward to the next cell, and repeat from step 1.
This rather simple ruleset leads to an initially chaotic movement pattern, and after about 10000 steps, a cycle appears where the ant moves steadily away from the starting location in a diagonal corridor about 10 pixels wide. Conceptually the ant can then travel to infinitely far away.
For this task, start the ant near the center of a 100 by 100 field of cells, which is about big enough to contain the initial chaotic part of the movement. Follow the movement rules for the ant, terminate when it moves out of the region, and show the cell colors it leaves behind.
The problem has received some analysis, for more details, please take a look at the Wikipedia article.
AutoHotkey
To support all AHK flavors, a pseudo-array is used. <lang AHK>SetBatchLines -1 n := 0, x := 50, y := 50, d := 1 ; starting positions and orientation
While x > 0 and x < 100 and y > 0 and y < 100 ; In this loop the ant moves d := d + !!(a%x%_%y%) - !(a%x%_%y%) ,d := d=5 ? 1 : d=0 ? 4 : d ,a%x%_%y% := !a%x%_%y% ,x := x + (d=3) - (d=1) ,y := y + (d=4) - (d=2)
Loop 99 ; in this loop the ant's movements are compiled into a string { y := A_Index Loop 99 x := A_Index ,o .= a%x%_%y% ? "#" : "."
o .= "`r`n" } clipboard := o ; set the string to the clipboard</lang>
- Output
......................................................................#.#.##....................... .....................................................................##.###.#...................... ....................................................................#.#...####..................... ...................................................................##..#.#####..................... ..................................................................#.##.##...#...................... .................................................................##..#...###....................... ................................................................#.##.##...#........................ ...............................................................##..#...###......................... ..............................................................#.##.##...#.......................... .............................................................##..#...###........................... ............................................................#.##.##...#............................ ...........................................................##..#...###............................. ..........................................................#.##.##...#.............................. .........................................................##..#...###............................... ........................................................#.##.##...#................................ .......................................................##..#...###................................. ......................................................#.##.##...#.................................. .....................................................##..#...###................................... ....................................................#.##.##...#.................................... ...................................................##..#...###..................................... ..................................................#.##.##...#...................................... .................................................##..#...###....................................... ................................................#.##.##...#........................................ ...............................................##..#...###......................................... ..............................................#.##.##...#.......................................... .............................................##..#...###........................................... ............................................#.##.##...#............................................ ...........................................##..#...###............................................. ..........................................#.##.##...#.............................................. .........................................##..#...###............................................... ....................................##..#.##.##...#................................................ ...................................##..##..#...###................................................. ................................#...##..##.##...#.................................................. ................................###..#...#...###...####............................................ ................................#...####.##...#...#....#........................................... ...............................#.##.#......#.#...#....###.......................................... ...............................##.#..##.#.....##.#....###.......................................... ..................................##.....#.#.##...#....#........................................... .................................#...#..#####.#......#.#........................................... .............................######.##..........#####...#.......................................... ............................##.#.##...#.#.#.##.#..##..###.......................................... ...........................#.##....###..#...#.#######.#..##........................................ ...........................#...#...##.#..#...##.######..#..#....................................... ............................#...#######.######..#.##.#.#....#...................................... ............................#.##.#.##..##....####.#.##.####.#...................................... ...........................###....##.######.#..#...####....#....................................... ...........................###...##..##..#.###.#.##.#...#.......................................... ...........................#.....#.##.##..#....#######............................................. ...........................#.....#..##.##.##.####..##.##..####..................................... ...........................#....####.#....###.##.###...#.#....#.................................... ...........................#......#.#....#####.#.#.###.......###................................... ...........................#.....##.###.##...#.##.####.###...#.#................................... ...........................#.....#.#.#.####....####..##.##......................................... ...........................#......###.....###..###...##..#....#.................................... ...........................#..##...###......#..####.###.##...##.................................... ...........................#...##.###.##.#..#...#.....####.#.##.................................... ...........................#...###..#..#..#.#..####.##...##.####................................... ............................#.#.....#.#.....#.#.##.#.#..###.##.#................................... ................................##.###..#.#..##.##....#..#.#....................................... ...........................#.#..#....#....#.#####..#....#.##....................................... ...........................###......###..#.##.##....#..#.##.#...................................... ............................#....##..##...###..#..#..#..#...#.#.................................... .............................##.#.#######.###.######.#####.#.###................................... ................................#####.#####..##...#####....#.#.#................................... ...............................###.###..##.#..#......#...##..#..................................... .....................................#.#...#########.#####...####.................................. ...................................###..###.#...#.#.###.....#..#....##............................. .................................##.....##.###...##.###...##.####..#..#............................ .................................###.##..#..#....#...#####.#.##.#....###........................... ..................................#..#...#....#.....##..##...#.#.#####.#........................... ...................................##.#.#..##..#...#.##..####.######............................... ......................................###...#...####..##.###.#......##............................. .......................................#..#..#...##.#...#..#####.#..#.............................. ........................................##.#.....#.....#######.###.##.............................. ...........................................#....##...#......##.##..#.#............................. ............................................#..##..###........####.#..#............................ .............................................##..##............###.##.#............................ ....................................................................##............................. ...................................................................##.............................. ................................................................................................... ................................................................................................... ................................................................................................... ................................................................................................... ................................................................................................... ................................................................................................... ................................................................................................... ................................................................................................... ................................................................................................... ................................................................................................... ................................................................................................... ................................................................................................... ................................................................................................... ................................................................................................... ................................................................................................... ................................................................................................... ................................................................................................... ................................................................................................... ................................................................................................... ...................................................................................................
C
Requires ANSI terminal. <lang c>#include <stdio.h>
- include <stdlib.h>
- include <string.h>
- include <unistd.h>
int w = 0, h = 0; unsigned char *pix;
void refresh(int x, int y) { int i, j, k; printf("\033[H"); for (i = k = 0; i < h; putchar('\n'), i++) for (j = 0; j < w; j++, k++) putchar(pix[k] ? '#' : ' '); }
void walk() { int dx = 0, dy = 1, i, k; int x = w / 2, y = h / 2;
pix = calloc(1, w * h); printf("\033[H\033[J");
while (1) { i = (y * w + x); if (pix[i]) k = dx, dx = -dy, dy = k; else k = dy, dy = -dx, dx = k;
pix[i] = !pix[i]; printf("\033[%d;%dH%c", y + 1, x + 1, pix[i] ? '#' : ' ');
x += dx, y += dy;
k = 0; if (x < 0) { memmove(pix + 1, pix, w * h - 1); for (i = 0; i < w * h; i += w) pix[i] = 0; x++, k = 1; } else if (x >= w) { memmove(pix, pix + 1, w * h - 1); for (i = w-1; i < w * h; i += w) pix[i] = 0; x--, k = 1; }
if (y >= h) { memmove(pix, pix + w, w * (h - 1)); memset(pix + w * (h - 1), 0, w); y--, k = 1; } else if (y < 0) { memmove(pix + w, pix, w * (h - 1)); memset(pix, 0, w); y++, k = 1; } if (k) refresh(x, y); printf("\033[%d;%dH\033[31m@\033[m", y + 1, x + 1);
fflush(stdout); usleep(10000); } }
int main(int c, char **v) { if (c > 1) w = atoi(v[1]); if (c > 2) h = atoi(v[2]); if (w < 40) w = 40; if (h < 25) h = 25;
walk(); return 0; }</lang>
C#
<lang C#>using System;
namespace LangtonAnt {
public struct Point { public int X; public int Y;
public Point(int x, int y) { X = x; Y = y; } }
enum Direction { North, East, West, South }
public class Langton { public readonly bool [,] IsBlack; private Point _origin; private Point _antPosition = new Point(0, 0); public bool OutOfBounds { get; set;}
// I don't see any mention of what direction the ant is supposed to start out in private Direction _antDirection = Direction.East;
private readonly Direction[] _leftTurn = new[] { Direction.West, Direction.North, Direction.South, Direction.East }; private readonly Direction[] _rightTurn = new[] { Direction.East, Direction.South, Direction.North, Direction.West }; private readonly int[] _xInc = new[] {0, 1, -1, 0}; private readonly int[] _yInc = new[] {1, 0, 0, -1};
public Langton(int width, int height, Point origin) { _origin = origin; IsBlack = new bool[width, height]; OutOfBounds = false; }
public Langton(int width, int height) : this(width, height, new Point(width / 2, height / 2)) {}
private void MoveAnt() { _antPosition.X += _xInc[(int)_antDirection]; _antPosition.Y += _yInc[(int)_antDirection]; }
public Point Step() { if (OutOfBounds) { throw new InvalidOperationException("Trying to step after ant is out of bounds"); } Point ptCur = new Point(_antPosition.X + _origin.X, _antPosition.Y + _origin.Y); bool leftTurn = IsBlack[ptCur.X, ptCur.Y]; int iDirection = (int) _antDirection; _antDirection = leftTurn ? _leftTurn[iDirection] : _rightTurn[iDirection]; IsBlack[ptCur.X, ptCur.Y] = !IsBlack[ptCur.X, ptCur.Y]; MoveAnt(); ptCur = new Point(_antPosition.X + _origin.X, _antPosition.Y + _origin.Y); OutOfBounds = ptCur.X < 0 || ptCur.X >= IsBlack.GetUpperBound(0) || ptCur.Y < 0 || ptCur.Y >= IsBlack.GetUpperBound(1); return _antPosition; } } class Program { static void Main() { Langton ant = new Langton(100, 100);
while (!ant.OutOfBounds) ant.Step();
for (int iRow = 0; iRow < 100; iRow++) { for (int iCol = 0; iCol < 100; iCol++) { Console.Write(ant.IsBlack[iCol, iRow] ? "#" : " "); } Console.WriteLine(); }
Console.ReadKey(); } }
} </lang> Output:
## ## # ## ### ## ## # # #### ### ## # # # ## ## # ## # ## ### ####### # # ## # # ##### # # ## # # # ## # ### ## #### # ### ###### #### ## # # ## # # ## # ##### # # ## ## # # # # ### # ## # ##### # # # ## ### # # #### ## ### ## ### ## ## ## # # ### # # # ### ### #### ##### ######### # # # ## # # # ## ### ### # # # ##### ## ##### ##### ### # ##### ###### ### ####### # ## # # # # # # ### ## ## # # ## # # ## ## # ### ### ## # # ##### # # # # # # # # ## ## # # ### ## # ## ### # # ## # # # # # # #### ## ## #### # # # # ### # ## # #### # # # ## ### ## # ## ## ### #### # ### ## # # # ## ### ### ### # ## ## #### #### # # # # # # ### #### ## # ## ### ## # ### ### # # ##### # # # # # # ### ## ### # #### # #### ## ## #### ## ## ## # # ####### # ## ## # # # # ## # ### # ## ## ### # #### # # ###### ## ### # #### ## # #### ## ## # ## # # # # ## # ###### ####### # # # ###### ## # # ## # # ## # ####### # # ### ## # ### ## # ## # # # ## # ## # ##### ## ###### # # # ##### # # # # ## # # ## ### # ## # ## # ## ### # # # # ## # # # # ## #### # #### ### # # ### # ## ## ## # ### # ## ## # ## ## # ## ### # ## # ## ## # ### # ## # ## ## # ### # ## # ## ## # ### # ## # ## ## # ### # ## # ## ## # ### # ## # ## ## # ### # ## # ## ## # ### # ## # ## ## # ### # ## # ## ## # ### # ## # ## ## # ### # ## # ## ## # ### # ## # ## ## # ##### # ## #### ### # # ### ## ## # # # #
D
A basic textual version. <lang D>import std.stdio, std.algorithm, std.traits;
enum Direction { up, right, down, left } enum Turn : bool { left = false, right = true } enum Color : char { white = '.', black = '#' }
void main() {
enum width = 75, height = 52; enum nsteps = 12_000;
auto M = new Color[][](height, width); int x = width / 2; int y = height / 2; auto dir = Direction.up;
for (int i = 0; i < nsteps && x >= 0 && y >= 0 && x < width && y < height; i++) { immutable turn = M[y][x] == Color.black ? Turn.left : Turn.right; M[y][x] = M[y][x] == Color.black ? Color.white : Color.black;
immutable d = (4 + dir + (turn == Turn.right ? 1 : -1)) % 4; dir = [EnumMembers!Direction][d]; final switch(dir) { case Direction.up: y--; break; case Direction.right: x--; break; case Direction.down: y++; break; case Direction.left: x++; break; } }
foreach (row; M) writeln(cast(char[])row);
}</lang> Output:
........................................................................... ........................................................................... ........................................................................... ........................................................................... ..........................##..############..##............................. .........................##..#..........####..#............................ ........................#.##............##...###........................... ........................#....#..#.........#..#.#........................... ......................#.......###.........#.#.##..##....................... ......................###..##.##.....#.....#...#..#.###.................... ..................##..##.#..#.#...##.####.##..###..#.#..................... .................###...###.....#.#.###..##.#..##.###.#..................... ................#.#.#.###...#..####..#.#.#####...#.....#................... ................#...#.###.#.######.##.##..####.#...##.###.................. .................##.###.#####...#.##.##.##.#.#.##.#.###.#.................. ...............##.#....####..#.#...#...###.##.#...#.#...................... ..............##.....#.##.....##..#...##.##.........#..#................... .............#.##..##.###...#.....##..#..###.##.#.#...###.................. .............#...####.##..#....#..###...##.##...##..###..#................. ..............#.....#..###.##.#..##.####.#.#..#.#...#...###................ ............##..#..#.##.###......#..###.#..#....##.#..###..#............... ...........#...##.####..####.#####..##..##.#.##.#.....#...###.............. ..........#...#....#.#.#...##......##.#.#.###.#..#.#.#..###..#............. ..........#......#...####.####.......##...#.##..###.##..#...###............ ...........#....#....#..####..#.###########..##...#..#.#..###..#........... ...........##..#....##..#..#########..##..####.#......##..#...###.......... ..........#.####..##.#..#...###.###.##.##...##.#..##...#.#..###..#......... ..........#...##...###.###....#.#.##.#.##.######.#..#...##..#...###........ ...........#...##....#.##..#.#.....#####.#.#####.....#...#.#..###..#....... ...........#..#..#.##..#..#...#.#..##.#####.##.#.....#....##..#...###...... ...........##...##########...##.#####..#.####...#....#.....#.#..###..#..... ...............##.####.##...#..####...#..#...##...##.#......##..#...###.... .............#.#..#..#..#.#....#...#.##...##..#.#####........#.#..###..#... .............##..##..#..##.#.#.##.##....#.#.#.##..##..........##..#...###.. .............#.####..##.#.#.########.#....#..#.................#.#..###..#. .............#.##..#..#...##.##.......#...#..#..................##..#...### .............####.##...##..##..#......#..#..#....................#.#..##... ............###.#...#....##..##.......#...##......................##..#..## ............####.###.####....####..##.#............................#.#.#.#. ...........#..#.#.##.#..##....####..##..............................##.#### ..........#####.##.###.##....##....##................................#.##.# ..........####..#.##.#................................................####. ..........##.##.##.....................................................##.. ................##......................................................... ........#.####..##.#....................................................... ........###..###.#..#...................................................... .........#..#..#.##.#...................................................... ..........##......##....................................................... .................##........................................................ ........................................................................... ........................................................................... ...........................................................................
Go
<lang go>package main
import (
"fmt" "image" "image/color" "image/draw" "image/png" "os"
)
const (
up = iota rt dn lt
)
func main() {
bounds := image.Rect(0, 0, 100, 100) im := image.NewGray(bounds) gBlack := color.Gray{0} gWhite := color.Gray{255} draw.Draw(im, bounds, image.NewUniform(gWhite), image.ZP, draw.Src) pos := image.Point{50, 50} dir := up for pos.In(bounds) { switch im.At(pos.X, pos.Y).(color.Gray).Y { case gBlack.Y: im.SetGray(pos.X, pos.Y, gWhite) dir-- case gWhite.Y: im.SetGray(pos.X, pos.Y, gBlack) dir++ } if dir&1 == 1 { pos.X += 1 - dir&2 } else { pos.Y -= 1 - dir&2 } } f, err := os.Create("ant.png") if err != nil { fmt.Println(err) return } if err = png.Encode(f, im); err != nil { fmt.Println(err) } if err = f.Close(); err != nil { fmt.Println(err) }
}</lang>
Icon and Unicon
<lang Icon>link graphics,printf
procedure main(A)
e := ( 0 < integer(\A[1])) | 100 # 100 or whole number from command line LangtonsAnt(e)
end
record antrec(x,y,nesw)
procedure LangtonsAnt(e)
size := sprintf("size=%d,%d",e,e) label := sprintf("Langton's Ant %dx%d [%d]",e,e,0) &window := open(label,"g","bg=white",size) | stop("Unable to open window")
ant := antrec(e/2,e/2,?4%4) board := list(e) every !board := list(e,"w") k := 0 repeat { k +:= 1 WAttrib("fg=red") DrawPoint(ant.x,ant.y) cell := board[ant.x,ant.y] if cell == "w" then { # white cell WAttrib("fg=black") ant.nesw := (ant.nesw + 1) % 4 # . turn right } else { # black cell WAttrib( "fg=white") ant.nesw := (ant.nesw + 3) % 4 # . turn left = 3 x right } board[ant.x,ant.y] := map(cell,"wb","bw") # flip colour DrawPoint(ant.x,ant.y) case ant.nesw of { # go 0: ant.y -:= 1 # . north 1: ant.x +:= 1 # . east 2: ant.y +:= 1 # . south 3: ant.x -:= 1 # . west } if 0 < ant.x <= e & 0 < ant.y <= e then next else break } printf("Langton's Ant exited the field after %d rounds.\n",k) label := sprintf("label=Langton's Ant %dx%d [%d]",e,e,k) WAttrib(label) WDone()
end</lang>
printf.icn provides formatting graphics.icn provides graphics support (WDone)
J
<lang j>dirs=: 0 1,1 0,0 _1,:_1 0 langton=:3 :0
loc=. <.-:$cells=. (_2{.y,y)$dir=. 0 while. *./(0<:loc), loc<$cells do. color=. (<loc) { cells cells=. (-.color) (<loc)} cells dir=. 4 | dir + _1 ^ color loc=. loc + dir { dirs end. ' #' {~ cells
)</lang>
langton 100 100 # # ## # # # ### ## #### ### # ##### # ## # ## ## # ### # ## # ## ## # ### # ## # ## ## # ### # ## # ## ## # ### # ## # ## ## # ### # ## # ## ## # ### # ## # ## ## # ### # ## # ## ## # ### # ## # ## ## # ### # ## # ## ## # ### # ## # ## ## # ### # ## # ## ## # ### # ## # ## ## # ### # ## # ## ## # ## ### # ## ## # ## ## ## # #### ### # # ### # # # ## #### # ### # # # # ## # ### # ## # ## # ## # # ## # # ## # # # ##### # # # ##### ## ###### ### ## # ## # # # ## # ## ## # ####### # # ### ## # # # ###### ## # # ## # # # # # ## # ###### ####### # # #### ## # #### ## ## # ## # # #### # # ###### ## ### # # ## # ### # ## ## ### ####### # ## ## # # #### ## ## #### ## ## ## # # # # # ### ## ### # #### # ### ### # # ##### # # # # # ### #### ## # ## ### ## # ## ## #### #### # # # # # # ## ### ### ### # ## ## ### #### # ### ## # ## # #### # # # ## ### ## # #### ## ## #### # # # # ### # # ## ### # # ## # # # # # # # # # ## ## # # ### ## ## # # ##### # # # # # # ## # # ## ## # ### ### # # # # # # ### ## ## # ### # ##### ###### ### ####### # ## # # # ##### ## ##### ##### # ## # # # ## ### ### #### ##### ######### # # ## # # ### # # # ### ### # # #### ## ### ## ### ## ## ### # ## # ##### # # # ## ### # ##### # # ## ## # # # # ###### #### ## # # ## # # ## ## # ### ## #### # ### # # ##### # # ## # # # ## ### ####### # # ## # # ## ## # ## # # # #### ### ## # # ## ### ## ## ## ##
Java
This implementation allows for sizes other than 100x100, marks the starting position with a green box (sometimes hard to see at smaller zoom levels and the box is smaller than the "pixels" so it doesn't cover up the color of the "pixel" it's in), and includes a "zoom factor" (ZOOM
) in case the individual "pixels" are hard to see on your monitor.
<lang java>import java.awt.Color;
import java.awt.Graphics;
import javax.swing.JFrame; import javax.swing.JPanel;
public class Langton extends JFrame{ private JPanel planePanel; private static final int ZOOM = 4;
public Langton(final boolean[][] plane){ planePanel = new JPanel(){ @Override public void paint(Graphics g) { for(int y = 0; y < plane.length;y++){ for(int x = 0; x < plane[0].length;x++){ g.setColor(plane[y][x] ? Color.BLACK : Color.WHITE); g.fillRect(x * ZOOM, y * ZOOM, ZOOM, ZOOM); } } //mark the starting point g.setColor(Color.GREEN); g.fillRect(plane[0].length / 2 * ZOOM, plane.length / 2 * ZOOM, ZOOM/2, ZOOM/2); } }; planePanel.setSize(plane[0].length - 1, plane.length - 1); add(planePanel); setSize(ZOOM * plane[0].length, ZOOM * plane.length + 30); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); setVisible(true); }
public static void main(String[] args){ new Langton(runAnt(100, 100)); }
private static boolean[][] runAnt(int height, int width){ boolean[][] plane = new boolean[height][width]; int antX = width/2, antY = height/2;//start in the middle-ish int xChange = 0, yChange = -1; //start moving up while(antX < width && antY < height && antX >= 0 && antY >= 0){ plane[antY][antX] = !plane[antY][antX]; if(plane[antY][antX]){ //turn left if(xChange == 0){ //if moving up or down xChange = yChange; yChange = 0; }else{ //if moving left or right yChange = -xChange; xChange = 0; } }else{ //turn right if(xChange == 0){ //if moving up or down xChange = -yChange; yChange = 0; }else{ //if moving left or right yChange = xChange; xChange = 0; } } antX += xChange; antY += yChange; } return plane; } }</lang> Output (click for a larger view):
OCaml
<lang ocaml>open Graphics
type dir = North | East | South | West
let turn_left = function
| North -> West | East -> North | South -> East | West -> South
let turn_right = function
| North -> East | East -> South | South -> West | West -> North
let move (x, y) = function
| North -> x, y + 1 | East -> x + 1, y | South -> x, y - 1 | West -> x - 1, y
let () =
open_graph ""; let rec loop (x, y as pos) dir = let color = point_color x y in set_color (if color = white then black else white); plot x y; let dir = (if color = white then turn_right else turn_left) dir in if not(key_pressed()) then loop (move pos dir) dir in loop (size_x()/2, size_y()/2) North</lang>
Run with:
$ ocaml graphics.cma langton.ml
PARI/GP
<lang parigp>langton()={
my(M=matrix(100,100),x=50,y=50,d=0); while(x && y && x<=100 && y<=100, d=(d+if(M[x,y],1,-1))%4; M[x,y]=!M[x,y]; if(d%2,x+=d-2,y+=d-1); ); M
}; show(M)={
my(d=sum(i=1,#M[,1],sum(j=1,#M,M[i,j])),u=vector(d),v=u,t); for(i=1,#M[,1],for(j=1,#M,if(M[i,j],v[t++]=i;u[t]=j))); plothraw(u,v)
}; show(langton())</lang>
PicoLisp
This code pipes a PBM into ImageMagick's "display" to show the result: <lang PicoLisp>(de ant (Width Height X Y)
(let (Field (make (do Height (link (need Width)))) Dir 0) (until (or (le0 X) (le0 Y) (> X Width) (> Y Height)) (let Cell (nth Field X Y) (setq Dir (% (+ (if (car Cell) 1 3) Dir) 4)) (set Cell (not (car Cell))) (case Dir (0 (inc 'X)) (1 (inc 'Y)) (2 (dec 'X)) (3 (dec 'Y)) ) ) ) (prinl "P1") (prinl Width " " Height) (for Row Field (prinl (mapcar '[(X) (if X 1 0)] Row)) ) ) )
(out '(display -) (ant 100 100 50 50)) (bye) </lang>
Processing
Processing implementation, this uses two notable features of Processing, first of all, the animation is calculated with the draw() loop, second the drawing on the screen is also used to represent the actual state.
<lang processing>/*
* we use the following conventions: * directions 0: up, 1: right, 2: down: 3: left * * pixel white: true, black: false * * turn right: true, left: false * */
// number of iteration steps per frame // set this to 1 to see a slow animation of each // step or to 10 or 100 for a faster animation
final int STEP=100;
int x; int y; int direction;
void setup() {
// 100x100 is large enough to show the // corridor after about 10000 cycles size(100, 100, P2D);
background(#ffffff);
x=width/2; y=height/2;
direction=0;
}
int count=0;
void draw() {
for(int i=0;i<STEP;i++) { count++; boolean pix=get(x,y)!=-1; setBool(x,y,pix); turn(pix); move(); if(x<0||y<0||x>=width||y>=height) { println("finished"); noLoop(); break; } } if(count%1000==0) { println("iteration "+count); }
}
void move() {
switch(direction) { case 0: y--; break; case 1: x++; break; case 2: y++; break; case 3: x--; break; }
}
void turn(boolean rightleft) {
direction+=rightleft?1:-1; if(direction==-1) direction=3; if(direction==4) direction=0;
}
void setBool(int x, int y, boolean white) {
set(x,y,white?#ffffff:#000000);
}</lang>
PureBasic
<lang purebasic>#White = $FFFFFF
- Black = 0
- planeHeight = 100
- planeWidth = 100
- canvasID = 0
- windowID = 0
OpenWindow(#windowID, 0, 0, 150, 150, "Langton's ant", #PB_Window_SystemMenu | #PB_Window_ScreenCentered) CanvasGadget(#canvasID, 25, 25, #planeWidth, #planeHeight) StartDrawing(CanvasOutput(#canvasID))
Box(0, 0, #planeWidth, #planeHeight, #White)
StopDrawing()
Define event, quit, ant.POINT, antDirection, antSteps
ant\x = #planeHeight / 2 ant\y = #planeWidth / 2 Repeat
Repeat event = WindowEvent() If event = #PB_Event_CloseWindow quit = 1 event = 0 EndIf Until event = 0
StartDrawing(CanvasOutput(#canvasID)) Select Point(ant\x, ant\y) Case #Black Plot(ant\x, ant\y, #White) antDirection = (antDirection + 1) % 4 ;turn left Case #White Plot(ant\x, ant\y, #Black) antDirection = (antDirection - 1 + 4) % 4 ;turn right EndSelect StopDrawing()
Select antDirection Case 0 ;up ant\y - 1 Case 1 ;left ant\x - 1 Case 2 ;down ant\y + 1 Case 3 ;right ant\x + 1 EndSelect antSteps + 1 If ant\x < 0 Or ant\x >= #planeWidth Or ant\y < 0 Or ant\y >= #planeHeight MessageRequester("Langton's ant status", "Out of bounds after " + Str(antSteps) + " steps.") quit = 1 EndIf Delay(10) ;control animation speed and avoid hogging CPU
Until quit = 1</lang> Sample output:
Out of bounds after 11669 steps.
Python
<lang python>width = 75 height = 52 nsteps = 12000
class Dir: up, right, down, left = range(4) class Turn: left, right = False, True class Color: white, black = '.', '#' M = [[Color.white] * width for _ in xrange(height)]
x = width // 2 y = height // 2 dir = Dir.up
i = 0 while i < nsteps and 0 <= x < width and 0 <= y < height:
turn = Turn.left if M[y][x] == Color.black else Turn.right M[y][x] = Color.white if M[y][x] == Color.black else Color.black
dir = (4 + dir + (1 if turn else -1)) % 4 dir = [Dir.up, Dir.right, Dir.down, Dir.left][dir] if dir == Dir.up: y -= 1 elif dir == Dir.right: x -= 1 elif dir == Dir.down: y += 1 elif dir == Dir.left: x += 1 else: assert False i += 1
print "\n".join("".join(row) for row in M)</lang> The output is the same as the basic D version.
Ruby
<lang ruby>class Ant
Directions = [:north, :east, :south, :west]
def initialize(plane, pos_x, pos_y) @plane = plane @position = Position.new(plane, pos_x, pos_y) @direction = :south end attr_reader :plane, :direction, :position
def run moves = 0 loop do begin if $DEBUG and moves % 100 == 0 system "clear" puts "%5d %s" % [moves, position] puts plane end moves += 1 move rescue OutOfBoundsException break end end moves end
def move plane.at(position).toggle_colour position.advance(direction) if plane.at(position).white? turn(:right) else turn(:left) end end
def turn(left_or_right) idx = Directions.index(direction) case left_or_right when :left then @direction = Directions[(idx - 1) % Directions.length] when :right then @direction = Directions[(idx + 1) % Directions.length] end end
end
class Plane
def initialize(x, y) @x = x @y = y @cells = Array.new(y) {Array.new(x) {Cell.new}} end attr_reader :x, :y
def at(position) @cells[position.y][position.x] end
def to_s @cells.collect {|row| row.collect {|cell| cell.white? ? "." : "#"}.join + "\n" }.join end
end
class Cell
def initialize @colour = :white end attr_reader :colour
def white? colour == :white end
def toggle_colour @colour = (white? ? :black : :white) end
end
class Position
def initialize(plane, x, y) @plane = plane @x = x @y = y check_bounds end attr_accessor :x, :y
def advance(direction) case direction when :north then @y -= 1 when :east then @x += 1 when :south then @y += 1 when :west then @x -= 1 end check_bounds end
def check_bounds unless (0 <= @x and @x < @plane.x) and (0 <= @y and @y < @plane.y) raise OutOfBoundsException, to_s end end
def to_s "(%d, %d)" % [x, y] end
end
class OutOfBoundsException < StandardError; end
- the simulation
ant = Ant.new(Plane.new(100, 100), 50, 50) moves = ant.run puts "out of bounds after #{moves} moves: #{ant.position}" puts ant.plane</lang>
output
out of bounds after 11669 moves: (26, -1) ..........................#.#....................................................................... ........................##.#.#...................................................................... .......................#.###.##..................................................................... ......................####.###.#.................................................................... ......................#####.#..##................................................................... .......................#...##.##.#.................................................................. ........................###...#..##................................................................. .........................#...##.##.#................................................................ ..........................###...#..##............................................................... ...........................#...##.##.#.............................................................. ............................###...#..##............................................................. .............................#...##.##.#............................................................ ..............................###...#..##........................................................... ...............................#...##.##.#.......................................................... ................................###...#..##......................................................... .................................#...##.##.#........................................................ ..................................###...#..##....................................................... ...................................#...##.##.#...................................................... ....................................###...#..##..................................................... .....................................#...##.##.#.................................................... ......................................###...#..##................................................... .......................................#...##.##.#.................................................. ........................................###...#..##................................................. .........................................#...##.##.#................................................ ..........................................###...#..##............................................... ...........................................#...##.##.#.............................................. ............................................###...#..##............................................. .............................................#...##.##.#............................................ ..............................................###...#..##........................................... ...............................................#...##.##.#.......................................... ................................................###...#..##......................................... .................................................#...##.##.#..##.................................... ..................................................###...#..##..##................................... ...................................................#...##.##..##...#................................ .............................................####...###...#...#..###................................ ............................................#....#...#...##.####...#................................ ...........................................###....#...#.#......#.##.#............................... ...........................................###....#.##.....#.##..#.##............................... ............................................#....#...##.#.#.....##.................................. ............................................#.#......#.#####..#...#................................. ...........................................#...#####..........##.######............................. ...........................................###..##..#.##.#.#.#...##.#.##............................ .........................................##..#.#######.#...#..###....##.#........................... ........................................#..#..######.##...#..#.##...#...#........................... .......................................#....#.#.##.#..######.#######...#............................ .......................................#.####.##.#.####....##..##.#.##.#............................ ........................................#....####...#..#.######.##....###........................... ...........................................#...#.##.#.###.#..##..##...###........................... ..............................................#######....#..##.##.#.....#........................... ......................................####..##.##..####.##.##.##..#.....#........................... .....................................#....#.#...###.##.###....#.####....#........................... ....................................###.......###.#.#.#####....#.#......#........................... ....................................#.#...###.####.##.#...##.###.##.....#........................... ..........................................##.##..####....####.#.#.#.....#........................... .....................................#....#..##...###..###.....###......#........................... .....................................##...##.###.####..#......###...##..#........................... .....................................##.#.####.....#...#..#.##.###.##...#........................... ....................................####.##...##.####..#.#..#..#..###...#........................... ....................................#.##.###..#.#.##.#.#.....#.#.....#.#............................ ........................................#.#..#....##.##..#.#..###.##................................ ........................................##.#....#..#####.#....#....#..#.#........................... .......................................#.##.#..#....##.##.#..###......###........................... .....................................#.#...#..#..#..#..###...##..##....#............................ ....................................###.#.#####.######.###.#######.#.##............................. ....................................#.#.#....#####...##..#####.#####................................ ......................................#..##...#......#..#.##..###.###............................... ...................................####...#####.#########...#.#..................................... ..............................##....#..#.....###.#.#...#.###..###................................... .............................#..#..####.##...###.##...###.##.....##................................. ............................###....#.##.#.#####...#....#..#..##.###................................. ............................#.#####.#.#...##..##.....#....#...#..#.................................. ................................######.####..##.#...#..##..#.#.##................................... ..............................##......#.###.##..####...#...###...................................... ...............................#..#.#####..#...#.##...#..#..#....................................... ...............................##.###.#######.....#.....#.##........................................ ..............................#.#..##.##......#...##....#........................................... .............................#..#.####........###..##..#............................................ .............................#.##.###............##..##............................................. ..............................##.................................................................... ...............................##................................................................... .................................................................................................... .................................................................................................... .................................................................................................... .................................................................................................... .................................................................................................... .................................................................................................... .................................................................................................... .................................................................................................... .................................................................................................... .................................................................................................... .................................................................................................... .................................................................................................... .................................................................................................... .................................................................................................... .................................................................................................... .................................................................................................... .................................................................................................... .................................................................................................... .................................................................................................... ....................................................................................................
TI-83 BASIC
The initial Pxl-On(0,0) calibrates the screen, otherwise it doesn't work, and the variable N counts the generation number. <lang TI-83b>PROGRAM:LANT
- ClrDraw
- 0→N
- Pxl-On(0,0)
- 47→X
- 31→Y
- 90→Θ
- Repeat getKey
- If pxl-Test(Y,X)
- Then
- Θ+90→Θ
- Else
- Θ-90→Θ
- End
- Pxl-Change(Y,X)
- X+cos(Θ°)→X
- Y+sin(Θ°)→Y
- N+1→N
- End
</lang>