A Pen by Stan Williams on CodePen.
Created
May 20, 2025 23:21
-
-
Save stanwmusic/e36b0cfd29c913a1ad293f5ab607331c to your computer and use it in GitHub Desktop.
8 Queens 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>8 Queens Puzzle</title> | |
<link rel="stylesheet" href="style.css"> | |
</head> | |
<body> | |
<h1>8 Dang Queens Puzzle</h1> | |
<div class="controls"> | |
<button id="reset-button">Reset Game</button> | |
<p id="message">Place 8 queens so that none attack each other. Click a square to place/remove a queen.</p> | |
<p>Queens placed: <span id="queen-count">0</span> / 8</p> | |
</div> | |
<div id="chessboard"> | |
<!-- Squares will be generated by JavaScript --> | |
</div> | |
<script src="script.js"></script> | |
</body> | |
</html> |
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
document.addEventListener('DOMContentLoaded', () => { | |
const boardSize = 8; | |
const chessboard = document.getElementById('chessboard'); | |
const messageElement = document.getElementById('message'); | |
const queenCountElement = document.getElementById('queen-count'); | |
const resetButton = document.getElementById('reset-button'); | |
const bodyElement = document.body; | |
let boardState = Array(boardSize).fill(null).map(() => Array(boardSize).fill(0)); // 0: empty, 1: queen | |
let queenCount = 0; | |
let gameOver = false; | |
// --- Board Generation --- | |
function createBoard() { | |
chessboard.innerHTML = ''; // Clear previous board | |
for (let row = 0; row < boardSize; row++) { | |
for (let col = 0; col < boardSize; col++) { | |
const square = document.createElement('div'); | |
square.classList.add('square'); | |
square.classList.add(((row + col) % 2 === 0) ? 'light' : 'dark'); | |
square.dataset.row = row; | |
square.dataset.col = col; | |
square.addEventListener('click', handleSquareClick); | |
chessboard.appendChild(square); | |
} | |
} | |
} | |
// --- Game Logic --- | |
function isSafe(row, col) { | |
// Check row and column | |
for (let i = 0; i < boardSize; i++) { | |
if (boardState[row][i] === 1 || boardState[i][col] === 1) { | |
return false; | |
} | |
} | |
// Check diagonals | |
for (let i = 1; row - i >= 0 && col - i >= 0; i++) { // Top-left | |
if (boardState[row - i][col - i] === 1) return false; | |
} | |
for (let i = 1; row - i >= 0 && col + i < boardSize; i++) { // Top-right | |
if (boardState[row - i][col + i] === 1) return false; | |
} | |
for (let i = 1; row + i < boardSize && col - i >= 0; i++) { // Bottom-left | |
if (boardState[row + i][col - i] === 1) return false; | |
} | |
for (let i = 1; row + i < boardSize && col + i < boardSize; i++) { // Bottom-right | |
if (boardState[row + i][col + i] === 1) return false; | |
} | |
return true; | |
} | |
function handleSquareClick(event) { | |
if (gameOver) return; // Don't allow changes after winning | |
const square = event.target; | |
const row = parseInt(square.dataset.row); | |
const col = parseInt(square.dataset.col); | |
messageElement.textContent = "Place 8 queens so that none attack each other."; // Reset message | |
bodyElement.classList.remove('win'); | |
if (boardState[row][col] === 1) { | |
// Remove queen | |
boardState[row][col] = 0; | |
square.classList.remove('queen'); | |
queenCount--; | |
} else { | |
// Try to place queen | |
if (isSafe(row, col)) { | |
boardState[row][col] = 1; | |
square.classList.add('queen'); | |
queenCount++; | |
if (queenCount === boardSize) { | |
checkWinCondition(); | |
} | |
} else { | |
// Optionally provide feedback for invalid placement | |
// square.classList.add('invalid'); | |
// setTimeout(() => square.classList.remove('invalid'), 200); | |
messageElement.textContent = "Invalid move! A queen here is attacked."; | |
} | |
} | |
updateQueenCount(); | |
} | |
function updateQueenCount() { | |
queenCountElement.textContent = queenCount; | |
} | |
function checkWinCondition() { | |
// Since we prevent invalid moves, reaching 8 queens means success | |
if (queenCount === boardSize) { | |
messageElement.textContent = "Congratulations! You solved the 8 Queens puzzle!"; | |
bodyElement.classList.add('win'); // Add class for styling | |
gameOver = true; // Stop further placements | |
} | |
} | |
// --- Reset --- | |
function resetGame() { | |
boardState = Array(boardSize).fill(null).map(() => Array(boardSize).fill(0)); | |
queenCount = 0; | |
gameOver = false; | |
messageElement.textContent = "Place 8 queens so that none attack each other."; | |
bodyElement.classList.remove('win'); | |
updateQueenCount(); | |
// Clear visual representation | |
const squares = chessboard.querySelectorAll('.square'); | |
squares.forEach(square => square.classList.remove('queen')); | |
} | |
// --- Initialization --- | |
createBoard(); | |
resetButton.addEventListener('click', resetGame); | |
updateQueenCount(); // Initial count (0) | |
}); |
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
body { | |
font-family: sans-serif; | |
display: flex; | |
flex-direction: column; | |
align-items: center; | |
background-color: #f0f0f0; | |
margin-top: 20px; | |
} | |
h1 { | |
color: #333; | |
} | |
.controls { | |
margin-bottom: 20px; | |
text-align: center; | |
} | |
#reset-button { | |
padding: 10px 20px; | |
font-size: 1em; | |
cursor: pointer; | |
background-color: #4CAF50; | |
color: white; | |
border: none; | |
border-radius: 5px; | |
margin-bottom: 10px; | |
} | |
#reset-button:hover { | |
background-color: #45a049; | |
} | |
#message { | |
font-style: italic; | |
color: #555; | |
min-height: 20px; /* Prevent layout shift */ | |
} | |
#queen-count { | |
font-weight: bold; | |
} | |
#chessboard { | |
width: 400px; /* Adjust size as needed */ | |
height: 400px; /* Should be equal to width */ | |
display: grid; | |
grid-template-columns: repeat(8, 1fr); | |
grid-template-rows: repeat(8, 1fr); | |
border: 3px solid #333; | |
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2); | |
} | |
.square { | |
width: 100%; | |
height: 100%; | |
display: flex; | |
justify-content: center; | |
align-items: center; | |
font-size: 2.5em; /* Adjust queen size */ | |
cursor: pointer; | |
user-select: none; /* Prevent text selection on click */ | |
transition: background-color 0.1s ease-in-out; /* Smooth highlight */ | |
} | |
.square.light { | |
background-color: #f0d9b5; /* Light square color */ | |
} | |
.square.dark { | |
background-color: #b58863; /* Dark square color */ | |
} | |
.square.queen::before { | |
content: '♛'; /* Queen symbol */ | |
color: #000; /* Queen color */ | |
} | |
/* Optional: Highlight invalid moves briefly */ | |
/* .square.invalid { | |
background-color: rgba(255, 0, 0, 0.5) !important; | |
} */ | |
/* Style for winning state */ | |
.win #message { | |
color: green; | |
font-weight: bold; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment