entropy / sketch.js
shikharyashmaurya's picture
Upload sketch.js
49549db verified
let boundaries = [];
let balls = [];
let drawingBoundary = false;
let boundaryDrawn = false;
let w, h;
let entropyGraph = [];
let startTime;
function setup() {
w = windowWidth;
h = windowHeight;
canvas = createCanvas(w, h);
startTime = millis();
}
function draw() {
background(0);
// Draw the boundaries
stroke(255);
strokeWeight(2);
if (boundaries.length >= 3) {
beginShape();
for (let v of boundaries) {
vertex(v.x, v.y);
}
endShape(CLOSE);
}
// Update and draw the balls
for (let ball of balls) {
ball.move();
ball.checkBoundaryCollision();
ball.display();
}
// Calculate and display entropy
if (boundaryDrawn && balls.length > 0) {
let entropy = calculateEntropy();
entropyGraph.push(entropy);
displayEntropyGraph();
}
// Display instructions
displayInstructions();
}
function mouseDragged() {
if (!drawingBoundary && !boundaryDrawn) {
boundaries = [];
drawingBoundary = true;
}
if (drawingBoundary) {
boundaries.push({ x: mouseX, y: mouseY });
}
}
function mouseReleased() {
drawingBoundary = false;
boundaryDrawn = true;
}
function mouseClicked() {
if (boundaryDrawn) {
balls.push(new Ball());
}
}
class Ball {
constructor() {
this.x = mouseX;
this.y = mouseY;
this.vx = random(-2, 2);
this.vy = random(-2, 2);
this.radius = 2;
this.color = color(random(100, 255), random(100, 255), random(100, 255));
}
move() {
this.x += this.vx;
this.y += this.vy;
}
checkBoundaryCollision() {
let isOutside = !this.isPointInPolygon(boundaries, this.x, this.y);
if (isOutside) {
let closestEdge = this.findClosestEdge(boundaries);
let edgeNormal = p5.Vector.fromAngle(closestEdge.angle + HALF_PI);
let reflectedVelocity = this.reflectVector(createVector(this.vx, this.vy), edgeNormal);
this.vx = reflectedVelocity.x;
this.vy = reflectedVelocity.y;
// Move the ball back inside the boundary
this.x = constrain(this.x, closestEdge.x1, closestEdge.x2);
this.y = constrain(this.y, closestEdge.y1, closestEdge.y2);
}
}
// findClosestEdge(polygon) {
// // ... (keep the existing implementation)
// }
// distanceToLine(edge) {
// // ... (keep the existing implementation)
// }
// reflectVector(vector, normal) {
// // ... (keep the existing implementation)
// }
// isPointInPolygon(polygon, px, py) {
// // ... (keep the existing implementation)
// }
findClosestEdge(polygon) {
let closestEdge = null;
let closestDistance = Infinity;
for (let i = 0; i < polygon.length; i++) {
let j = (i + 1) % polygon.length;
let x1 = polygon[i].x;
let y1 = polygon[i].y;
let x2 = polygon[j].x;
let y2 = polygon[j].y;
let edge = { x1, y1, x2, y2 };
let distance = this.distanceToLine(edge);
if (distance < closestDistance) {
closestDistance = distance;
closestEdge = edge;
}
}
let dx = closestEdge.x2 - closestEdge.x1;
let dy = closestEdge.y2 - closestEdge.y1;
closestEdge.angle = atan2(dy, dx);
return closestEdge;
}
distanceToLine(edge) {
let x1 = edge.x1;
let y1 = edge.y1;
let x2 = edge.x2;
let y2 = edge.y2;
let dx = x2 - x1;
let dy = y2 - y1;
let a = dy;
let b = -dx;
let c = dx * y1 - dy * x1;
let dist = Math.abs(a * this.x + b * this.y + c) / Math.sqrt(a * a + b * b);
return dist;
}
reflectVector(vector, normal) {
let dotProduct = vector.x * normal.x + vector.y * normal.y;
let reflectedVector = p5.Vector.sub(vector, p5.Vector.mult(normal, 2 * dotProduct));
return reflectedVector;
}
isPointInPolygon(polygon, px, py) {
const epsilon = 0.01; // Adjust this value as needed
const radius = this.radius;
let isInside = false;
let j = polygon.length - 1;
for (let i = 0; i < polygon.length; i++) {
let x1 = polygon[i].x;
let y1 = polygon[i].y;
let x2 = polygon[j].x;
let y2 = polygon[j].y;
if ((y1 > py + radius + epsilon) !== (y2 > py + radius + epsilon) &&
px + radius + epsilon < ((x2 - x1) * (py + radius + epsilon - y1)) / (y2 - y1) + x1) {
isInside = !isInside;
}
j = i;
}
return isInside;
}
display() {
fill(this.color);
noStroke();
ellipse(this.x, this.y, this.radius * 2, this.radius * 2);
}
}
function calculateEntropy() {
const gridSize = 10;
const grid = {};
const totalBalls = balls.length;
for (let ball of balls) {
const gridX = Math.floor(ball.x / gridSize);
const gridY = Math.floor(ball.y / gridSize);
const key = `${gridX},${gridY}`;
grid[key] = (grid[key] || 0) + 1;
}
let entropy = 0;
for (let count of Object.values(grid)) {
const probability = count / totalBalls;
entropy -= probability * Math.log2(probability);
}
return entropy;
}
function displayEntropyGraph() {
const graphWidth = 200;
const graphHeight = 100;
const x = width - graphWidth - 10;
const y = height - graphHeight - 10;
fill(0, 150);
rect(x, y, graphWidth, graphHeight);
stroke(255);
noFill();
beginShape();
for (let i = 0; i < entropyGraph.length; i++) {
const px = map(i, 0, entropyGraph.length - 1, x, x + graphWidth);
const py = map(entropyGraph[i], 0, 5, y + graphHeight, y);
vertex(px, py);
}
endShape();
fill(255);
noStroke();
textAlign(RIGHT);
text(`Entropy: ${entropyGraph[entropyGraph.length - 1].toFixed(2)}`, x + graphWidth, y - 5);
}
function displayInstructions() {
fill(255);
noStroke();
textAlign(LEFT);
textSize(14);
text("1. Draw a boundary by dragging the mouse", 10, 20);
text("2. Click inside the boundary to add balls", 10, 40);
text("3. Observe the entropy graph in the bottom right", 10, 60);
}
function windowResized() {
w = windowWidth;
h = windowHeight;
resizeCanvas(w, h);
}