From f0b5ae87b62a2f21ad4bf7d0f8c3ff28ebc5aeba Mon Sep 17 00:00:00 2001 From: Evelyn Sucitro Date: Fri, 14 Nov 2025 12:31:54 +0700 Subject: [PATCH] Backend --- 2048.js | 244 ------------------------------------ Database.sql | 20 +++ Database.php => Koneksi.php | 0 Leaderboard.php | 23 ++++ Login.php | 45 ++++--- Logout.php | 18 ++- Register.php | 39 +++--- Save Score.php | 16 --- Save_Score.php | 32 +++++ Score.js | 18 +++ Session_Check.php | 15 +++ 11 files changed, 161 insertions(+), 309 deletions(-) delete mode 100644 2048.js create mode 100644 Database.sql rename Database.php => Koneksi.php (100%) delete mode 100644 Save Score.php create mode 100644 Save_Score.php create mode 100644 Score.js create mode 100644 Session_Check.php diff --git a/2048.js b/2048.js deleted file mode 100644 index b0043d3..0000000 --- a/2048.js +++ /dev/null @@ -1,244 +0,0 @@ -var board; -var score = 0; -var rows = 4; -var columns = 4; -var gameOver = false; - -window.onload = function () { - setGame(); - document.getElementById("replayBtn").addEventListener("click", restartGame); -}; - -function setGame() { - board = [ - [0, 0, 0, 0], - [0, 0, 0, 0], - [0, 0, 0, 0], - [0, 0, 0, 0], - ]; - - score = 0; - gameOver = false; - document.getElementById("score").innerText = score; - document.getElementById("board").innerHTML = ""; - - for (let r = 0; r < rows; r++) { - for (let c = 0; c < columns; c++) { - let tile = document.createElement("div"); - tile.id = r.toString() + "-" + c.toString(); - let num = board[r][c]; - updateTile(tile, num); - document.getElementById("board").append(tile); - } - } - - setTwo(); - setTwo(); -} - -function restartGame() { - document.getElementById("gameOverOverlay").style.display = "none"; - setGame(); -} - -function updateTile(tile, num) { - tile.innerText = ""; - tile.classList.value = ""; - tile.classList.add("tile"); - if (num > 0) { - tile.innerText = num.toString(); - if (num <= 4096) { - tile.classList.add("x" + num.toString()); - } else { - tile.classList.add("x8192"); - } - } -} - -document.addEventListener("keyup", (e) => { - if (gameOver) return; - - let moved = false; - - if (e.code == "ArrowLeft") { - moved = slideLeft(); - } else if (e.code == "ArrowRight") { - moved = slideRight(); - } else if (e.code == "ArrowUp") { - moved = slideUp(); - } else if (e.code == "ArrowDown") { - moved = slideDown(); - } - - // Only add new tile if board actually moved - if (moved) { - setTwo(); - document.getElementById("score").innerText = score; - } -}); - -function filterZero(row) { - return row.filter((num) => num != 0); -} - -function slide(row) { - row = filterZero(row); - for (let i = 0; i < row.length - 1; i++) { - if (row[i] == row[i + 1]) { - row[i] *= 2; - row[i + 1] = 0; - score += row[i]; - } - } - row = filterZero(row); - while (row.length < columns) { - row.push(0); - } - return row; -} - -function slideLeft() { - let moved = false; - for (let r = 0; r < rows; r++) { - let row = board[r]; - let original = [...row]; - row = slide(row); - board[r] = row; - - // Check if board changed - if (JSON.stringify(original) !== JSON.stringify(row)) { - moved = true; - } - - for (let c = 0; c < columns; c++) { - let tile = document.getElementById(r.toString() + "-" + c.toString()); - let num = board[r][c]; - updateTile(tile, num); - } - } - return moved; -} - -function slideRight() { - let moved = false; - for (let r = 0; r < rows; r++) { - let row = board[r]; - let original = [...row]; - row.reverse(); - row = slide(row); - board[r] = row.reverse(); - - // Check if board changed - if (JSON.stringify(original) !== JSON.stringify(board[r])) { - moved = true; - } - - for (let c = 0; c < columns; c++) { - let tile = document.getElementById(r.toString() + "-" + c.toString()); - let num = board[r][c]; - updateTile(tile, num); - } - } - return moved; -} - -function slideUp() { - let moved = false; - for (let c = 0; c < columns; c++) { - let row = [board[0][c], board[1][c], board[2][c], board[3][c]]; - let original = [...row]; - row = slide(row); - - // Check if board changed - if (JSON.stringify(original) !== JSON.stringify(row)) { - moved = true; - } - - for (let r = 0; r < rows; r++) { - board[r][c] = row[r]; - let tile = document.getElementById(r.toString() + "-" + c.toString()); - let num = board[r][c]; - updateTile(tile, num); - } - } - return moved; -} - -function slideDown() { - let moved = false; - for (let c = 0; c < columns; c++) { - let row = [board[0][c], board[1][c], board[2][c], board[3][c]]; - let original = [...row]; - row.reverse(); - row = slide(row); - row.reverse(); - - // Check if board changed - if (JSON.stringify(original) !== JSON.stringify(row)) { - moved = true; - } - - for (let r = 0; r < rows; r++) { - board[r][c] = row[r]; - let tile = document.getElementById(r.toString() + "-" + c.toString()); - let num = board[r][c]; - updateTile(tile, num); - } - } - return moved; -} - -function setTwo() { - if (!hasEmptyTile()) { - checkGameOver(); - return; - } - let found = false; - while (!found) { - let r = Math.floor(Math.random() * rows); - let c = Math.floor(Math.random() * columns); - if (board[r][c] == 0) { - board[r][c] = 2; - let tile = document.getElementById(r.toString() + "-" + c.toString()); - tile.innerText = "2"; - tile.classList.add("x2"); - found = true; - } - } -} - -function hasEmptyTile() { - for (let r = 0; r < rows; r++) { - for (let c = 0; c < columns; c++) { - if (board[r][c] == 0) { - return true; - } - } - } - return false; -} - -function checkGameOver() { - // Check if any moves are possible - for (let r = 0; r < rows; r++) { - for (let c = 0; c < columns; c++) { - // Check right - if (c < columns - 1 && board[r][c] == board[r][c + 1]) { - return; - } - // Check down - if (r < rows - 1 && board[r][c] == board[r + 1][c]) { - return; - } - } - } - - // No moves available - game over - gameOver = true; - showGameOver(); -} - -function showGameOver() { - document.getElementById("finalScore").innerText = score; - document.getElementById("gameOverOverlay").style.display = "flex"; -} diff --git a/Database.sql b/Database.sql new file mode 100644 index 0000000..48e6ab0 --- /dev/null +++ b/Database.sql @@ -0,0 +1,20 @@ +CREATE DATABASE IF NOT EXISTS 2048; +USE 2048; + +CREATE TABLE IF NOT EXISTS users ( + id INT AUTO_INCREMENT PRIMARY KEY, + username VARCHAR(50) NOT NULL UNIQUE, + password VARCHAR(255) NOT NULL, + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP +); + +CREATE TABLE IF NOT EXISTS leaderboard ( + id INT AUTO_INCREMENT PRIMARY KEY, + user_id INT, + username VARCHAR(50), + score INT NOT NULL, + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE SET NULL +); + +CREATE INDEX idx_score ON leaderboard(score DESC); \ No newline at end of file diff --git a/Database.php b/Koneksi.php similarity index 100% rename from Database.php rename to Koneksi.php diff --git a/Leaderboard.php b/Leaderboard.php index e69de29..dbdea31 100644 --- a/Leaderboard.php +++ b/Leaderboard.php @@ -0,0 +1,23 @@ +query($query); + +$leaderboard = []; + +if ($result && $result->num_rows > 0) { + while ($row = $result->fetch_assoc()) { + $leaderboard[] = $row; + } +} + +// Kirim data ke frontend dalam bentuk JSON +echo json_encode([ + "status" => "success", + "leaderboard" => $leaderboard +]); + +$conn->close(); +?> \ No newline at end of file diff --git a/Login.php b/Login.php index a26feed..583e01c 100644 --- a/Login.php +++ b/Login.php @@ -1,33 +1,38 @@ "error","message"=>"Username & password dibutuhkan"]); +$username = $_POST['username'] ?? ''; +$password = $_POST['password'] ?? ''; + +if (empty($username) || empty($password)) { + echo json_encode(["status" => "error", "message" => "Username dan password wajib diisi"]); exit; } -$username = trim($data['username']); -$password = $data['password']; - -$stmt = $conn->prepare("SELECT id, password FROM users WHERE username = ?"); +$stmt = $conn->prepare("SELECT password FROM users WHERE username = ?"); $stmt->bind_param("s", $username); $stmt->execute(); -$stmt->bind_result($id, $hash); -if ($stmt->fetch()) { - if (password_verify($password, $hash)) { - session_regenerate_id(true); - $_SESSION['user_id'] = $id; - $_SESSION['username'] = $username; - echo json_encode(["status"=>"success","message"=>"Login berhasil"]); - } else { - echo json_encode(["status"=>"error","message"=>"Password salah"]); - } -} else { - echo json_encode(["status"=>"error","message"=>"User tidak ditemukan"]); +$stmt->store_result(); + +if ($stmt->num_rows === 0) { + echo json_encode(["status" => "error", "message" => "Username tidak ditemukan"]); + $stmt->close(); + $conn->close(); + exit; } + +$stmt->bind_result($hashedPassword); +$stmt->fetch(); + +if (password_verify($password, $hashedPassword)) { + $_SESSION['username'] = $username; + echo json_encode(["status" => "success", "message" => "Login berhasil"]); +} else { + echo json_encode(["status" => "error", "message" => "Password salah"]); +} + $stmt->close(); $conn->close(); ?> \ No newline at end of file diff --git a/Logout.php b/Logout.php index ddc1066..33601c8 100644 --- a/Logout.php +++ b/Logout.php @@ -1,14 +1,12 @@ "success","message"=>"Logout berhasil"]); + +echo json_encode([ + "status" => "success", + "message" => "Logout berhasil" +]); ?> \ No newline at end of file diff --git a/Register.php b/Register.php index 1f8e16a..6e9fa43 100644 --- a/Register.php +++ b/Register.php @@ -1,37 +1,38 @@ "error","message"=>"Username & password dibutuhkan"]); +$username = $_POST['username'] ?? ''; +$password = $_POST['password'] ?? ''; + +if (empty($username) || empty($password)) { + echo json_encode(["status" => "error", "message" => "Username dan password wajib diisi"]); exit; } -$username = trim($data['username']); -$password = $data['password']; +$check = $conn->prepare("SELECT id FROM users WHERE username = ?"); +$check->bind_param("s", $username); +$check->execute(); +$check->store_result(); -$stmt = $conn->prepare("SELECT id FROM users WHERE username = ?"); -$stmt->bind_param("s", $username); -$stmt->execute(); -$stmt->store_result(); -if ($stmt->num_rows > 0) { - echo json_encode(["status"=>"error","message"=>"Username sudah terpakai"]); +if ($check->num_rows > 0) { + echo json_encode(["status" => "error", "message" => "Username sudah digunakan"]); + $check->close(); + $conn->close(); exit; } -$stmt->close(); -$hash = password_hash($password, PASSWORD_DEFAULT); +$hashedPassword = password_hash($password, PASSWORD_DEFAULT); + $stmt = $conn->prepare("INSERT INTO users (username, password) VALUES (?, ?)"); -$stmt->bind_param("ss", $username, $hash); +$stmt->bind_param("ss", $username, $hashedPassword); + if ($stmt->execute()) { - $_SESSION['user_id'] = $stmt->insert_id; - $_SESSION['username'] = $username; - echo json_encode(["status"=>"success","message"=>"Register berhasil"]); + echo json_encode(["status" => "success", "message" => "Pendaftaran berhasil"]); } else { - echo json_encode(["status"=>"error","message"=>"Gagal mendaftar"]); + echo json_encode(["status" => "error", "message" => "Gagal mendaftar"]); } + $stmt->close(); $conn->close(); ?> \ No newline at end of file diff --git a/Save Score.php b/Save Score.php deleted file mode 100644 index e8a5302..0000000 --- a/Save Score.php +++ /dev/null @@ -1,16 +0,0 @@ - "success"]); -} else { - echo json_encode(["status" => "error", "message" => "Not logged in"]); -} -?> \ No newline at end of file diff --git a/Save_Score.php b/Save_Score.php new file mode 100644 index 0000000..b86b5fa --- /dev/null +++ b/Save_Score.php @@ -0,0 +1,32 @@ + "error", "message" => "Belum login"]); + exit; +} + +$username = $_SESSION['username']; +$score = $_POST['score'] ?? 0; + +if ($score <= 0) { + echo json_encode(["status" => "error", "message" => "Skor tidak valid"]); + exit; +} + +// Simpan ke database +$stmt = $conn->prepare("INSERT INTO leaderboard (username, score) VALUES (?, ?)"); +$stmt->bind_param("si", $username, $score); + +if ($stmt->execute()) { + echo json_encode(["status" => "success", "message" => "Skor berhasil disimpan"]); +} else { + echo json_encode(["status" => "error", "message" => "Gagal menyimpan skor"]); +} + +$stmt->close(); +$conn->close(); +?> \ No newline at end of file diff --git a/Score.js b/Score.js new file mode 100644 index 0000000..61dab53 --- /dev/null +++ b/Score.js @@ -0,0 +1,18 @@ +function saveScore(score) { + fetch('Save_Score.php', { + method: 'POST', + headers: { + 'Content-Type': 'application/x-www-form-urlencoded' + }, + body: 'score=' + encodeURIComponent(score) + }) + .then(response => response.json()) + .then(data => { + if (data.status === "success") { + console.log("Skor berhasil disimpan!"); + } else { + console.log("Gagal menyimpan skor:", data.message); + } + }) + .catch(error => console.error("Error API:", error)); +} \ No newline at end of file diff --git a/Session_Check.php b/Session_Check.php new file mode 100644 index 0000000..1e3feb7 --- /dev/null +++ b/Session_Check.php @@ -0,0 +1,15 @@ + "logged_in", + "username" => $_SESSION['username'] + ]); +} else { + echo json_encode([ + "status" => "not_logged_in" + ]); +} +?> \ No newline at end of file