34464-vm/puzzle.php
2025-09-28 22:38:17 +00:00

228 lines
9.6 KiB
PHP

<?php
ini_set('display_errors', 1);
error_reporting(E_ALL);
require_once 'db/config.php';
// --- VARIABLES ---
$puzzle_id = isset($_GET['id']) ? (int)$_GET['id'] : 0;
$difficulty = isset($_GET['difficulty']) ? (int)$_GET['difficulty'] : 16;
// Determine grid size based on difficulty
$valid_difficulties = [
16 => [4, 4], // 4x4 grid
32 => [8, 4], // 8x4 grid
64 => [8, 8] // 8x8 grid
];
if (!isset($valid_difficulties[$difficulty])) {
$difficulty = 16; // Fallback to default if invalid
}
list($cols, $rows) = $valid_difficulties[$difficulty];
$puzzle = null;
$error_message = '';
$pieces = [];
$source_width = 1;
$source_height = 1;
// --- DATA FETCHING & PUZZLE CREATION ---
if ($puzzle_id > 0) {
try {
$pdo = db();
$stmt = $pdo->prepare("SELECT * FROM puzzles WHERE id = ?");
$stmt->execute([$puzzle_id]);
$puzzle = $stmt->fetch(PDO::FETCH_ASSOC);
if (!$puzzle) {
$error_message = "Puzzle non trovato.";
} else {
$image_path = 'uploads/' . $puzzle['file_name'];
if (!file_exists($image_path)) {
$error_message = "File immagine del puzzle non trovato.";
} else {
$image_info = getimagesize($image_path);
$source_width = $image_info[0];
$source_height = $image_info[1];
// Use a difficulty-specific directory
$pieces_dir = sprintf('puzzles/%d/%d', $puzzle['id'], $difficulty);
if (!is_dir($pieces_dir)) {
mkdir($pieces_dir, 0777, true);
}
$piece_files = glob($pieces_dir . '/piece_*.jpg');
if (count($piece_files) !== ($cols * $rows)) {
foreach ($piece_files as $file) { unlink($file); }
$mime_type = $image_info['mime'];
$source_image = null;
switch ($mime_type) {
case 'image/jpeg': $source_image = imagecreatefromjpeg($image_path); break;
case 'image/png': $source_image = imagecreatefrompng($image_path); break;
case 'image/gif': $source_image = imagecreatefromgif($image_path); break;
default: $error_message = "Formato immagine non supportato."; break;
}
if ($source_image) {
$piece_width = floor($source_width / $cols);
$piece_height = floor($source_height / $rows);
for ($y = 0; $y < $rows; $y++) {
for ($x = 0; $x < $cols; $x++) {
$piece = imagecreatetruecolor($piece_width, $piece_height);
imagecopy($piece, $source_image, 0, 0, $x * $piece_width, $y * $piece_height, $piece_width, $piece_height);
imagejpeg($piece, "{$pieces_dir}/piece_{$y}_{$x}.jpg", 95);
imagedestroy($piece);
}
}
imagedestroy($source_image);
}
}
$pieces = glob($pieces_dir . '/piece_*.jpg');
shuffle($pieces);
}
}
} catch (PDOException $e) {
$error_message = "Errore di sistema: " . $e->getMessage();
}
} else {
$error_message = "ID del puzzle non valido.";
}
?>
<!DOCTYPE html>
<html lang="it">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Risolvi: <?php echo $puzzle ? htmlspecialchars($puzzle['name']) : 'Puzzle'; ?></title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet">
<link rel="stylesheet" href="assets/css/custom.css?v=<?php echo time(); ?>">
<style>
#puzzle-board {
border: 2px dashed #ccc;
background-color: #f8f9fa;
display: grid;
grid-template-columns: repeat(<?php echo $cols; ?>, 1fr);
grid-template-rows: repeat(<?php echo $rows; ?>, 1fr);
aspect-ratio: <?php echo $source_width; ?> / <?php echo $source_height; ?>;
max-width: 100%;
}
.drop-zone { border: 1px solid #eee; width: 100%; height: 100%; }
.drop-zone.hovered { background-color: #e9ecef; }
.puzzle-piece { cursor: grab; width: 100%; height: 100%; object-fit: cover; box-shadow: 0 0 5px rgba(0,0,0,0.5); }
#pieces-tray { display: flex; flex-wrap: wrap; justify-content: center; align-items: flex-start; min-height: 150px; background-color: #f0f0f0; border-radius: 10px; }
#pieces-tray .puzzle-piece { width: 80px; height: auto; margin: 4px; }
#win-message { display: none; position: fixed; top: 50%; left: 50%; transform: translate(-50%, -50%); background-color: rgba(40, 167, 69, 0.95); color: white; padding: 40px; border-radius: 15px; text-align: center; z-index: 1000; }
</style>
</head>
<body>
<div id="win-message">
<h2>Complimenti!</h2>
<p>Hai risolto il puzzle!</p>
<a href="index.php" class="btn btn-light">Gioca Ancora</a>
</div>
<div class="container mt-4">
<div class="text-center mb-4">
<h1><?php echo $puzzle ? htmlspecialchars($puzzle['name']) : 'Risolvi il Puzzle'; ?></h1>
<a href="index.php" class="btn btn-secondary btn-sm">Torna alla Galleria</a>
</div>
<?php if ($error_message): ?>
<div class="alert alert-danger"><?php echo htmlspecialchars($error_message); ?></div>
<?php elseif ($puzzle): ?>
<div class="text-center mb-3">
<form method="GET" action="puzzle.php" class="d-inline-flex align-items-center">
<input type="hidden" name="id" value="<?php echo $puzzle_id; ?>">
<label for="difficulty" class="form-label me-2 mb-0">Difficoltà:</label>
<select name="difficulty" id="difficulty" class="form-select form-select-sm" onchange="this.form.submit()">
<option value="16" <?php if ($difficulty == 16) echo 'selected'; ?>>Facile (16 pezzi)</option>
<option value="32" <?php if ($difficulty == 32) echo 'selected'; ?>>Medio (32 pezzi)</option>
<option value="64" <?php if ($difficulty == 64) echo 'selected'; ?>>Difficile (64 pezzi)</option>
</select>
</form>
</div>
<div class="row">
<div class="col-lg-8 col-md-12 mb-3">
<div id="puzzle-board"></div>
</div>
<div class="col-lg-4 col-md-12">
<h2 class="h5">I Tuoi Pezzi</h2>
<div id="pieces-tray" class="p-2">
<?php foreach ($pieces as $piece_path): ?>
<img src="<?php echo htmlspecialchars($piece_path); ?>" class="puzzle-piece" alt="Pezzo del puzzle" draggable="true">
<?php endforeach; ?>
</div>
</div>
</div>
<?php endif; ?>
</div>
<script>
document.addEventListener('DOMContentLoaded', () => {
const board = document.getElementById('puzzle-board');
const piecesTray = document.getElementById('pieces-tray');
const pieces = document.querySelectorAll('.puzzle-piece');
const cols = <?php echo $cols; ?>;
const rows = <?php echo $rows; ?>;
let draggedPiece = null;
for (let y = 0; y < rows; y++) {
for (let x = 0; x < cols; x++) {
const dropZone = document.createElement('div');
dropZone.classList.add('drop-zone');
dropZone.dataset.position = `${y}-${x}`;
board.appendChild(dropZone);
dropZone.addEventListener('dragover', e => { e.preventDefault(); dropZone.classList.add('hovered'); });
dropZone.addEventListener('dragleave', () => dropZone.classList.remove('hovered'));
dropZone.addEventListener('drop', e => {
e.preventDefault();
dropZone.classList.remove('hovered');
if (draggedPiece && dropZone.children.length === 0) {
dropZone.appendChild(draggedPiece);
checkWin();
}
});
}
}
piecesTray.addEventListener('dragover', e => e.preventDefault());
piecesTray.addEventListener('drop', e => {
e.preventDefault();
if (draggedPiece) { piecesTray.appendChild(draggedPiece); }
});
pieces.forEach(piece => {
const match = piece.src.match(/piece_(\d+)_(\d+)\.jpg$/);
if (match) { piece.dataset.position = `${match[1]}-${match[2]}`; }
piece.addEventListener('dragstart', e => {
draggedPiece = e.target;
setTimeout(() => { e.target.style.opacity = '0.5'; }, 0);
});
piece.addEventListener('dragend', e => {
draggedPiece = null;
e.target.style.opacity = '1';
});
});
function checkWin() {
const dropZones = board.querySelectorAll('.drop-zone');
if ([...dropZones].every(zone =>
zone.children.length > 0 &&
zone.children[0].dataset.position === zone.dataset.position
)) {
document.getElementById('win-message').style.display = 'block';
board.style.borderColor = '#28a745';
}
}
});
</script>
</body>
</html>