Collatz Conjecture + Unit Circle
Published: April 9, 2018 | Last Modified: May 13, 2025
Tags: collatz conjecture 3n+1
Categories: Java Processing
Inspired by this cool page, I decided to make my own Collatz Conjecture visualization. My first try looked a lot like what I saw in the Numberphile video, which was pretty good. But then I thought of trying something new by keeping the original rules and wrapping everything around a unit circle. This created 360 “branches”, each showing a 1-degree turn.
Even though this new approach might not reveal any groundbreaking insights into the Collatz Conjecture, I had a lot of fun with it and got some interesting results. The number 327, in particular, had a really long and cool path in this version.
import java.util.*;
int howMany = 361;
int howManyFrames = 9840; //2:44 @ 60FPS
int size=30;
Stack[] stacks = new Stack[howMany];
Turtle[] turtles = new Turtle[howMany];
void setup() {
size(1080,1080, P3D);
//fullScreen(P3D);
background(0);
textAlign(LEFT, CENTER);
textSize(size);
for (int i = 0; i < howMany; i++) {
stacks[i] = new Stack();
collatz(i, stacks[i]);
}
for (int i = 0; i < howMany; i++) {
turtles[i] = new Turtle(width/4, height/4, stacks[i]);
}
}
public void collatz(int n, Stack s) {
s.add(n);
if (n == 1 || n==0) return;
else if (n % 2 == 0) collatz(n / 2, s);
else collatz(3*n + 1, s);
}
void draw() {
translate(width/2, height/2, -1750);
for (int i = 1; i < howMany; i++) {
float m = map(i, 0, howMany-2, 0, (float)Math.PI*2);
rotateZ(-m);
turtles[i].crawl();
rotateZ(m);
}
/*
if (frameCount<howManyFrames+1) {
saveFrame("frame-####.png");
} else {
exit();
}
*/
}
void keyTyped() {
if (int(key) ==32) {
saveFrame("frame-####.png");
}
}
class Turtle {
PVector v1;
int counter;
Stack values;
Turtle(float _x, float _y, Stack _values) {
this.v1 = new PVector(_x, _y, 0);
this.values = _values;
this.counter = 1;
}
void crawl() {
float rg = map(counter, 0, this.values.size(), 0, 255);
float b = map(frameCount, 0, howManyFrames, 0, 255);
if (counter<this.values.size()) {
int d = (int)this.values.get(this.counter);
//PVector v2 = PVector.fromAngle(degrees(d));
PVector v2 = PVector.fromAngle(radians(d));
this.v1.x += v2.x;
this.v1.y += v2.y;
stroke(0, 31);
fill(255-rg, rg, b);
ellipse(this.v1.x, this.v1.y, size, size);
} else {
//noStroke();
//fill(53, m, 255-m);
//ellipse(this.v1.x, this.v1.y, size, size);
//fill(255);
//text(this.values.get(0)+"", this.v1.x+size/2, this.v1.y);
}
if (frameCount%60==0) {
counter++;
}
}
}