xxxxxxxxxx
149
function setup() {
createCanvas(600, 600);
noLoop();
}
function draw() {
background(255); // White background
let cellSize = 30; // Reduced cell size for more cells
let gridStrokeWeight = 4; // Thicker grid lines
// Draw the grid
stroke(200); // Light grey color
strokeWeight(gridStrokeWeight);
// Vertical grid lines
for (let x = 0; x <= width; x += cellSize) {
line(x, 0, x, height);
}
// Horizontal grid lines
for (let y = 0; y <= height; y += cellSize) {
line(0, y, width, y);
}
// Generate a path that crosses grid lines only at cell centers, without revisiting cells
let linePoints = [];
let cols = floor(width / cellSize);
let rows = floor(height / cellSize);
// Create a 2D array to keep track of visited cells
let visited = [];
for (let i = 0; i < cols; i++) {
visited[i] = [];
for (let j = 0; j < rows; j++) {
visited[i][j] = false;
}
}
// Start from a random cell
let currentCol = floor(random(cols));
let currentRow = floor(random(rows));
let currentX = currentCol * cellSize + cellSize / 2;
let currentY = currentRow * cellSize + cellSize / 2;
linePoints.push(createVector(currentX, currentY));
visited[currentCol][currentRow] = true;
// Create a path that moves to adjacent unvisited cell centers
let steps = cols * rows; // Maximum number of steps is total number of cells
for (let i = 0; i < steps; i++) {
// Find possible moves to adjacent unvisited cells
let possibleMoves = [];
if (currentCol > 0 && !visited[currentCol - 1][currentRow]) possibleMoves.push([-1, 0]); // left
if (currentCol < cols - 1 && !visited[currentCol + 1][currentRow]) possibleMoves.push([1, 0]); // right
if (currentRow > 0 && !visited[currentCol][currentRow - 1]) possibleMoves.push([0, -1]); // up
if (currentRow < rows - 1 && !visited[currentCol][currentRow + 1]) possibleMoves.push([0, 1]); // down
if (possibleMoves.length === 0) {
// No unvisited adjacent cells, stop the path
break;
}
// Randomly select a move
let move = random(possibleMoves);
currentCol += move[0];
currentRow += move[1];
currentX = currentCol * cellSize + cellSize / 2;
currentY = currentRow * cellSize + cellSize / 2;
linePoints.push(createVector(currentX, currentY));
visited[currentCol][currentRow] = true;
}
// Split the line into segments that alternate over and under the grid
let underSegments = [];
let overSegments = [];
let currentSegment = [];
let overUnder = true; // Start with over
for (let i = 0; i < linePoints.length - 1; i++) {
let pt1 = linePoints[i];
let pt2 = linePoints[i + 1];
currentSegment.push(pt1);
// Since we move between cell centers, every move crosses a grid line
currentSegment.push(pt2);
// Add the segment to the appropriate list
if (overUnder) {
overSegments.push([currentSegment]);
} else {
underSegments.push([currentSegment]);
}
// Reset the segment
currentSegment = [];
overUnder = !overUnder; // Toggle over/under
}
// Draw the under segments
stroke('limegreen');
let threadStrokeWeight = 10; // Thicker thread
strokeWeight(threadStrokeWeight);
for (let segment of underSegments) {
noFill();
beginShape();
for (let pt of segment) {
vertex(pt.x, pt.y);
}
endShape();
}
// Erase parts of the under-thread where it crosses grid lines
stroke(255); // Background color (white)
strokeWeight(gridStrokeWeight + 2); // Slightly thicker than the grid lines
// Redraw the grid lines over the under-thread
for (let x = 0; x <= width; x += cellSize) {
line(x, 0, x, height);
}
for (let y = 0; y <= height; y += cellSize) {
line(0, y, width, y);
}
// Redraw grid lines with the desired thickness
stroke(200); // Light grey color
strokeWeight(gridStrokeWeight);
for (let x = 0; x <= width; x += cellSize) {
line(x, 0, x, height);
}
for (let y = 0; y <= height; y += cellSize) {
line(0, y, width, y);
}
// Draw the over segments
stroke('limegreen');
strokeWeight(threadStrokeWeight);
for (let segment of overSegments) {
noFill();
beginShape();
for (let pt of segment) {
vertex(pt.x, pt.y);
}
endShape();
}
}