"Langton's Car" Not working

The idea is this: Set all pixels positions on screen to a random value of either 0,1,2, or 3. Set a particle “car” in the middle with an arbitrary velocity vector. On each frame, the car will move to a new position.
if the pixel is 0, increase speed slightly, but never more than maxSpeed.
If the pixel is 1, angle slightly to the right.
If the pixel is 2, decrease speed slightly, but never less than 1.
If the pixel is 3, angle slightly to the left.
Reset the pixel it’s on to a new random value so no infinite loops occur, and then update position.
I already have some code:

// Settings
final float SPEED_STEP = 0.1;
final float SPEED_MAX = 2;
final float SPEED_MIN = 1;
final float ANGLE_STEP = PI/2; //pi/2 radians, 90 degrees
final color COLOR_CAR = color(255, 0, 0); //Red car - my favorite!
final color COLOR_BACKGROUND = color(0, 0, 0); //Black background

// Car variables
float car_px;
float car_py;
float car_vx;
float car_vy;
float car_angle;
float car_speed;

// Automaton variables
int cell;

// Display settings
int[][] grid;
int col;
int pix;
int car;

// Setup
void setup() {
  size(500, 500);
  grid = new int[width][height];
  
  smooth(); //I think this is what I want
  
  // Randomize screen contents
  for(int x = 0; x < width; x++) {
    for(int y = 0; y < height; y++) {
      grid[x][y] = round(random(0, 3));
    }
  }
  
  // Place car
  car_px = width / 2;
  car_py = height / 2;
  car_angle = quant(random(0, TWO_PI), ANGLE_STEP);
  car_speed = random(SPEED_MIN, SPEED_MAX);
  
}

// Loop
void draw() {
  background(COLOR_BACKGROUND);
  
  // Car physics
  car_speed = constrain(car_speed, SPEED_MIN, SPEED_MAX);
  car_angle %= TWO_PI;
  car_vx = car_speed * cos(car_angle);
  car_vy = car_speed * sin(car_angle);
  car_px = constrain(car_px + car_vx, 0, width);
  car_py = constrain(car_py + car_vy, 0, height);
  
  // Cellular automaton
  cell = grid[(int) car_px][(int) car_py];
  switch(cell) {
    
    case 0:
    car_speed += SPEED_STEP;
    break;
    
    case 1:
    car_angle += ANGLE_STEP;
    break;
    
    case 2:
    car_speed -= SPEED_STEP;
    break;
    
    case 3:
    car_angle -= ANGLE_STEP;
    break;
    
  }
  
  // Graphics
  loadPixels();
  for(int x = 0; x < width; x++) {
    for(int y = 0; y < height; y++) {
      pix = x + (y * width);
      col = (int) map(grid[x][y], 0, 3, 0, 255);
      pixels[pix] = col;
      //stroke(col);
      //point(x, y);
    }
  }
  car = (int) (car_px + (car_py * width));
  pixels[car] = COLOR_CAR;
  //stroke(COLOR_CAR);
  //point(car_px, car_py);
  updatePixels();
  
}

// Quantization function
float quant(float x, float step) {
  return round(x / step) * step;
}

It compiles without any issues, but it doesn’t quite work the way it should:

Thought I should mention this: the function quant(float, foat) should exist natively in Processing. Maybe I’ll create a mathematical utilities function including sig(float), hyperbolic functions, “Lerp noise”, and quant(float, float)

check on https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#signum-float-
Math.signum(f)
test:

println(Math.signum(-22.5));
  1. Does java.Math include sinh(float) cosh(float) tanh(float) quant(float), or anything similar?
  2. Let’s not get off topic. The idea is I’m using pixels[] for graphics because point(float, float) is too slow. The background is supposed to be random shades of gray, and the car (red dots) isn’t supposed to act like that. I’ve made 50 physics engines in Processing already, and I’ll be damned if now is the time where I screw up.

Hi,

You might want to use this:

pixels[pix] = color(col, col, col);

instead of this:

pixels[pix] = col;

I think this is the problem:

Try:

car = ((int) car_px + ((int) car_py * width));

Otherwise fractional Y will move your car in X as well.

1 Like

Came to the same conclusion while trying how to get it to work, only problem is that since maxSpeed is 2 it sometimes jumps a pixel which leaves the trace with holes in it… Could be fixed by setting max_Speed to 1 and min to 0.5, just takes double the time then.

Also use : pixels[x + (y *(int) height)] = color(map(grid[x][y], 0, 3, 0, 255));
to draw the grey pixels. Saves declaring all the variables, unless you want to use them later on, then just declare the color as color, not just int. Because setting pixels to a positive integer will not do much, since pixels[] requires values below 0, so from -1 to -16million~.

Also, you should reset the gridpoint you were just on right after getting it for cell, so that the car doesn’t just stop if it hits a loop or just turns in a point (doesn’t move, so will stay on the same grid spot that tells it to rotate…).

Also, if you want the path of the car to be shown, you should only draw the greyscale once in setup and you can ignore if gridspots change, since then they would already be red, so no neet to redo the grid just for a spot noone sees. But if you don’t need the path, just draw it like the code i post below.
Or if you want the path separetly, you could just draw it onto a PGraphics.

Edited Code

// Settings
final float SPEED_STEP = 0.01;
final float SPEED_MAX = 1f;
final float SPEED_MIN = 0.5f;
final float ANGLE_STEP = PI/2; //pi/2 radians, 90 degrees
final color COLOR_CAR = color(255, 0, 0); //Red car - my favorite!
final color COLOR_BACKGROUND = color(0, 0, 0); //Black background

