<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 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>
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;
}
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 Pen doesn't use any external CSS resources.
This Pen doesn't use any external JavaScript resources.