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