Created
May 22, 2025 23:16
-
-
Save mdchaney/c816094ae7b3898cdc24a8016a1cf5d8 to your computer and use it in GitHub Desktop.
Square puzzle
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<html lang="en"> | |
<head> | |
<meta charset="UTF-8"> | |
<meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
<title>Five Squares Puzzle Demo</title> | |
<style> | |
body { | |
margin: 0; | |
font-family: Arial, sans-serif; | |
text-align: center; | |
background-color: #f0f0f0; | |
} | |
.controls { | |
padding: 20px; | |
} | |
svg { | |
width: 100vw; | |
height: calc(100vh - 80px); | |
background-color: #e0e0e0; | |
} | |
.square { | |
fill: none; | |
stroke: black; | |
stroke-width: 2; | |
} | |
#smallest-square { | |
fill: #ff9999; | |
} | |
#h-line { | |
stroke: red; | |
stroke-width: 3; | |
} | |
#h-label { | |
fill: red; | |
font-size: 20px; | |
font-weight: bold; | |
} | |
</style> | |
</head> | |
<body> | |
<div class="controls"> | |
<label for="scale-slider">Scale Factor (c): <span id="scale-value">2</span></label><br> | |
<input type="range" id="scale-slider" min="1" max="5" step="0.1" value="2"> | |
<p>h = <span id="h-value">4</span></p> | |
</div> | |
<svg id="puzzle-svg"></svg> | |
<script> | |
const svg = document.getElementById('puzzle-svg'); | |
const slider = document.getElementById('scale-slider'); | |
const scaleValueDisplay = document.getElementById('scale-value'); | |
const hValueDisplay = document.getElementById('h-value'); | |
function drawPuzzle(c) { | |
svg.innerHTML = ''; | |
const svgWidth = svg.clientWidth; | |
const svgHeight = svg.clientHeight; | |
// Side lengths | |
const s = 1; | |
const a = c + 1; | |
const b = c + 2; | |
const d = c + 3; | |
// Compute h | |
const h = (b + d) - (a + c); // Should be 4 | |
const scale_factor = 5; | |
// Adjust coordinates | |
const xShift = scale_factor + 1; | |
const yShift = scale_factor; | |
// Define the squares' positions | |
const s1 = { x: 0, y: 0 }; | |
const s2 = { x: 1, y: 0 }; | |
const s3 = { x: 1, y:1 }; | |
const s4 = { x: 0, y: 1 }; | |
const a1 = { x: -c, y: 0 }; | |
const a2 = { x: 0, y: 0 }; | |
const a3 = { x: 0, y: c }; | |
const a4 = { x: -c, y: c }; | |
const b1 = { x: -c, y: 0 }; | |
const b2 = { x: 1, y: 0 }; | |
const b3 = { x: 1, y: -c - 1 }; | |
const b4 = { x: -c, y: -c - 1 }; | |
const c1 = { x: 1, y: 1 }; | |
const c2 = { x: 1, y: -c - 1 }; | |
const c3 = { x: c + 3, y: -c - 1 }; | |
const c4 = { x: c + 3, y: 1 }; | |
const d1 = { x: 0, y: 1 }; | |
const d2 = { x: c + 3, y: 1 }; | |
const d3 = { x: c + 3, y: c + 4 }; | |
const d4 = { x: 0, y: c + 4 }; | |
// Scale to fit SVG - scale factor is always 5 | |
const totalWidth = (scale_factor + 4) - (-1); | |
const totalHeight = (2 * scale_factor + 3) - 0 + h; // Include h below square C | |
const scale = Math.min(svgWidth / totalWidth, svgHeight / totalHeight) * 0.8; | |
const offsetX = (svgWidth - totalWidth * scale) / 2; | |
const offsetY = (svgHeight - totalHeight * scale) / 2; | |
const transform = (x, y) => ({ | |
x: (x + xShift) * scale + offsetX, | |
y: (y + yShift) * scale + offsetY | |
}); | |
// Transform all points | |
const squares = [ | |
{ points: [s1, s2, s3, s4].map(p => transform(p.x, p.y)), id: 'smallest-square' }, | |
{ points: [a1, a2, a3, a4].map(p => transform(p.x, p.y)) }, | |
{ points: [b1, b2, b3, b4].map(p => transform(p.x, p.y)) }, | |
{ points: [c1, c2, c3, c4].map(p => transform(p.x, p.y)) }, | |
{ points: [d1, d2, d3, d4].map(p => transform(p.x, p.y)) } | |
]; | |
squares.forEach(square => { | |
const pointsStr = square.points.map(p => `${p.x},${p.y}`).join(' '); | |
const poly = document.createElementNS('http://www.w3.org/2000/svg', 'polygon'); | |
poly.setAttribute('points', pointsStr); | |
poly.setAttribute('class', 'square'); | |
if (square.id) poly.setAttribute('id', square.id); | |
svg.appendChild(poly); | |
}); | |
// Draw the h line (from bottom of square A downward (+Y) by 4 units) | |
const hStart = transform(-0.5 * c, c); // Top of square C | |
const hEnd = transform(-0.5 * c, c + h); // Down by h units | |
const line = document.createElementNS('http://www.w3.org/2000/svg', 'line'); | |
line.setAttribute('x1', hStart.x); | |
line.setAttribute('y1', hStart.y); | |
line.setAttribute('x2', hEnd.x); | |
line.setAttribute('y2', hEnd.y); | |
line.setAttribute('id', 'h-line'); | |
svg.appendChild(line); | |
const hMid = transform(-0.5 * c - 0.5, c + h / 2); | |
const text = document.createElementNS('http://www.w3.org/2000/svg', 'text'); | |
text.setAttribute('x', hMid.x); | |
text.setAttribute('y', hMid.y); | |
text.setAttribute('id', 'h-label'); | |
text.textContent = 'h'; | |
svg.appendChild(text); | |
// Draw a blue circle at 0,0 to show the origin, with | |
// a z index of 999 so it's on top of the other elements | |
const circle = document.createElementNS('http://www.w3.org/2000/svg', 'circle'); | |
const origin = transform(0, 0); | |
circle.setAttribute('cx', origin.x); | |
circle.setAttribute('cy', origin.y); | |
circle.setAttribute('r', 5); | |
circle.setAttribute('fill', 'blue'); | |
circle.setAttribute('stroke', 'green'); | |
circle.setAttribute('stroke-width', 0.1); | |
circle.setAttribute('z-index', 999); | |
svg.appendChild(circle); | |
// And a red circle at 1,1 | |
const redCircle = document.createElementNS('http://www.w3.org/2000/svg', 'circle'); | |
const redOrigin = transform(1, 1); | |
redCircle.setAttribute('cx', redOrigin.x); | |
redCircle.setAttribute('cy', redOrigin.y); | |
redCircle.setAttribute('r', 5); | |
redCircle.setAttribute('fill', 'red'); | |
redCircle.setAttribute('stroke', 'green'); | |
redCircle.setAttribute('stroke-width', 0.1); | |
redCircle.setAttribute('z-index', 999); | |
svg.appendChild(redCircle); | |
scaleValueDisplay.textContent = c.toFixed(1); | |
hValueDisplay.textContent = h.toFixed(2); | |
} | |
drawPuzzle(parseFloat(slider.value)); | |
slider.addEventListener('input', () => { | |
const c = parseFloat(slider.value); | |
drawPuzzle(c); | |
}); | |
</script> | |
</body> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment