let lastCrazyIvanTime = 0;
let saveGenerations = true;
createCanvas(random(400, 800), random(400, 800));
randomSeed(floor(random(1000)));
noiseSeed(floor(random(1000)));
bgColor = color(random(50, 255), random(50, 255), random(50, 255));
let cellWidth = random(1, 5);
let cellHeight = random(1, 5);
automaton = new CellularAutomaton(caWidth, caHeight, cellWidth, cellHeight);
let resolution = random(5, 200);
flowField = new FlowField(resolution);
flowField.generateNoiseField();
for (let i = 0; i < width / cellWidth; i++) {
particles.push(new Particle(i * cellWidth, 0));
crazyIvanInterval = floor(random(200, 600));
console.log("Setup generativo completato.");
let currentTime = frameCount;
if (currentTime - lastCrazyIvanTime > crazyIvanInterval) {
lastCrazyIvanTime = currentTime;
for (let i = 0; i < particles.length; i++) {
particles[i].follow(flowField);
particles[i].update(automaton.cells[i]);
if (saveGenerations && frameCount % 500 === 0) {
saveCanvas("generation_" + frameCount, "jpg");
console.log("Crazy Ivan attivato!");
bgColor = color(random(50, 255), random(50, 255), random(50, 255),50);
flowField.modifyAngles();
for (let i = 0; i < particles.length; i++) {
particles[i].randomize();
crazyIvanInterval = floor(random(200, 600));
class CellularAutomaton {
constructor(wid, hei, altezz, largh) {
this.cellHeight = altezz;
this.cells = Array(floor(wid / largh)).fill(0);
this.cells[floor(this.cells.length / 2)] = 1;
this.ruleset = this.generateRandomRules();
let nextGen = Array(this.cells.length).fill(0);
for (let i = 1; i < this.cells.length - 1; i++) {
let left = this.cells[i - 1];
let right = this.cells[i + 1];
nextGen[i] = this.rules(left, me, right);
if (a === 1 && b === 1 && c === 1) return this.ruleset[0];
if (a === 1 && b === 1 && c === 0) return this.ruleset[1];
if (a === 1 && b === 0 && c === 1) return this.ruleset[2];
if (a === 1 && b === 0 && c === 0) return this.ruleset[3];
if (a === 0 && b === 1 && c === 1) return this.ruleset[4];
if (a === 0 && b === 1 && c === 0) return this.ruleset[5];
if (a === 0 && b === 0 && c === 1) return this.ruleset[6];
if (a === 0 && b === 0 && c === 0) return this.ruleset[7];
.map(() => (random() < 0.5 ? 0 : 1));
this.ruleset = this.generateRandomRules();
console.log("Automa casualizzato:", this.ruleset);
this.pos = createVector(x, y);
this.prevPos = createVector(x, y);
this.vel = createVector();
this.acc = createVector();
this.maxSpeed = random(0.5, 5);
this.size = random(0.5,1);
this.color = color(random(255), random(255), random(255));
let x = floor(this.pos.x / flow.resolution);
let y = floor(this.pos.y / flow.resolution);
let index = x + y * flow.cols;
let force = flow.field[index];
this.vel.limit(this.maxSpeed);
if (this.pos.y > height) {
if (this.pos.x > width) {
this.color = state === 1 ? this.color: color(0);
ellipse(this.pos.x, this.pos.y, this.size, this.size);
this.maxSpeed = random(1, 5);
this.size = random(0.5, 1);
this.color = color(random(255), random(255), random(255));
constructor(resolution) {
this.resolution = resolution;
this.cols = floor(width / this.resolution);
this.rows = floor(height / this.resolution);
for (let y = 0; y < this.rows; y++) {
for (let x = 0; x < this.cols; x++) {
let angle = noise(x * 0.001, y * 0.01) * TWO_PI;
let v = p5.Vector.fromAngle(angle);
for (let i = 0; i < this.field.length; i++) {
let newAngle = random(TWO_PI);
this.field[i] = p5.Vector.fromAngle(newAngle).mult(random(0.5, 2));
console.log("Flow field angoli modificati!");
this.resolution = random(50, 200);
this.cols = floor(width / this.resolution);
this.rows = floor(height / this.resolution);
this.generateNoiseField();
console.log("Flow field casualizzato: risoluzione =", this.resolution);