34464-vm/puzzle.php
Flatlogic Bot 6972ed7543 + Grafica
2025-09-28 23:26:12 +00:00

303 lines
11 KiB
PHP

<?php
session_start();
// Gatekeeper: redirect if not logged in
if (!isset($_SESSION['user_id'])) {
header('Location: login.php');
exit;
}
ini_set('display_errors', 1);
error_reporting(E_ALL);
require_once 'db/config.php';
// Handle Score Submission
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action']) && $_POST['action'] === 'save_score') {
header('Content-Type: application/json');
$user_id = $_SESSION['user_id'];
$puzzle_id = (int)$_POST['puzzle_id'];
$time_taken = (int)$_POST['time_taken'];
$moves = (int)$_POST['moves'];
// Simple scoring formula
$score = max(0, 10000 - ($time_taken * 10) - ($moves * 5));
try {
$pdo = db();
$stmt = $pdo->prepare("INSERT INTO scores (user_id, puzzle_id, time_taken, moves, score) VALUES (?, ?, ?, ?, ?)");
$stmt->execute([$user_id, $puzzle_id, $time_taken, $moves, $score]);
echo json_encode(['success' => true, 'score' => $score]);
} catch (PDOException $e) {
echo json_encode(['success' => false, 'error' => $e->getMessage()]);
}
exit; // Important: stop script execution after AJAX response
}
// --- 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];
$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.";
}
$page_title = 'Risolvi: ' . ($puzzle ? htmlspecialchars($puzzle['name']) : 'Puzzle');
require_once 'includes/header.php';
?>
<style>
#puzzle-board {
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%;
}
</style>
<div id="win-message">
<h2>Complimenti!</h2>
<p>Hai risolto il puzzle!</p>
<p>Punteggio: <strong id="final-score">0</strong></p>
<a href="leaderboard.php" class="btn btn-warning">Classifica</a>
<a href="index.php" class="btn btn-light">Gioca Ancora</a>
</div>
<main class="container mt-4">
<div class="text-center mb-4">
<h1><?php echo $puzzle ? htmlspecialchars($puzzle['name']) : 'Risolvi il Puzzle'; ?></h1>
<div class="d-flex justify-content-center align-items-center gap-3">
<a href="index.php" class="btn btn-secondary btn-sm">Torna alla Galleria</a>
<span class="badge bg-primary">Tempo: <span id="timer">0s</span></span>
<span class="badge bg-info">Mosse: <span id="move-counter">0</span></span>
</div>
</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" class="puzzle-board shadow-lg rounded"></div>
</div>
<div class="col-lg-4 col-md-12">
<div class="card p-2">
<h2 class="h5 text-center">I Tuoi Pezzi</h2>
<div id="pieces-tray" class="pieces-tray 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>
</div>
<?php endif; ?>
</main>
<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; ?>;
const puzzleId = <?php echo $puzzle_id; ?>;
let draggedPiece = null;
let moves = 0;
let gameStarted = false;
let startTime = 0;
let timerInterval = null;
function startTimer() {
if (gameStarted) return;
gameStarted = true;
startTime = Date.now();
timerInterval = setInterval(updateTimer, 1000);
}
function updateTimer() {
const seconds = Math.floor((Date.now() - startTime) / 1000);
document.getElementById('timer').textContent = `${seconds}s`;
}
function incrementMoves() {
moves++;
document.getElementById('move-counter').textContent = moves;
}
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) {
startTimer();
incrementMoves();
dropZone.appendChild(draggedPiece);
checkWin();
}
});
}
}
piecesTray.addEventListener('dragover', e => e.preventDefault());
piecesTray.addEventListener('drop', e => {
e.preventDefault();
if (draggedPiece) {
startTimer();
incrementMoves();
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
)) {
clearInterval(timerInterval);
const timeTaken = Math.floor((Date.now() - startTime) / 1000);
const formData = new FormData();
formData.append('action', 'save_score');
formData.append('puzzle_id', puzzleId);
formData.append('time_taken', timeTaken);
formData.append('moves', moves);
fetch('puzzle.php', {
method: 'POST',
body: formData
})
.then(response => response.json())
.then(data => {
if (data.success) {
document.getElementById('final-score').textContent = data.score;
document.getElementById('win-message').style.display = 'block';
board.style.borderColor = 'var(--mavi-orange)';
} else {
console.error('Failed to save score:', data.error);
alert('Si è verificato un errore durante il salvataggio del punteggio.');
}
});
}
}
});
</script>
<?php require_once 'includes/footer.php'; ?>