Tetris Shape Maker
by Ben Gillbanks
HTML
<h1>Tetris style Block Editor</h1>
<p>Select cells to design a shape. Then click "Generate Rotations".</p>
<table id="grid"></table>
<button id="generate">Generate Shape Rotations</button>
<pre id="output"></pre>
CSS
table {
border-collapse: collapse;
margin: 20px 0;
}
td {
width: 30px;
height: 30px;
text-align: center;
border: 1px solid #ccc;
}
JavaScript
// Create a 4x4 grid of checkboxes.
const grid = document.getElementById('grid');
const gridSize = 4;
for (let y = 0; y < gridSize; y++) {
const row = document.createElement('tr');
for (let x = 0; x < gridSize; x++) {
const cell = document.createElement('td');
const checkbox = document.createElement('input');
checkbox.type = 'checkbox';
checkbox.id = `cell-${x}-${y}`;
cell.appendChild(checkbox);
row.appendChild(cell);
}
grid.appendChild(row);
}
// Normalize the shape so its top-left coordinate is [0,0].
function normalizeShape(shape) {
const xs = shape.map(c => c[0]);
const ys = shape.map(c => c[1]);
const minX = Math.min(...xs);
const minY = Math.min(...ys);
return shape.map(([x, y]) => [x - minX, y - minY]);
}
// Rotate a shape 90° counterclockwise.
function rotateShape(shape) {
const norm = normalizeShape(shape);
const ys = norm.map(c => c[1]);
const height = Math.max(...ys) + 1;
// Rotation formula: [x, y] -> [height - 1 - y, x].
const rotated = norm.map(([x, y]) => [height - 1 - y, x]);
return normalizeShape(rotated);
}
// Check if two shapes (arrays of coordinate pairs) are equal.
function arraysEqual(a, b) {
if (a.length !== b.length) return false;
for (let i = 0; i < a.length; i++) {
if (a[i][0] !== b[i][0] || a[i][1] !== b[i][1]) return false;
}
return true;
}
// See if a shape is already in a list.
function shapeInList(shape, list) {
return list.some(item => arraysEqual(item, shape));
}
// Generate unique rotations (up to 4) until they repeat.
function generateRotations(shape) {
const rotations = [];
let current = normalizeShape(shape);
rotations.push(current);
for (let i = 0; i < 3; i++) {
current = rotateShape(current);
if (shapeInList(current, rotations)) {
break;
} else {
rotations.push(current);
}
}
return rotations;
}
// Read the grid and return the selected cell coordinates.
function getShapeFromGrid() {
const shape = [];
for (let y = 0; y < gridSize; y++) {
for (let x = 0; x <...