257 lines
7.4 KiB
PHP
257 lines
7.4 KiB
PHP
<?php
|
|
require_once 'db.php';
|
|
|
|
// Auto-create table if it doesn't exist
|
|
try {
|
|
$checkTable = $conn->query("SHOW TABLES LIKE 'leaderboard_sudoku'");
|
|
if ($checkTable->rowCount() == 0) {
|
|
$createSql = "
|
|
CREATE TABLE leaderboard_sudoku (
|
|
id INT AUTO_INCREMENT PRIMARY KEY,
|
|
username VARCHAR(50),
|
|
difficulty VARCHAR(10),
|
|
time_seconds INT,
|
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
|
)";
|
|
$conn->exec($createSql);
|
|
}
|
|
} catch (PDOException $e) {
|
|
// Fail silently or log, but attempting to continue might show empty leaderboard instead of crash
|
|
}
|
|
|
|
// Helper function to get top 10 by difficulty
|
|
function getLeaderboard($conn, $difficulty) {
|
|
$sql = "
|
|
SELECT username, time_seconds, created_at
|
|
FROM leaderboard_sudoku
|
|
WHERE difficulty = :difficulty
|
|
ORDER BY time_seconds ASC
|
|
LIMIT 10
|
|
";
|
|
$stmt = $conn->prepare($sql);
|
|
$stmt->execute(['difficulty' => $difficulty]);
|
|
return $stmt->fetchAll(PDO::FETCH_ASSOC);
|
|
}
|
|
|
|
// Fetch data for each level
|
|
$easyData = getLeaderboard($conn, 'easy');
|
|
$mediumData = getLeaderboard($conn, 'medium');
|
|
$hardData = getLeaderboard($conn, 'hard');
|
|
?>
|
|
|
|
<!DOCTYPE html>
|
|
<html lang="id">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title>Leaderboard Sudoku</title>
|
|
<style>
|
|
body {
|
|
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
|
|
background-color: #121212;
|
|
color: white;
|
|
display: flex;
|
|
flex-direction: column;
|
|
align-items: center;
|
|
min-height: 100vh;
|
|
margin: 0;
|
|
padding: 20px;
|
|
}
|
|
|
|
h2 { margin-bottom: 20px; }
|
|
|
|
.leaderboard-container {
|
|
width: 100%;
|
|
max-width: 500px;
|
|
background: #1e1e1e;
|
|
border-radius: 12px;
|
|
overflow: hidden;
|
|
box-shadow: 0 4px 15px rgba(0,0,0,0.5);
|
|
}
|
|
|
|
/* Tabs Navigation */
|
|
.tabs {
|
|
display: flex;
|
|
width: 100%;
|
|
}
|
|
|
|
.tab-btn {
|
|
flex: 1;
|
|
padding: 15px;
|
|
border: none;
|
|
cursor: pointer;
|
|
font-size: 16px;
|
|
font-weight: bold;
|
|
color: #ccc;
|
|
background-color: #2c2c2c;
|
|
transition: 0.3s;
|
|
border-bottom: 4px solid transparent;
|
|
}
|
|
|
|
.tab-btn:hover {
|
|
background-color: #333;
|
|
color: white;
|
|
}
|
|
|
|
/* Active Tab Styling - Colors requested: Easy=Green, Medium=Yellow, Hard=Blue */
|
|
.tab-btn.active.easy {
|
|
background-color: #1e1e1e;
|
|
color: #4CAF50; /* Green */
|
|
border-bottom-color: #4CAF50;
|
|
}
|
|
.tab-btn.active.medium {
|
|
background-color: #1e1e1e;
|
|
color: #2196F3; /* Blue */
|
|
border-bottom-color: #2196F3;
|
|
}
|
|
.tab-btn.active.hard {
|
|
background-color: #1e1e1e;
|
|
color: #f44336; /* Red */
|
|
border-bottom-color: #f44336;
|
|
}
|
|
|
|
/* Content Sections */
|
|
.tab-content {
|
|
display: none; /* Hidden by default */
|
|
padding: 20px;
|
|
animation: fadeIn 0.4s;
|
|
}
|
|
|
|
.tab-content.active {
|
|
display: block;
|
|
}
|
|
|
|
table {
|
|
width: 100%;
|
|
border-collapse: collapse;
|
|
margin-top: 10px;
|
|
}
|
|
|
|
th, td {
|
|
text-align: left;
|
|
padding: 12px;
|
|
border-bottom: 1px solid #333;
|
|
}
|
|
|
|
th {
|
|
color: #888;
|
|
font-size: 14px;
|
|
text-transform: uppercase;
|
|
}
|
|
|
|
tr:last-child td {
|
|
border-bottom: none;
|
|
}
|
|
|
|
/* Rank Colors */
|
|
.rank-1 { color: gold; font-weight: bold; }
|
|
.rank-2 { color: silver; font-weight: bold; }
|
|
.rank-3 { color: #cd7f32; font-weight: bold; } /* Bronze */
|
|
|
|
.back-btn {
|
|
margin-top: 20px;
|
|
padding: 10px 20px;
|
|
background-color: #333;
|
|
color: white;
|
|
border: none;
|
|
border-radius: 20px;
|
|
cursor: pointer;
|
|
text-decoration: none;
|
|
font-weight: bold;
|
|
transition: 0.2s;
|
|
}
|
|
.back-btn:hover {
|
|
background-color: #444;
|
|
}
|
|
|
|
@keyframes fadeIn {
|
|
from { opacity: 0; transform: translateY(5px); }
|
|
to { opacity: 1; transform: translateY(0); }
|
|
}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
|
|
<h2>🏆 Leaderboard</h2>
|
|
|
|
<div class="leaderboard-container">
|
|
<!-- Tabs -->
|
|
<div class="tabs">
|
|
<button class="tab-btn easy active" onclick="openTab('easy')">MUDAH</button>
|
|
<button class="tab-btn medium" onclick="openTab('medium')">SEDANG</button>
|
|
<button class="tab-btn hard" onclick="openTab('hard')">SULIT</button>
|
|
</div>
|
|
|
|
<!-- Easy Section -->
|
|
<div id="easy" class="tab-content active">
|
|
<h3 style="color: #4CAF50; margin-top: 0;">Level Mudah</h3>
|
|
<?php renderTable($easyData); ?>
|
|
</div>
|
|
|
|
<!-- Medium Section -->
|
|
<div id="medium" class="tab-content">
|
|
<h3 style="color: #2196F3; margin-top: 0;">Level Sedang</h3>
|
|
<?php renderTable($mediumData); ?>
|
|
</div>
|
|
|
|
<!-- Hard Section -->
|
|
<div id="hard" class="tab-content">
|
|
<h3 style="color: #f44336; margin-top: 0;">Level Sulit</h3>
|
|
<?php renderTable($hardData); ?>
|
|
</div>
|
|
</div>
|
|
|
|
<a href="Sudoku.php" class="back-btn">Kembali ke Game</a>
|
|
|
|
<script>
|
|
function openTab(difficulty) {
|
|
// Hide all tab contents
|
|
const contents = document.querySelectorAll('.tab-content');
|
|
contents.forEach(content => content.classList.remove('active'));
|
|
|
|
// Deactivate all buttons
|
|
const buttons = document.querySelectorAll('.tab-btn');
|
|
buttons.forEach(btn => btn.classList.remove('active'));
|
|
|
|
// Activate specific tab and button
|
|
document.getElementById(difficulty).classList.add('active');
|
|
|
|
// Find the button that calls this function (or match by class) needs logic if I don't pass 'this'
|
|
// Using querySelector to find the button with specific class for simplicity in this context
|
|
document.querySelector(`.tab-btn.${difficulty}`).classList.add('active');
|
|
}
|
|
</script>
|
|
|
|
</body>
|
|
</html>
|
|
|
|
<?php
|
|
// Helper to render table
|
|
function renderTable($data) {
|
|
if (count($data) === 0) {
|
|
echo "<p style='color: gray; text-align: center; padding: 20px;'>Belum ada data.</p>";
|
|
return;
|
|
}
|
|
|
|
echo "<table>";
|
|
echo "<tr><th>Rank</th><th>Player</th><th>Waktu</th></tr>";
|
|
|
|
$rank = 1;
|
|
foreach ($data as $row) {
|
|
$timeStr = sprintf("%02d:%02d", floor($row['time_seconds'] / 60), $row['time_seconds'] % 60);
|
|
|
|
$rankClass = '';
|
|
if ($rank == 1) $rankClass = 'rank-1';
|
|
elseif ($rank == 2) $rankClass = 'rank-2';
|
|
elseif ($rank == 3) $rankClass = 'rank-3';
|
|
|
|
echo "<tr>";
|
|
echo "<td class='{$rankClass}'>#{$rank}</td>";
|
|
echo "<td>" . htmlspecialchars($row['username']) . "</td>";
|
|
echo "<td>{$timeStr}</td>";
|
|
echo "</tr>";
|
|
$rank++;
|
|
}
|
|
echo "</table>";
|
|
}
|
|
?>
|