// Car variables
float car_px;
float car_py;
float car_vx;
float car_vy;
float car_angle;
float car_speed;

// Automaton variables
int cell;

// Display settings
int[][] grid;
int col;
int pix;
int car;

// Setup
void setup() {
size(500, 500);
grid = new int[width][height];

smooth(); //I think this is what I want

// Randomize screen contents
for(int x = 0; x < width; x++) {
for(int y = 0; y < height; y++) {
grid[x][y] = round(random(0, 3));
}
}

// Place car
car_px = width / 2;
car_py = height / 2;
car_angle = quant(random(0, TWO_PI), ANGLE_STEP);
car_speed = random(SPEED_MIN, SPEED_MAX);

}

// Loop
void draw() {
background(COLOR_BACKGROUND);

// Car physics
car_speed = constrain(car_speed, SPEED_MIN, SPEED_MAX);
car_angle %= TWO_PI;
car_vx = car_speed * cos(car_angle);
car_vy = car_speed * sin(car_angle);
car_px = constrain(car_px + car_vx, 0, width);
car_py = constrain(car_py + car_vy, 0, height);

// Cellular automaton
cell = grid[(int) car_px][(int) car_py];
grid[(int) car_px][(int)car_py] = round(random(0, 3));
switch(cell) {

case 0:
car_speed += SPEED_STEP;
break;

case 1:
car_angle += ANGLE_STEP;
break;

case 2:
car_speed -= SPEED_STEP;
break;

case 3:
car_angle -= ANGLE_STEP;
break;

}

// Graphics
loadPixels();
for(int x = 0; x < width; x++) {
for(int y = 0; y < height; y++) {
pixels[x + (y *(int) height)] = color(map(grid[x][y], 0, 3, 0, 255));
//stroke(col);
//point(x, y);
}
}
pixels[(int)car_px +( (int)car_py * height)] = COLOR_CAR;
updatePixels();

}

// Quantization function
float quant(float x, float step) {
return round(x / step) * step;
}

This should do exactly what you asked for… i think :sweat_smile:

Thanks! I’ll let you know what I get with these changes.

The edited code, after the modifications I said I was going to do, and a few more:

// Settings
final float SPEED_STEP = 1;
final float SPEED_MAX = 5;
final float SPEED_MIN = 1;
final float ANGLE_STEP = PI/2; //pi/2 radians, 90 degrees
final color COLOR_CAR = color(255, 0, 0); //Red car - my favorite!
final color COLOR_BACKGROUND = color(0, 0, 0); //Black background

// Car variables
float car_px;
float car_py;
float car_vx;
float car_vy;
float car_angle;
float car_speed;

// Automaton variables
int cell;

// Display settings
int[][] grid;
int col;
int pix;
int car;

PImage bg;

// Setup
void setup() {
  size(500, 500);
  grid = new int[width][height];
  
  //smooth(); //I think this is what I want (it wasn't)
  bg = new PImage(width, height);
  
  // Randomize screen contents
  for(int x = 0; x < width; x++) {
    for(int y = 0; y < height; y++) {
      grid[x][y] = round(random(0, 3));
    }
  }
  
  // Place car
  car_px = width / 2;
  car_py = height / 2;
  car_angle = quant(random(0, TWO_PI), ANGLE_STEP);
  car_speed = random(SPEED_MIN, SPEED_MAX);
  
  // Initial data
  //loadPixels();
  bg.loadPixels();
  for(int x = 0; x < width; x++) {
    for(int y = 0; y < height; y++) {
      pix = (int) x + ((int) y * bg.width);
      col = (int) color(map(grid[x][y], 0, 3, 0, 255));
      bg.pixels[pix] = col;
      //stroke(col);
      //point(x, y);
    }
  }
  bg.updatePixels();
  //updatePixels();
  
}

// Loop
void draw() {
  //background(COLOR_BACKGROUND);
  background(bg);
  
  // Car physics
  car_speed = constrain(car_speed, SPEED_MIN, SPEED_MAX);
  car_angle %= TWO_PI;
  car_vx = car_speed * cos(car_angle);
  car_vy = car_speed * sin(car_angle);
  car_px = constrain(car_px + car_vx, 0, width-1);
  car_py = constrain(car_py + car_vy, 0, height-1);
  
  // Cellular automaton
  cell = grid[(int) car_px][(int) car_py];
  grid[(int) car_px][(int) car_py] = round(random(0, 3));
  switch(cell) {
    
    case 0:
    car_speed += SPEED_STEP;
    break;
    
    case 1:
    car_angle += ANGLE_STEP;
    break;
    
    case 2:
    car_speed -= SPEED_STEP;
    break;
    
    case 3:
    car_angle -= ANGLE_STEP;
    break;
    
  }
  
  // Graphics
  bg.loadPixels();
  for(int x = 0; x < bg.width; x++) {
    for(int y = 0; y < bg.height; y++) {
      pix = (int) x + ((int) y * bg.width);
      //col = (int) color(map(grid[x][y], 0, 3, 0, 255));
      //bg.pixels[pix] = col;
      col = bg.pixels[pix];
      grid[x][y] = col;
      //stroke(col);
      //point(x, y);
    }
  }
  //car = ((int) car_px) + (int) (car_py * width);
  //pixels[car] = COLOR_CAR;
  stroke(COLOR_CAR);
  strokeWeight(3);
  point(car_px, car_py);
  //updatePixels();
  
}

// Quantization function
float quant(float x, float step) {
  return round(x / step) * step;
}

As well as the changes you asked for, I changed it so that it renders a PImage of the grid in background(PImage), instead of the grid itself, for performance. However, even with the angle step at 90 degrees; PI/2 radians, it can’t steer…