
๐ p5.js
let particles = [];
const PARTICLE_COUNT = 2000;
const YELLOW_PERCENTAGE = 0.01;
const CANVAS_SIZE = 1000;
const BG_COLOR = 10;
let startTime;
let endTime = null;
let isInfectionComplete = false;
function setup() {
createCanvas(CANVAS_SIZE, CANVAS_SIZE);
const yellowCount = Math.floor(PARTICLE_COUNT * YELLOW_PERCENTAGE);
for (let i = 0; i < PARTICLE_COUNT; i++) {
particles.push({
x: random(CANVAS_SIZE),
y: random(CANVAS_SIZE),
vx: random(-1, 1),
vy: random(-1, 1),
r: floor(random(3, 5)),
isYellow: i < yellowCount,
});
}
startTime = millis();
}
function draw() {
background(BG_COLOR);
noStroke();
let yellowCount = 0;
let greenCount = 0;
for (let i = 0; i < particles.length; i++) {
let p = particles[i];
if (p.isYellow) {
yellowCount++;
} else {
greenCount++;
}
if (!isInfectionComplete) {
p.x += p.vx;
p.y += p.vy;
if (p.x - p.r < 0 || p.x + p.r > CANVAS_SIZE) {
p.vx *= -1;
p.x = constrain(p.x, p.r, CANVAS_SIZE - p.r);
}
if (p.y - p.r < 0 || p.y + p.r > CANVAS_SIZE) {
p.vy *= -1;
p.y = constrain(p.y, p.r, CANVAS_SIZE - p.r);
}
for (let j = i + 1; j < particles.length; j++) {
let other = particles[j];
let dx = other.x - p.x;
let dy = other.y - p.y;
let distSq = dx * dx + dy * dy;
let minDist = p.r + other.r;
if (distSq < minDist * minDist) {
if (p.isYellow && !other.isYellow) {
other.isYellow = true;
} else if (!p.isYellow && other.isYellow) {
p.isYellow = true;
}
let dist = sqrt(distSq);
let nx = dx / dist;
let ny = dy / dist;
let dvx = p.vx - other.vx;
let dvy = p.vy - other.vy;
let dotProduct = dvx * nx + dvy * ny;
p.vx -= dotProduct * nx;
p.vy -= dotProduct * ny;
other.vx += dotProduct * nx;
other.vy += dotProduct * ny;
let overlap = minDist - dist;
let separateX = nx * overlap * 0.5;
let separateY = ny * overlap * 0.5;
p.x -= separateX;
p.y -= separateY;
other.x += separateX;
other.y += separateY;
}
}
}
fill(p.isYellow ? color(255, 255, 0) : color(0, 100, 0));
circle(p.x, p.y, p.r * 2);
}
if (!isInfectionComplete && greenCount === 0) {
isInfectionComplete = true;
endTime = millis();
}
fill(255);
textSize(20);
textAlign(LEFT);
text(`Yellow Team : ${yellowCount}`, 20, CANVAS_SIZE - 40);
text(`Green Team : ${greenCount}`, 20, CANVAS_SIZE - 15);
textAlign(RIGHT);
textSize(50);
let elapsedTime;
if (isInfectionComplete) {
elapsedTime = (endTime - startTime) / 1000;
} else {
elapsedTime = (millis() - startTime) / 1000;
}
text(`Time : ${elapsedTime.toFixed(1)}s`, CANVAS_SIZE - 20, CANVAS_SIZE - 15);
}