refactor: fillCanvasWithSquares

This commit is contained in:
sthag 2026-04-20 20:39:35 +02:00
parent 0f92174143
commit c73f4fbdb3

View file

@ -29,40 +29,21 @@ tags:
'#b7e0f0', '#52bed1', '#0c85ff' '#b7e0f0', '#52bed1', '#0c85ff'
]; ];
// Verify maxSquareSize and minSquareSize are powers of 2
if (!isPowerOfTwo(maxSquareSize) || !isPowerOfTwo(minSquareSize)) {
console.error('Both maxSquareSize and minSquareSize must be powers of 2');
return;
}
if (minSquareSize > maxSquareSize) {
console.error('minSquareSize must be <= maxSquareSize');
return;
}
if (largeSquarePercentage < 0 || largeSquarePercentage > 100) {
console.error('largeSquarePercentage must be between 0 and 100');
return;
}
function isPowerOfTwo(n) { function isPowerOfTwo(n) {
return n > 0 && (n & (n - 1)) === 0; return n > 0 && (n & (n - 1)) === 0;
} }
// Grid to track occupied cells if (!isPowerOfTwo(maxSquareSize) || !isPowerOfTwo(minSquareSize)) {
let grid = []; console.error('Both sizes must be powers of 2');
return;
}
function initializeGrid() { let grid = Array(Math.ceil(canvas.height / minSquareSize))
grid = Array(Math.ceil(canvas.height / minSquareSize))
.fill(null) .fill(null)
.map(() => Array(Math.ceil(canvas.width / minSquareSize)).fill(false)); .map(() => Array(Math.ceil(canvas.width / minSquareSize)).fill(false));
}
function canPlaceSquare(gridX, gridY, sizeInCells) {
if (gridY + sizeInCells > grid.length || gridX + sizeInCells > grid[0].length) {
return false;
}
function canPlace(gridX, gridY, sizeInCells) {
if (gridY + sizeInCells > grid.length || gridX + sizeInCells > grid[0].length) return false;
for (let y = gridY; y < gridY + sizeInCells; y++) { for (let y = gridY; y < gridY + sizeInCells; y++) {
for (let x = gridX; x < gridX + sizeInCells; x++) { for (let x = gridX; x < gridX + sizeInCells; x++) {
if (grid[y][x]) return false; if (grid[y][x]) return false;
@ -71,7 +52,7 @@ tags:
return true; return true;
} }
function markSquareOccupied(gridX, gridY, sizeInCells) { function markOccupied(gridX, gridY, sizeInCells) {
for (let y = gridY; y < gridY + sizeInCells; y++) { for (let y = gridY; y < gridY + sizeInCells; y++) {
for (let x = gridX; x < gridX + sizeInCells; x++) { for (let x = gridX; x < gridX + sizeInCells; x++) {
grid[y][x] = true; grid[y][x] = true;
@ -79,108 +60,67 @@ tags:
} }
} }
function drawSquare(gridX, gridY, sizeInPixels) { function draw(gridX, gridY, sizeInPixels) {
const pixelX = gridX * minSquareSize; const x = gridX * minSquareSize;
const pixelY = gridY * minSquareSize; const y = gridY * minSquareSize;
ctx.fillStyle = colors[Math.floor(Math.random() * colors.length)];
const color = colors[Math.floor(Math.random() * colors.length)]; ctx.fillRect(x, y, sizeInPixels, sizeInPixels);
ctx.fillStyle = color;
ctx.fillRect(pixelX, pixelY, sizeInPixels, sizeInPixels);
ctx.strokeStyle = '#333'; ctx.strokeStyle = '#333';
ctx.lineWidth = 1; ctx.lineWidth = 1;
ctx.strokeRect(pixelX, pixelY, sizeInPixels, sizeInPixels); ctx.strokeRect(x, y, sizeInPixels, sizeInPixels);
} }
function getSizesInDescendingOrder() { function fill() {
const sizes = []; const largestSizeInCells = maxSquareSize / minSquareSize;
for (let size = maxSquareSize; size >= minSquareSize; size /= 2) {
sizes.push(size);
}
return sizes;
}
function countPossibleSquares(size) { // Collect and shuffle positions for largest squares
const sizeInCells = size / minSquareSize;
let count = 0;
for (let gridY = 0; gridY < grid.length; gridY++) {
for (let gridX = 0; gridX < grid[0].length; gridX++) {
if (canPlaceSquare(gridX, gridY, sizeInCells)) {
count++;
}
}
}
return count;
}
function fillCanvasWithPercentage() {
const sizes = getSizesInDescendingOrder();
// Fill the largest squares based on percentage
const largestSize = sizes[0];
const maxPossibleLargeSquares = countPossibleSquares(largestSize);
const targetLargeSquares = Math.floor((maxPossibleLargeSquares * largeSquarePercentage) / 100);
const largestSizeInCells = largestSize / minSquareSize;
// Collect all valid positions for largest squares
if (targetLargeSquares > 0) {
const positions = []; const positions = [];
for (let gridY = 0; gridY < grid.length; gridY++) { for (let gridY = 0; gridY < grid.length; gridY++) {
for (let gridX = 0; gridX < grid[0].length; gridX++) { for (let gridX = 0; gridX < grid[0].length; gridX++) {
if (canPlaceSquare(gridX, gridY, largestSizeInCells)) { if (canPlace(gridX, gridY, largestSizeInCells)) {
positions.push({ gridX, gridY }); positions.push({ gridX, gridY });
} }
} }
} }
// Shuffle positions array
positions.sort(() => Math.random() - 0.5); positions.sort(() => Math.random() - 0.5);
// Place squares up to target percentage // Place largest squares up to percentage
let placedCount = 0; const target = Math.floor(positions.length * largeSquarePercentage / 100);
for (let i = 0; i < positions.length && placedCount < targetLargeSquares; i++) { for (let i = 0; i < target; i++) {
const { gridX, gridY } = positions[i]; const { gridX, gridY } = positions[i];
// Double-check the position is still valid before placing if (canPlace(gridX, gridY, largestSizeInCells)) {
if (canPlaceSquare(gridX, gridY, largestSizeInCells)) { markOccupied(gridX, gridY, largestSizeInCells);
markSquareOccupied(gridX, gridY, largestSizeInCells); draw(gridX, gridY, maxSquareSize);
drawSquare(gridX, gridY, largestSize);
placedCount++;
}
} }
} }
// Fill remaining space with all sizes in descending order // Fill remaining space with smaller sizes
// Skip the largest size since we already handled it for (let size = maxSquareSize / 2; size >= minSquareSize; size /= 2) {
for (let i = 1; i < sizes.length; i++) { const cellSize = size / minSquareSize;
const size = sizes[i];
const sizeInCells = size / minSquareSize;
for (let gridY = 0; gridY < grid.length; gridY++) { for (let gridY = 0; gridY < grid.length; gridY++) {
for (let gridX = 0; gridX < grid[0].length; gridX++) { for (let gridX = 0; gridX < grid[0].length; gridX++) {
if (canPlaceSquare(gridX, gridY, sizeInCells)) { if (canPlace(gridX, gridY, cellSize)) {
markSquareOccupied(gridX, gridY, sizeInCells); markOccupied(gridX, gridY, cellSize);
drawSquare(gridX, gridY, size); draw(gridX, gridY, size);
} }
} }
} }
} }
} }
initializeGrid(); fill();
fillCanvasWithPercentage();
window.addEventListener('resize', () => { window.addEventListener('resize', () => {
canvas.width = window.innerWidth; canvas.width = window.innerWidth;
canvas.height = window.innerHeight; canvas.height = window.innerHeight;
grid = Array(Math.ceil(canvas.height / minSquareSize))
.fill(null)
.map(() => Array(Math.ceil(canvas.width / minSquareSize)).fill(false));
ctx.clearRect(0, 0, canvas.width, canvas.height); ctx.clearRect(0, 0, canvas.width, canvas.height);
fill();
initializeGrid();
fillCanvasWithPercentage();
}); });
} }
fillCanvasWithSquares(128, 8, 40); fillCanvasWithSquares(128, 8, 10);
</script> </script>
{% endblock %} {% endblock %}