Adds a leaderboard
This commit is contained in:
53
html/api/klumpy.php
Executable file
53
html/api/klumpy.php
Executable file
@@ -0,0 +1,53 @@
|
||||
<?php
|
||||
require_once "api.php";
|
||||
// Used to create an entry in the leaderboard
|
||||
if (array_key_exists("board", $_POST) && array_key_exists("history", $_POST) && array_key_exists("points", $_POST) && array_key_exists("type", $_POST)) {
|
||||
exec("node ../klumpy/score.js " . escapeshellarg($OGPOST["board"]), $points);
|
||||
$points = array_sum(json_decode(join("", $points)));
|
||||
if ($points > 0 && $points == intval($_POST["points"]) && $_POST["type"] == "main") {
|
||||
if ($USERNAME) {
|
||||
$ID = random_int(0, 2147483600);
|
||||
dbCommand("DELETE FROM klumpy WHERE gameID = ?", [$ID]);
|
||||
dbCommand("INSERT INTO klumpy (gameID, `type`, username, score, board, history) VALUES (?, ?, ?, ?, ?, ?)", [$ID, $_POST["type"], $USERNAME, $points, $OGPOST["board"], $OGPOST["history"]]);
|
||||
}
|
||||
http_response_code(200);
|
||||
// Gets the leaderboard position
|
||||
$position = count(dbRequest2("SELECT DISTINCT(username) FROM klumpy WHERE score >= ? ORDER BY score", "*", [$points]));
|
||||
// Adds one to the leaderboard position if the user is not logged in due to that meaning that he is not in the DB
|
||||
if (!$USERNAME) {
|
||||
$position += 1;
|
||||
echo json_encode([
|
||||
"position" => $position,
|
||||
"points" => $points,
|
||||
"error" => true,
|
||||
"message" => "You are not logged in",
|
||||
]);
|
||||
} else {
|
||||
echo json_encode([
|
||||
"position" => $position,
|
||||
"points" => $points,
|
||||
"error" => false,
|
||||
"gameID" => $ID,
|
||||
]);
|
||||
}
|
||||
} else {
|
||||
http_response_code(400);
|
||||
echo "Invalid board";
|
||||
}
|
||||
} elseif (array_key_exists("gameID", $_GET)) {
|
||||
$GAME = dbRequest2("SELECT * FROM klumpy WHERE gameID = ?", "*", [$_GET["gameID"]]);
|
||||
if ($GAME) {
|
||||
http_response_code(200);
|
||||
echo json_encode($GAME[0]);
|
||||
} else {
|
||||
http_response_code(404);
|
||||
echo "Invalid gameID";
|
||||
}
|
||||
} elseif (array_key_exists("search", $_GET)) {
|
||||
$LIMIT = intval($_GET["search"]);
|
||||
$DATA = dbRequest2("SELECT gameID, username, score FROM klumpy ORDER BY score DESC LIMIT $LIMIT");
|
||||
echo json_encode($DATA);
|
||||
} else {
|
||||
http_response_code(400);
|
||||
echo "Invalid command";
|
||||
}
|
||||
@@ -1,273 +1,280 @@
|
||||
body {
|
||||
background-color: black;
|
||||
color: white;
|
||||
font-size: 18px;
|
||||
font-family:'Roboto', sans-serif;
|
||||
background-color: black;
|
||||
color: white;
|
||||
font-size: 18px;
|
||||
font-family: "Roboto", sans-serif;
|
||||
}
|
||||
|
||||
.main {
|
||||
margin-left: 250px;
|
||||
margin-right: 10px;
|
||||
margin-left: 250px;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
a {
|
||||
color: rgb(42, 42, 255);
|
||||
color: rgb(42, 42, 255);
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 50px;
|
||||
font-size: 50px;
|
||||
}
|
||||
|
||||
h2 {
|
||||
color: red;
|
||||
color: red;
|
||||
}
|
||||
.menu-nav {
|
||||
background-color: green;
|
||||
padding-top: 30px;
|
||||
width: 240px;
|
||||
height: 100%;
|
||||
font-size: 20px;
|
||||
z-index: 1;
|
||||
top: 0;
|
||||
left: 0;
|
||||
position: fixed;
|
||||
overflow-y: scroll;
|
||||
background-color: green;
|
||||
padding-top: 30px;
|
||||
width: 240px;
|
||||
height: 100%;
|
||||
font-size: 20px;
|
||||
z-index: 1;
|
||||
top: 0;
|
||||
left: 0;
|
||||
position: fixed;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
.menu-nav ul {
|
||||
padding: 0px;
|
||||
margin: 0px;
|
||||
padding: 0px;
|
||||
margin: 0px;
|
||||
}
|
||||
|
||||
.menu-nav li {
|
||||
list-style: none;
|
||||
margin: 0px;
|
||||
overflow: hidden;
|
||||
list-style: none;
|
||||
margin: 0px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.menu-nav a {
|
||||
padding: 6px 6px 6px 30px;
|
||||
background-color: green;
|
||||
color: white;
|
||||
display: block;
|
||||
text-decoration: none;
|
||||
padding: 6px 6px 6px 30px;
|
||||
background-color: green;
|
||||
color: white;
|
||||
display: block;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.menu-nav a:hover {
|
||||
background-color: darkgreen;
|
||||
font-size: 22px;
|
||||
background-color: darkgreen;
|
||||
font-size: 22px;
|
||||
}
|
||||
|
||||
.menu-nav a.active {
|
||||
background-color: black;
|
||||
background-color: black;
|
||||
}
|
||||
.menu .menu-btn {
|
||||
display: none;
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* Used for the mobile menu */
|
||||
@media (max-width: 900px) {
|
||||
.menu-nav {
|
||||
height: 63px;
|
||||
padding: 0px;
|
||||
position: fixed;
|
||||
overflow-y: none;
|
||||
width: 100%;
|
||||
margin: 0px;
|
||||
transition: all 0.2s ease-in-out;
|
||||
}
|
||||
.main {
|
||||
margin-left: 10px;
|
||||
margin-top: 80px;
|
||||
}
|
||||
.menu-nav a {
|
||||
text-align: center;
|
||||
font-size: 22px;
|
||||
padding: 6px;
|
||||
}
|
||||
.menu-nav ul {
|
||||
display: none;
|
||||
}
|
||||
.menu .menu-btn:checked ~ .menu-nav {
|
||||
height: 100%;
|
||||
transition: all 0.2s ease-in-out;
|
||||
}
|
||||
.menu .menu-btn:checked ~ .menu-nav ul {
|
||||
margin-top: 80px;
|
||||
display: block;
|
||||
}
|
||||
/* Used for the icon */
|
||||
.menu .menu-btn:checked ~ .menu-icon .navicon {
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
.menu .menu-btn:checked ~ .menu-icon .navicon:before {
|
||||
transform: rotate(-45deg);
|
||||
}
|
||||
|
||||
.menu .menu-btn:checked ~ .menu-icon .navicon:after {
|
||||
transform: rotate(45deg);
|
||||
}
|
||||
|
||||
.menu .menu-btn:checked ~ .menu-icon:not(.steps) .navicon:before,
|
||||
.menu .menu-btn:checked ~ .menu-icon:not(.steps) .navicon:after {
|
||||
top: 0;
|
||||
}
|
||||
.menu .menu-icon {
|
||||
cursor: pointer;
|
||||
display: inline-block;
|
||||
padding: 30px 30px;
|
||||
position: fixed;
|
||||
top : 0;
|
||||
user-select: none;
|
||||
z-index: 5;
|
||||
}
|
||||
|
||||
.menu .menu-icon .navicon {
|
||||
background: #fff;
|
||||
display: block;
|
||||
height: 3px;
|
||||
position: relative;
|
||||
transition: #fff .2s ease-out;
|
||||
width: 30px;
|
||||
}
|
||||
|
||||
.menu .menu-icon .navicon:before,
|
||||
.menu .menu-icon .navicon:after {
|
||||
background: #fff;
|
||||
content: '';
|
||||
display: block;
|
||||
height: 100%;
|
||||
position: absolute;
|
||||
transition: all .2s ease-out;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.menu .menu-icon .navicon:before {
|
||||
top: 8px;
|
||||
}
|
||||
|
||||
.menu .menu-icon .navicon:after {
|
||||
top: -8px;
|
||||
}
|
||||
}
|
||||
/* Removes the hamburger menu */
|
||||
@media (min-width: 800px) {
|
||||
|
||||
.menu-nav {
|
||||
height: 63px;
|
||||
padding: 0px;
|
||||
position: fixed;
|
||||
overflow-y: none;
|
||||
width: 100%;
|
||||
margin: 0px;
|
||||
transition: all 0.2s ease-in-out;
|
||||
}
|
||||
.main {
|
||||
margin-left: 10px;
|
||||
margin-top: 80px;
|
||||
}
|
||||
.menu-nav a {
|
||||
text-align: center;
|
||||
font-size: 22px;
|
||||
padding: 6px;
|
||||
}
|
||||
.menu-nav ul {
|
||||
display: none;
|
||||
}
|
||||
.menu .menu-btn:checked ~ .menu-nav {
|
||||
height: 100%;
|
||||
transition: all 0.2s ease-in-out;
|
||||
}
|
||||
.menu .menu-btn:checked ~ .menu-nav ul {
|
||||
margin-top: 80px;
|
||||
display: block;
|
||||
}
|
||||
/* Used for the icon */
|
||||
.menu .menu-btn:checked ~ .menu-icon .navicon {
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
.menu .menu-btn:checked ~ .menu-icon .navicon:before {
|
||||
transform: rotate(-45deg);
|
||||
}
|
||||
|
||||
.menu .menu-btn:checked ~ .menu-icon .navicon:after {
|
||||
transform: rotate(45deg);
|
||||
}
|
||||
|
||||
.menu .menu-btn:checked ~ .menu-icon:not(.steps) .navicon:before,
|
||||
.menu .menu-btn:checked ~ .menu-icon:not(.steps) .navicon:after {
|
||||
top: 0;
|
||||
}
|
||||
.menu .menu-icon {
|
||||
cursor: pointer;
|
||||
display: inline-block;
|
||||
padding: 30px 30px;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
user-select: none;
|
||||
z-index: 5;
|
||||
}
|
||||
|
||||
.menu .menu-icon .navicon {
|
||||
background: #fff;
|
||||
display: block;
|
||||
height: 3px;
|
||||
position: relative;
|
||||
transition: #fff 0.2s ease-out;
|
||||
width: 30px;
|
||||
}
|
||||
|
||||
.menu .menu-icon .navicon:before,
|
||||
.menu .menu-icon .navicon:after {
|
||||
background: #fff;
|
||||
content: "";
|
||||
display: block;
|
||||
height: 100%;
|
||||
position: absolute;
|
||||
transition: all 0.2s ease-out;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.menu .menu-icon .navicon:before {
|
||||
top: 8px;
|
||||
}
|
||||
|
||||
.menu .menu-icon .navicon:after {
|
||||
top: -8px;
|
||||
}
|
||||
}
|
||||
|
||||
input {
|
||||
background-color: black;
|
||||
color: white;
|
||||
border: 1px solid white;
|
||||
border-radius: 4px;
|
||||
background-color: black;
|
||||
color: white;
|
||||
border: 1px solid white;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
button, input[type='submit'], select {
|
||||
color: rgb(0, 255, 0);
|
||||
background-color: black;
|
||||
border: 2px solid green;
|
||||
border-radius: 6px;
|
||||
button,
|
||||
input[type="submit"],
|
||||
select {
|
||||
color: rgb(0, 255, 0);
|
||||
background-color: black;
|
||||
border: 2px solid green;
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
button:hover, input[type='submit']:hover {
|
||||
background-color: green;
|
||||
color: black;
|
||||
button:hover,
|
||||
input[type="submit"]:hover {
|
||||
background-color: green;
|
||||
color: black;
|
||||
}
|
||||
|
||||
table {
|
||||
border: 0px;
|
||||
border-collapse: collapse;
|
||||
text-align: left;
|
||||
border: 0px;
|
||||
border-collapse: collapse;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
td, th {
|
||||
height: 10px;
|
||||
padding-right: 15px;
|
||||
td,
|
||||
th {
|
||||
height: 10px;
|
||||
padding-right: 15px;
|
||||
}
|
||||
|
||||
th {
|
||||
text-decoration-thickness: 10px;
|
||||
text-decoration-thickness: 10px;
|
||||
}
|
||||
|
||||
input[type="number"] {
|
||||
width: 45px;
|
||||
width: 45px;
|
||||
}
|
||||
|
||||
.grayed:hover {
|
||||
color: gray;
|
||||
background-color: black;
|
||||
color: gray;
|
||||
background-color: black;
|
||||
}
|
||||
|
||||
.grayed {
|
||||
color: gray;
|
||||
border-color: grey;
|
||||
color: gray;
|
||||
border-color: grey;
|
||||
}
|
||||
|
||||
.column2 {
|
||||
float: left;
|
||||
width: 50%;
|
||||
float: left;
|
||||
width: 50%;
|
||||
}
|
||||
|
||||
.red button:hover {
|
||||
background-color: red;
|
||||
border-color: red;
|
||||
color: black;
|
||||
background-color: red;
|
||||
border-color: red;
|
||||
color: black;
|
||||
}
|
||||
|
||||
.red button {
|
||||
color: red;
|
||||
border-color: red;
|
||||
color: red;
|
||||
border-color: red;
|
||||
}
|
||||
|
||||
.popup {
|
||||
display: none;
|
||||
position: fixed;
|
||||
z-index: 1;
|
||||
padding-top: 100px;
|
||||
left: 0;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
overflow: auto;
|
||||
background-color: rgba(0, 0, 0, 0.4);
|
||||
display: none;
|
||||
position: fixed;
|
||||
z-index: 1;
|
||||
padding-top: 100px;
|
||||
left: 0;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
overflow: auto;
|
||||
background-color: rgba(0, 0, 0, 0.4);
|
||||
}
|
||||
|
||||
.popup-content {
|
||||
background-color: black;
|
||||
margin: auto;
|
||||
padding: 20px;
|
||||
border: 1px solid green;
|
||||
margin-left: 220px;
|
||||
margin-right: 40px;
|
||||
background-color: black;
|
||||
margin: auto;
|
||||
padding: 20px;
|
||||
border: 1px solid green;
|
||||
margin-left: 260px;
|
||||
margin-right: 40px;
|
||||
}
|
||||
|
||||
.notification {
|
||||
background-color: black;
|
||||
margin: auto;
|
||||
padding: 20px;
|
||||
border: 3px solid green;
|
||||
z-index: 1;
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
width: fit-content;
|
||||
overflow: auto;
|
||||
position: sticky;
|
||||
margin-left: clamp(150px, 25%, 240px);
|
||||
margin-right: 10px;
|
||||
background-color: black;
|
||||
margin: auto;
|
||||
padding: 20px;
|
||||
border: 3px solid green;
|
||||
z-index: 1;
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
width: fit-content;
|
||||
overflow: auto;
|
||||
position: sticky;
|
||||
margin-left: clamp(150px, 25%, 240px);
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.right {
|
||||
float: right;
|
||||
float: right;
|
||||
}
|
||||
|
||||
.center {
|
||||
display:flex;
|
||||
justify-content:center;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
textarea {
|
||||
background-color: black;
|
||||
color: white;
|
||||
border-radius: 4px;
|
||||
}
|
||||
background-color: black;
|
||||
color: white;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
/* Style changes for the mobile view */
|
||||
@media (max-width: 900px) {
|
||||
.popup-content {
|
||||
margin-left: 40px;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@ include 'functions.php';
|
||||
<link rel="icon" type="image/png" sizes="32x32" href="/favicon/favicon-32x32.png">
|
||||
<link rel="icon" type="image/png" sizes="16x16" href="/favicon/favicon-16x16.png">
|
||||
<link rel="manifest" href="/favicon/site.webmanifest">
|
||||
<link rel="stylesheet" type="text/css" href="/css/website.css?v=1.0.2" />
|
||||
<link rel="stylesheet" type="text/css" href="/css/website.css?v=1.0.3" />
|
||||
<script type="text/javascript" src="/javascript/jquery.js"></script>
|
||||
<script defer="true" type="text/javascript" src="/javascript/jquery-ui.min.js"></script>
|
||||
<link defer="true" rel="stylesheet" href="/css/jquery-ui.min.css">
|
||||
@@ -18,7 +18,7 @@ include 'functions.php';
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Roboto&display=swap" rel="stylesheet">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<?php
|
||||
echo $MATOMO;
|
||||
if ($USERNAME) {
|
||||
@@ -40,11 +40,12 @@ if (isset($DESCRIPTION)) {
|
||||
* @param string $img used as the name of the image
|
||||
* @param string $alt used as the alternate text
|
||||
*/
|
||||
function createImage($img, $alt, $style="width:100%;") {
|
||||
function createImage($img, $alt, $style = "width:100%;")
|
||||
{
|
||||
global $MOBILE;
|
||||
if ($MOBILE && !in_array($img, ["notFound"])) {
|
||||
echo "<img src='/img/$img.mobile.jpg' alt='$alt' style='$style'>";
|
||||
} else {
|
||||
echo "<img src='/img/$img.jpg' alt='$alt' style='$style'>";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@ $MATOMO_SITE_ID = $jsonData["matomoSiteId"];
|
||||
if ($developer) {
|
||||
ini_set('display_errors', 1);
|
||||
ini_set('display_startup_errors', 1);
|
||||
error_reporting(E_ALL);
|
||||
error_reporting(E_ALL);
|
||||
}
|
||||
// Checks if the user is a mobile user
|
||||
if (array_key_exists("HTTP_USER_AGENT", $_SERVER)) {
|
||||
@@ -34,18 +34,18 @@ $MATOMO = "<!-- Matomo -->
|
||||
<!-- End Matomo Code -->";
|
||||
|
||||
require_once("ip.php");
|
||||
function delete_folder($path){ #Used to delete a folder
|
||||
if (is_dir($path) === true){
|
||||
$files = array_diff(scandir($path), array('.', '..'));
|
||||
foreach ($files as $file){
|
||||
delete_folder(realpath($path) . '/' . $file);
|
||||
}
|
||||
return rmdir($path);
|
||||
}
|
||||
else if (is_file($path) === true){
|
||||
return unlink($path);
|
||||
function delete_folder($path)
|
||||
{ #Used to delete a folder
|
||||
if (is_dir($path) === true) {
|
||||
$files = array_diff(scandir($path), array('.', '..'));
|
||||
foreach ($files as $file) {
|
||||
delete_folder(realpath($path) . '/' . $file);
|
||||
}
|
||||
return false;
|
||||
return rmdir($path);
|
||||
} else if (is_file($path) === true) {
|
||||
return unlink($path);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
/**
|
||||
* Is like the array_key_exists function but returns if the key in the array is equal to the compare value.
|
||||
@@ -55,7 +55,8 @@ function delete_folder($path){ #Used to delete a folder
|
||||
* @param string $compare The string it should be compared with
|
||||
* @return bool False if the key does not exist in array or does not equal compare. True otherwise
|
||||
*/
|
||||
function array_key_value(string $key, array $array, string $compare) {
|
||||
function array_key_value(string $key, array $array, string $compare)
|
||||
{
|
||||
if (array_key_exists($key, $array)) {
|
||||
if ($array[$key] == $compare) {
|
||||
return true;
|
||||
@@ -97,7 +98,8 @@ function dbConnect()
|
||||
* Can send any command to the database that is put into this function
|
||||
* prepare is used for prepared statementes
|
||||
*/
|
||||
function dbCommand($command, $prepare=[]) {
|
||||
function dbCommand($command, $prepare = [])
|
||||
{
|
||||
$connection = dbConnect();
|
||||
$length = count($prepare);
|
||||
if ($length == 0) {
|
||||
@@ -120,6 +122,24 @@ function dbCommand($command, $prepare=[]) {
|
||||
$stmt = mysqli_prepare($connection, $command);
|
||||
mysqli_stmt_bind_param($stmt, "sss", $parameter1, $parameter2, $parameter3);
|
||||
mysqli_stmt_execute($stmt);
|
||||
} elseif ($length == 4) {
|
||||
$parameter1 = $prepare[0];
|
||||
$parameter2 = $prepare[1];
|
||||
$parameter3 = $prepare[2];
|
||||
$parameter4 = $prepare[3];
|
||||
$stmt = mysqli_prepare($connection, $command);
|
||||
mysqli_stmt_bind_param($stmt, "ssss", $parameter1, $parameter2, $parameter3, $parameter4);
|
||||
mysqli_stmt_execute($stmt);
|
||||
} elseif ($length == 6) {
|
||||
$parameter1 = $prepare[0];
|
||||
$parameter2 = $prepare[1];
|
||||
$parameter3 = $prepare[2];
|
||||
$parameter4 = $prepare[3];
|
||||
$parameter5 = $prepare[4];
|
||||
$parameter6 = $prepare[5];
|
||||
$stmt = mysqli_prepare($connection, $command);
|
||||
mysqli_stmt_bind_param($stmt, "ssssss", $parameter1, $parameter2, $parameter3, $parameter4, $parameter5, $parameter6);
|
||||
mysqli_stmt_execute($stmt);
|
||||
}
|
||||
mysqli_close($connection);
|
||||
}
|
||||
@@ -165,7 +185,7 @@ function dbRequest($result, $table, $searchCat, $searchCriteria, $Type)
|
||||
* @param string $result the column to search will return all if left empty
|
||||
* @param array $prepare is a list of all the prepared statemends
|
||||
*/
|
||||
function dbRequest2($command, $result="*", $prepare=[])
|
||||
function dbRequest2($command, $result = "*", $prepare = [])
|
||||
{
|
||||
$connection = dbConnect();
|
||||
$length = count($prepare);
|
||||
@@ -177,7 +197,7 @@ function dbRequest2($command, $result="*", $prepare=[])
|
||||
mysqli_stmt_bind_param($stmt, "s", $parameter1);
|
||||
mysqli_stmt_execute($stmt);
|
||||
$response = mysqli_stmt_get_result($stmt);
|
||||
} else if ($length == 2) {
|
||||
} else if ($length == 2) {
|
||||
$stmt = mysqli_prepare($connection, $command);
|
||||
$parameter1 = $prepare[0];
|
||||
$parameter2 = $prepare[1];
|
||||
@@ -314,7 +334,8 @@ foreach ($_COOKIE as $pointer => $value) {
|
||||
$Time = time();
|
||||
dbCommand("DELETE FROM cookies WHERE expire < $Time and expire != 0");
|
||||
$PRIVILEGELIST = ["root", "internet", "editUser", "deleteUser", "deleteElectricity", "deleteLog", "viewLog", "changeCredintials", "deleteElectricity", "deleteError", "restartServer", "updateServer", "serverStatus", "viewBackup", "restore", "mail"]; // A List of all possible privileges
|
||||
function noUser() { # Used to set everything up as if no yser is logged in
|
||||
function noUser()
|
||||
{ # Used to set everything up as if no yser is logged in
|
||||
global $USERNAME, $PRIVILEGE, $PRIVILEGELIST;
|
||||
$USERNAME = "";
|
||||
foreach ($PRIVILEGELIST as $option) {
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
<!DOCTYPE html>
|
||||
|
||||
<html dir="ltr" lang="en">
|
||||
<?php
|
||||
if (! file_exists("config.json")) {
|
||||
echo '<link rel="stylesheet" type="text/css" href="/css/website.css?v=1.0.2" />';
|
||||
<?php
|
||||
if (!file_exists("config.json")) {
|
||||
echo '<link rel="stylesheet" type="text/css" href="/css/website.css?v=1.0.3" />';
|
||||
echo "<h2>Missing configuration please input configuration</h2>";
|
||||
}
|
||||
?>
|
||||
|
||||
<head>
|
||||
<meta name="msvalidate.01" content="52F3C351645EB7619858FA8FCB20C441" />
|
||||
<title>
|
||||
@@ -24,15 +25,16 @@ if (! file_exists("config.json")) {
|
||||
?>
|
||||
<div class='main'>
|
||||
<h1>Welcome to my personal website!</h1>
|
||||
<p>This website is a personal project by Lukas Schaefer to practice web development and the source code for this website is on <a href="https://github.com/Lukasdotcom/website" rel="noopener noreferrer" target="_blank">github</a>.
|
||||
If you find any bugs or want to request a feature feel free to open a github issue and I will look at it. If you find a security vulnerability or issue in my code please contact me directly at
|
||||
<a href="mailto:security@lschaefer.xyz?subject=Website%20Vulnerability&body=Hi%2C%20your%20website%20has%20a%20vulnerability.%20The%20vulnerability%20is%20...%20If%20you%20want%20to%20test%20it%20out%20these%20are%20the%20steps%20to%20reproduce%20it%20...%0AFrom%2C%20NAME">security@lschaefer.xyz</a></p>
|
||||
<p>This website is a personal project by Lukas Schaefer to practice web development and the source code for this website is on <a href="https://github.com/Lukasdotcom/website" rel="noopener noreferrer" target="_blank">github</a>.
|
||||
If you find any bugs or want to request a feature feel free to open a github issue and I will look at it. If you find a security vulnerability or issue in my code please contact me directly at
|
||||
<a href="mailto:security@lschaefer.xyz?subject=Website%20Vulnerability&body=Hi%2C%20your%20website%20has%20a%20vulnerability.%20The%20vulnerability%20is%20...%20If%20you%20want%20to%20test%20it%20out%20these%20are%20the%20steps%20to%20reproduce%20it%20...%0AFrom%2C%20NAME">security@lschaefer.xyz</a>
|
||||
</p>
|
||||
<a href="/floppy.php">
|
||||
<?php
|
||||
<?php
|
||||
createImage("floppy", "Picture of the great bun bun Floppy.");
|
||||
?>
|
||||
</a>
|
||||
</div>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
</html>
|
||||
@@ -19,6 +19,15 @@ td {
|
||||
font-size: 100px;
|
||||
}
|
||||
|
||||
.leaderboard th,
|
||||
.leaderboard td {
|
||||
background-color: black;
|
||||
color: white;
|
||||
font-size: 20px;
|
||||
height: auto;
|
||||
width: auto;
|
||||
}
|
||||
|
||||
.red-td {
|
||||
background-color: rgb(255, 54, 54);
|
||||
}
|
||||
|
||||
@@ -1,320 +1,57 @@
|
||||
const colors = ["red", "green", "blue", "yellow", "brown"];
|
||||
const rows = 4;
|
||||
const cols = 4;
|
||||
const state = {
|
||||
board: [],
|
||||
hand: [],
|
||||
picked_hand_card: null,
|
||||
picked_board_card: null,
|
||||
};
|
||||
const history = [];
|
||||
const arr = [];
|
||||
// Code until the next comment mentioned from this was made with help from Raj Tiller
|
||||
function color_fitting_adjecent_squares(object, nums) {
|
||||
let i = nums[0];
|
||||
let j = nums[1];
|
||||
const ret = [];
|
||||
if (object[i][j]) {
|
||||
const desired_color = object[i][j].color;
|
||||
if (
|
||||
i + 1 < rows &&
|
||||
object[i + 1][j] &&
|
||||
object[i + 1][j].color == desired_color
|
||||
) {
|
||||
ret.push([i + 1, j]);
|
||||
}
|
||||
if (i > 0 && object[i - 1][j] && object[i - 1][j].color == desired_color) {
|
||||
ret.push([i - 1, j]);
|
||||
}
|
||||
if (
|
||||
j + 1 < cols &&
|
||||
object[i][j + 1] &&
|
||||
object[i][j + 1].color == desired_color
|
||||
) {
|
||||
ret.push([i, j + 1]);
|
||||
}
|
||||
if (j > 0 && object[i][j - 1] && object[i][j - 1].color == desired_color) {
|
||||
ret.push([i, j - 1]);
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
function arr_to_num(arr) {
|
||||
return arr[0] * 4 + arr[1];
|
||||
}
|
||||
|
||||
function number_fitting_adjecent_squares(object, nums) {
|
||||
let i = nums[0];
|
||||
let j = nums[1];
|
||||
const desired_value = object[i][j].number + 1;
|
||||
let ret = [];
|
||||
if (
|
||||
i + 1 < rows &&
|
||||
object[i + 1][j] &&
|
||||
object[i + 1][j].number == desired_value
|
||||
) {
|
||||
ret.push([i + 1, j]);
|
||||
}
|
||||
if (i > 0 && object[i - 1][j] && object[i - 1][j].number == desired_value) {
|
||||
ret.push([i - 1, j]);
|
||||
}
|
||||
if (
|
||||
j + 1 < cols &&
|
||||
object[i][j + 1] &&
|
||||
object[i][j + 1].number == desired_value
|
||||
) {
|
||||
ret.push([i, j + 1]);
|
||||
}
|
||||
if (j > 0 && object[i][j - 1] && object[i][j - 1].number == desired_value) {
|
||||
ret.push([i, j - 1]);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
function clump_score(object) {
|
||||
const clumps = [];
|
||||
const inxs_done = [];
|
||||
for (let i = 0; i < rows; i++) {
|
||||
for (let j = 0; j < cols; j++) {
|
||||
if (object[i][j]) {
|
||||
curr_clump = [];
|
||||
if (inxs_done.indexOf(arr_to_num([i, j])) == -1) {
|
||||
curr_clump.push(arr_to_num([i, j]));
|
||||
inxs_done.push(arr_to_num([i, j]));
|
||||
let clumps_to_try = [[i, j]];
|
||||
while (clumps_to_try.length != 0) {
|
||||
let pot_new_squares = [];
|
||||
for (square of clumps_to_try) {
|
||||
to_add = color_fitting_adjecent_squares(object, square);
|
||||
if (to_add.length != 0) {
|
||||
pot_new_squares = pot_new_squares.concat(to_add);
|
||||
}
|
||||
}
|
||||
clumps_to_try = [];
|
||||
for (pot_square of pot_new_squares) {
|
||||
if (
|
||||
inxs_done.indexOf(arr_to_num(pot_square)) == -1 &&
|
||||
curr_clump.indexOf(arr_to_num(pot_square)) == -1
|
||||
) {
|
||||
curr_clump.push(arr_to_num(pot_square));
|
||||
inxs_done.push(arr_to_num(pot_square));
|
||||
clumps_to_try.push(pot_square);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (curr_clump.length != 0) {
|
||||
clumps.push(curr_clump);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
let ret = 0;
|
||||
for (clump of clumps) {
|
||||
ret += clump.length * clump.length;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
function single_run_score(object) {
|
||||
let longest_run_len = 0;
|
||||
let lowest_value = 0;
|
||||
let highest_value;
|
||||
for (let i = 0; i < rows; i++) {
|
||||
for (let j = 0; j < cols; j++) {
|
||||
if (object[i][j]) {
|
||||
let curr_squares = [];
|
||||
curr_squares.push([i, j]);
|
||||
let pot_long_run_length = 0;
|
||||
let pot_low_val = object[i][j].number;
|
||||
let pot_high_val = object[i][j].number - 1;
|
||||
while (curr_squares.length != 0) {
|
||||
let to_add = [];
|
||||
for (const nums of curr_squares) {
|
||||
if (nums.length != 0) {
|
||||
const new_squares = number_fitting_adjecent_squares(object, nums);
|
||||
if (new_squares.length > 0) {
|
||||
to_add = to_add.concat(
|
||||
number_fitting_adjecent_squares(object, nums)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
curr_squares = [...to_add];
|
||||
pot_high_val++;
|
||||
pot_long_run_length++;
|
||||
}
|
||||
if (
|
||||
pot_long_run_length > longest_run_len ||
|
||||
(pot_long_run_length == longest_run_len && pot_low_val < lowest_value)
|
||||
) {
|
||||
lowest_value = pot_low_val;
|
||||
highest_value = pot_high_val;
|
||||
longest_run_len = pot_long_run_length;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (highest_value === undefined) {
|
||||
return 0;
|
||||
}
|
||||
return (9 - lowest_value) * (highest_value - lowest_value + 1);
|
||||
}
|
||||
function increasing_row_across(object) {
|
||||
let ret = 0;
|
||||
for (let i = 0; i < rows; i++) {
|
||||
let curr_num = object[i][0] ? object[i][0].number : 0;
|
||||
for (let j = 1; j < cols; j++) {
|
||||
if (object[i][j] === null) {
|
||||
if (j == cols - 1) {
|
||||
ret += 10;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (object[i][j].number <= curr_num) {
|
||||
break;
|
||||
}
|
||||
if (j == cols - 1 && curr_num < object[i][j].number) {
|
||||
ret += 10;
|
||||
}
|
||||
curr_num = object[i][j].number;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
function tot_sum(object) {
|
||||
let ret = 0;
|
||||
for (let i = 0; i < rows; i++) {
|
||||
for (let j = 0; j < cols; j++) {
|
||||
num = object[i][j] ? object[i][j].number : 0;
|
||||
ret += num;
|
||||
}
|
||||
}
|
||||
return Math.floor(ret / 2);
|
||||
}
|
||||
function all_numbers(object) {
|
||||
const nums = [];
|
||||
for (let i = 0; i < rows; i++) {
|
||||
for (let j = 0; j < cols; j++) {
|
||||
if (object[i][j]) {
|
||||
let curr_num = object[i][j].number;
|
||||
if (nums.indexOf(curr_num) == -1) {
|
||||
nums.push(curr_num);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return nums.length * nums.length;
|
||||
}
|
||||
function calculate_score(object) {
|
||||
//object is an array of four arrays each of which is an array of four objects
|
||||
const clump_result = clump_score(object);
|
||||
// console.log("clump_result: ", clump_result);
|
||||
const single_run_result = single_run_score(object);
|
||||
// console.log("single_run_result: ", single_run_result);
|
||||
const increasing_row_across_result = increasing_row_across(object);
|
||||
// console.log("increasing_row_across_result: ", increasing_row_across_result);
|
||||
const tot_sum_result = tot_sum(object);
|
||||
// console.log("tot_sum_result: ", tot_sum_result);
|
||||
const all_numbers_result = all_numbers(object);
|
||||
// console.log("all_numbers_result: ", all_numbers_result);
|
||||
return [
|
||||
clump_result,
|
||||
single_run_result,
|
||||
increasing_row_across_result,
|
||||
tot_sum_result,
|
||||
all_numbers_result,
|
||||
];
|
||||
}
|
||||
// End of code made with help from Raj Tiller
|
||||
function render(state) {
|
||||
function render_game(state) {
|
||||
if (state.picked_board_card !== null && state.picked_hand_card !== null) {
|
||||
$("#play").button("enable");
|
||||
} else {
|
||||
$("#play").button("disable");
|
||||
}
|
||||
let board = state.board;
|
||||
const score = calculate_score(board);
|
||||
let new_score = score;
|
||||
if (state.picked_board_card !== null) {
|
||||
const new_temp_board = state.board.map((row_data, row) => {
|
||||
return row_data.map((a, col) => {
|
||||
if (
|
||||
row === state.picked_board_card[0] &&
|
||||
col === state.picked_board_card[1]
|
||||
) {
|
||||
return state.hand[state.picked_hand_card];
|
||||
const new_score = render(state);
|
||||
console.log(new_score);
|
||||
$("#winGamePoints").text(new_score[new_score.length - 1]);
|
||||
const game_finished =
|
||||
state.board.filter((e) => e.filter((e) => !e).length !== 0).length === 0;
|
||||
if (game_finished) {
|
||||
_paq.push(["trackEvent", "klumpy", "game_finished", new_score.join(",")]);
|
||||
fetch("/api/klumpy.php", {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/x-www-form-urlencoded",
|
||||
},
|
||||
body: `history=${JSON.stringify(history)}&board=${JSON.stringify(
|
||||
state.board
|
||||
)}&points=${new_score[new_score.length - 1]}&key=${getCookie(
|
||||
"user"
|
||||
)}&type=main`,
|
||||
}).then(async (e) => {
|
||||
if (e.status === 200) {
|
||||
const json_data = await e.json();
|
||||
$("#winGamePlace").text(json_data.position);
|
||||
$("#winGamePoints").text(json_data.points);
|
||||
if (json_data.error) {
|
||||
JQerror(json_data.message);
|
||||
} else {
|
||||
return a;
|
||||
$("#share").attr(
|
||||
"href",
|
||||
`/klumpy/leaderboard.php#${json_data.gameID}`
|
||||
);
|
||||
$("#share").show();
|
||||
}
|
||||
});
|
||||
});
|
||||
new_score = calculate_score(new_temp_board);
|
||||
}
|
||||
score.push(score.reduce((a, b) => a + b, 0));
|
||||
new_score.push(new_score.reduce((a, b) => a + b, 0));
|
||||
const score_parts = [
|
||||
"#clump_score",
|
||||
"#single_run_score",
|
||||
"#increasing_row_across_score",
|
||||
"#tot_sum_scores",
|
||||
"#all_number_scores",
|
||||
"#score",
|
||||
];
|
||||
score_parts.forEach((part, i) => {
|
||||
let text = score[i];
|
||||
if (new_score[i] > text) {
|
||||
text += ` <span style="color: green">+${new_score[i] - text}</span>`;
|
||||
} else if (new_score[i] < text) {
|
||||
text += ` <span style="color: red">-${text - new_score[i]}</span>`;
|
||||
}
|
||||
$(part).html(text);
|
||||
});
|
||||
let html = board
|
||||
.map((row, rowNum) => {
|
||||
return (
|
||||
"<tr>" +
|
||||
row
|
||||
.map((cell, rowCol) => {
|
||||
let highlight = "";
|
||||
let temp_card_text = "";
|
||||
let temp_card_class = "";
|
||||
if (
|
||||
state.picked_board_card &&
|
||||
rowNum === state.picked_board_card[0] &&
|
||||
rowCol === state.picked_board_card[1]
|
||||
) {
|
||||
highlight = "highlight-td";
|
||||
if (state.picked_hand_card !== null) {
|
||||
temp_card_text = state.hand[state.picked_hand_card].number;
|
||||
temp_card_class =
|
||||
state.hand[state.picked_hand_card].color + "-td";
|
||||
}
|
||||
}
|
||||
return cell
|
||||
? `<td class="${cell.color}-td">${cell.number}</td>`
|
||||
: `<td onClick="cellClicked(${rowNum}, ${rowCol})" class="${highlight} ${temp_card_class}">${temp_card_text}</td>`;
|
||||
})
|
||||
.join("") +
|
||||
"</tr>"
|
||||
);
|
||||
})
|
||||
.join("");
|
||||
$("#game").html(html);
|
||||
let hand = state.hand;
|
||||
html =
|
||||
"<tr>" +
|
||||
hand.map((cell, index) => {
|
||||
let highlight = "";
|
||||
if (index == state.picked_hand_card) {
|
||||
highlight = "highlight-td";
|
||||
} else {
|
||||
console.error(
|
||||
"Failed to save game with unknown error: " + (await e.text())
|
||||
);
|
||||
JQerror("An unknown error occured");
|
||||
}
|
||||
return cell
|
||||
? `<td onClick="cellClicked(${index})" class="${cell.color}-td ${highlight}">${cell.number}</td>`
|
||||
: `<td></td>`;
|
||||
}) +
|
||||
"</tr>";
|
||||
$("#hand").html(html);
|
||||
});
|
||||
$("#winGame").show();
|
||||
}
|
||||
}
|
||||
// If one element that hand card is picked otherwise that board card is picked
|
||||
function cellClicked(i, j) {
|
||||
@@ -323,7 +60,7 @@ function cellClicked(i, j) {
|
||||
} else {
|
||||
state.picked_hand_card = i;
|
||||
}
|
||||
render(state);
|
||||
render_game(state);
|
||||
}
|
||||
function giveHand() {
|
||||
state.hand = [0, 0, 0].map(() => {
|
||||
@@ -338,21 +75,30 @@ for (let i = 0; i < rows; i++) {
|
||||
const add = [];
|
||||
for (let j = 0; j < cols; j++) {
|
||||
add.push(null);
|
||||
// add.push({
|
||||
// number: Math.floor(Math.random() * 8) + 1,
|
||||
// color: colors[Math.floor(Math.random() * colors.length)],
|
||||
// });
|
||||
}
|
||||
arr.push(add);
|
||||
}
|
||||
arr[0][0] = null;
|
||||
state.board = arr;
|
||||
giveHand();
|
||||
$("document").ready(() => {
|
||||
$(".help").tooltip();
|
||||
$("#play").button();
|
||||
$("#play").click(() => {
|
||||
history.push({
|
||||
hand: state.hand,
|
||||
board: state.picked_board_card,
|
||||
});
|
||||
state.board[state.picked_board_card[0]][state.picked_board_card[1]] =
|
||||
state.hand[state.picked_hand_card];
|
||||
state.picked_hand_card = null;
|
||||
state.picked_board_card = null;
|
||||
giveHand();
|
||||
render(state);
|
||||
render_game(state);
|
||||
});
|
||||
render(state);
|
||||
render_game(state);
|
||||
});
|
||||
|
||||
@@ -3,65 +3,85 @@
|
||||
<html dir="ltr" lang="en">
|
||||
|
||||
<head>
|
||||
<title>
|
||||
Klumpy
|
||||
</title>
|
||||
<?php
|
||||
$DESCRIPTION = "A block based game where you try to get the highest score you can while choosing cards from a deck.";
|
||||
require_once '../include/all.php';
|
||||
?>
|
||||
<link rel="stylesheet" type="text/css" href="index.css" />
|
||||
<title>
|
||||
Klumpy
|
||||
</title>
|
||||
<?php
|
||||
$DESCRIPTION = "A block based game where you try to get the highest score you can while choosing cards from a deck.";
|
||||
require_once '../include/all.php';
|
||||
?>
|
||||
<link rel="stylesheet" type="text/css" href="index.css?v=1.1.0" />
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<?php
|
||||
include '../include/menu.php';
|
||||
echo "<div class='main'>";
|
||||
?>
|
||||
<h1>Klumpy</h1>
|
||||
<h3>Game Field</h3>
|
||||
<table id="game">
|
||||
<tr>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
</tr><tr>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
</tr><tr>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
</table>
|
||||
<p>Color Clump Score<span title="All clumps of colors are added together by squaring the number of neighboring colors." style="cursor: help" class="help ui-icon ui-icon-help"></span>: <span id="clump_score"></span></p>
|
||||
<p>Single Run Score<span title="The number of points based on the longest run of consecutive numbers in any orthogonal direction. Uses the following formula (9 - lowest_value) * (highest_value - lowest_value + 1)." style="cursor: help" class="help ui-icon ui-icon-help"></span>: <span id="single_run_score"></span></p>
|
||||
<p>Increasing Row Score<span title="You get 10 points for every row where the numbers are strictly increasing." style="cursor: help" class="help ui-icon ui-icon-help"></span>: <span id="increasing_row_across_score"></span></p>
|
||||
<p>Total Sum Score<span title="This is just a sum of all the numbers divided by 2." style="cursor: help" class="help ui-icon ui-icon-help"></span>: <span id="tot_sum_scores"></span></p>
|
||||
<p>Unique Number Bonus<span title="A bonus of 50 points if you have all the numbers on the board" style="cursor: help" class="help ui-icon ui-icon-help"></span>: <span id="all_number_scores"></span></p>
|
||||
<p>Score: <span id="score"></span></p>
|
||||
<h3>Hand</h3>
|
||||
<table id="hand">
|
||||
<tr>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
</table>
|
||||
<br>
|
||||
<button style="font-size: 50px" id="play">Play Card</button>
|
||||
<?php
|
||||
include '../include/menu.php';
|
||||
echo "<div class='main'>";
|
||||
?>
|
||||
<h1>Klumpy</h1>
|
||||
<?php
|
||||
echo "<p>$DESCRIPTION</p>";
|
||||
if (!$USERNAME) {
|
||||
echo "<h2>You must be logged in to use the leaderboard and share your games.</h2>";
|
||||
}
|
||||
?>
|
||||
<h3>Game Field</h3>
|
||||
<table id="game">
|
||||
<tr>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
</table>
|
||||
<p>Color Clump Score<span title="All clumps of colors are added together by squaring the number of neighboring colors." style="cursor: help" class="help ui-icon ui-icon-info"></span>: <span id="clump_score"></span></p>
|
||||
<p>Single Run Score<span title="The number of points based on the longest run of consecutive numbers in any orthogonal direction. Uses the following formula (9 - lowest_value) * (highest_value - lowest_value + 1)." style="cursor: help" class="help ui-icon ui-icon-info"></span>: <span id="single_run_score"></span></p>
|
||||
<p>Increasing Row Score<span title="You get 10 points for every row where the numbers are strictly increasing." style="cursor: help" class="help ui-icon ui-icon-info"></span>: <span id="increasing_row_across_score"></span></p>
|
||||
<p>Total Sum Score<span title="This is just a sum of all the numbers divided by 2." style="cursor: help" class="help ui-icon ui-icon-info"></span>: <span id="tot_sum_scores"></span></p>
|
||||
<p>Unique Number Bonus<span title="A bonus of 50 points if you have all the numbers on the board" style="cursor: help" class="help ui-icon ui-icon-info"></span>: <span id="all_number_scores"></span></p>
|
||||
<p>Score: <span id="score"></span></p>
|
||||
<h3>Hand</h3>
|
||||
<table id="hand">
|
||||
<tr>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
</table>
|
||||
<br>
|
||||
<button style="font-size: 50px" id="play">Play Card</button>
|
||||
<div id='winGame' class='popup'>
|
||||
<div class='popup-content'>
|
||||
<h1>You have finished!</h1>
|
||||
<p>You are in <span id='winGamePlace'></span> place.</p>
|
||||
<p>You have <span id='winGamePoints'></span> points.</p>
|
||||
<a href='/klumpy'><button>Restart</button></a>
|
||||
<a href="/klumpy/leaderboard"><button>View leaderboard</button></a>
|
||||
<a id="share" href="" style="display: none"><button>View Game and Share</button></a>
|
||||
</div>
|
||||
<script src="index.js"></script>
|
||||
</div>
|
||||
</div>
|
||||
<script src="render.js?v=1.0.0"></script>
|
||||
<script src="score.js?v=1.0.0"></script>
|
||||
<script src="index.js?v=1.1.0"></script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
97
html/klumpy/leaderboard.js
Normal file
97
html/klumpy/leaderboard.js
Normal file
@@ -0,0 +1,97 @@
|
||||
const historicalState = {
|
||||
history: [],
|
||||
board: [],
|
||||
hash: "",
|
||||
};
|
||||
const leaderboard = {
|
||||
data: [],
|
||||
unique: [],
|
||||
};
|
||||
async function render_historical() {
|
||||
await new Promise((res) => setTimeout(res, 2));
|
||||
const hash = window.location.hash.replace("#", "");
|
||||
if (hash === "") {
|
||||
$("#historicalGame").hide();
|
||||
return;
|
||||
}
|
||||
$("#historicalGame").show();
|
||||
const game_data = await fetch(`/api/klumpy.php?gameID=${hash}`).then((e) => {
|
||||
if (e.status === 200) {
|
||||
return e.json();
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
});
|
||||
if (game_data === null) {
|
||||
$("#historicalGame").hide();
|
||||
return;
|
||||
}
|
||||
historicalState.board = game_data.board;
|
||||
historicalState.history = JSON.parse(game_data.history);
|
||||
historicalState.hash = hash;
|
||||
$("#username").text(game_data.username);
|
||||
|
||||
$("#slider").slider({
|
||||
max: historicalState.history.length,
|
||||
change: update_view,
|
||||
value: historicalState.history.length,
|
||||
});
|
||||
update_view();
|
||||
}
|
||||
function update_view() {
|
||||
if (window.location.hash.replace("#", "") !== historicalState.hash) {
|
||||
render_historical();
|
||||
return;
|
||||
}
|
||||
const value = $("#slider").slider("value");
|
||||
const state = {
|
||||
board: JSON.parse(historicalState.board),
|
||||
hand: historicalState.history[value]
|
||||
? historicalState.history[value].hand
|
||||
: [],
|
||||
picked_hand_card: null,
|
||||
picked_board_card: null,
|
||||
};
|
||||
for (i = historicalState.history.length - 1; i >= value; i--) {
|
||||
state.board[historicalState.history[i].board[0]][
|
||||
historicalState.history[i].board[1]
|
||||
] = null;
|
||||
}
|
||||
render(state);
|
||||
}
|
||||
function close_historicalGame() {
|
||||
window.location.hash = "";
|
||||
render_historical();
|
||||
}
|
||||
async function loadMore() {
|
||||
const showAll = $("#show_all").is(":checked");
|
||||
const data = await fetch(
|
||||
`/api/klumpy.php?search=${leaderboard.data.length + 10}`
|
||||
).then((e) => e.json());
|
||||
leaderboard.data = data;
|
||||
for (const e of data) {
|
||||
if (
|
||||
leaderboard.unique.filter((e) => e.username === e.username).length === 0
|
||||
) {
|
||||
leaderboard.unique.push(e);
|
||||
}
|
||||
}
|
||||
let html =
|
||||
`<table class="leaderboard" id="leaderboard"><th>Position</th><th>Name</th><th>Score</th><th>View</th>` +
|
||||
(showAll ? leaderboard.data : leaderboard.unique)
|
||||
.map((e, idx) => {
|
||||
return `<tr><td>${idx + 1}</td><td>${e.username}</td><td>${
|
||||
e.score
|
||||
}</td><td><a onclick="render_historical()" href="#${
|
||||
e.gameID
|
||||
}"><button>View</button></a></td></tr>`;
|
||||
})
|
||||
.join("") +
|
||||
`</table>`;
|
||||
$("#leaderboard").html(html);
|
||||
}
|
||||
$("documnet").ready(function () {
|
||||
$(".help").tooltip();
|
||||
render_historical();
|
||||
loadMore();
|
||||
});
|
||||
86
html/klumpy/leaderboard.php
Normal file
86
html/klumpy/leaderboard.php
Normal file
@@ -0,0 +1,86 @@
|
||||
<!DOCTYPE html>
|
||||
|
||||
<html dir="ltr" lang="en">
|
||||
|
||||
<head>
|
||||
<title>
|
||||
Klumpy Leaderboard
|
||||
</title>
|
||||
<?php
|
||||
$DESCRIPTION = "A Leaderboard for Klumpy where you can see all the games and view them.";
|
||||
require_once '../include/all.php';
|
||||
?>
|
||||
<link rel="stylesheet" type="text/css" href="index.css?v=1.1.0" />
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<?php
|
||||
include '../include/menu.php';
|
||||
echo "<div class='main''>";
|
||||
?>
|
||||
<h1>Klumpy Leaderboard</h1>
|
||||
<input onclick="loadMore()" type='checkbox' id='show_all' name='show_all'>
|
||||
<label for='show_all'>Check this to show all games</label><br>
|
||||
<table class="leaderboard" id="leaderboard">
|
||||
<th>Position</th>
|
||||
<th>Name</th>
|
||||
<th>Score</th>
|
||||
<th>View</th>
|
||||
</table>
|
||||
<button onclick="loadMore()">Load More</button>
|
||||
<div id='historicalGame' class='popup'>
|
||||
<div class='popup-content'>
|
||||
<button onclick="close_historicalGame()">Close</button>
|
||||
<h1>Game from <span id='username'></span></h1>
|
||||
<p>Slide this to go through the game</p>
|
||||
<div id="slider"></div>
|
||||
<h3>Game Field</h3>
|
||||
<table id="game">
|
||||
<tr>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
</table>
|
||||
<p>Color Clump Score<span title="All clumps of colors are added together by squaring the number of neighboring colors." style="cursor: help" class="help ui-icon ui-icon-info"></span>: <span id="clump_score"></span></p>
|
||||
<p>Single Run Score<span title="The number of points based on the longest run of consecutive numbers in any orthogonal direction. Uses the following formula (9 - lowest_value) * (highest_value - lowest_value + 1)." style="cursor: help" class="help ui-icon ui-icon-info"></span>: <span id="single_run_score"></span></p>
|
||||
<p>Increasing Row Score<span title="You get 10 points for every row where the numbers are strictly increasing." style="cursor: help" class="help ui-icon ui-icon-info"></span>: <span id="increasing_row_across_score"></span></p>
|
||||
<p>Total Sum Score<span title="This is just a sum of all the numbers divided by 2." style="cursor: help" class="help ui-icon ui-icon-info"></span>: <span id="tot_sum_scores"></span></p>
|
||||
<p>Unique Number Bonus<span title="A bonus of 50 points if you have all the numbers on the board" style="cursor: help" class="help ui-icon ui-icon-info"></span>: <span id="all_number_scores"></span></p>
|
||||
<p>Score: <span id="score"></span></p>
|
||||
<h3>Hand</h3>
|
||||
<table id="hand">
|
||||
<tr>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<script src="render.js?v=1.0.0"></script>
|
||||
<script src="score.js?v=1.0.0"></script>
|
||||
<script src="leaderboard.js?v=1.0.0"></script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
86
html/klumpy/render.js
Normal file
86
html/klumpy/render.js
Normal file
@@ -0,0 +1,86 @@
|
||||
// Will render the UI based on a state and returns the score
|
||||
function render(state) {
|
||||
let board = state.board;
|
||||
const score = calculate_score(board);
|
||||
let new_score = score;
|
||||
if (state.picked_board_card !== null) {
|
||||
const new_temp_board = state.board.map((row_data, row) => {
|
||||
return row_data.map((a, col) => {
|
||||
if (
|
||||
row === state.picked_board_card[0] &&
|
||||
col === state.picked_board_card[1]
|
||||
) {
|
||||
return state.hand[state.picked_hand_card];
|
||||
} else {
|
||||
return a;
|
||||
}
|
||||
});
|
||||
});
|
||||
new_score = calculate_score(new_temp_board);
|
||||
new_score.push(new_score.reduce((a, b) => a + b, 0));
|
||||
}
|
||||
score.push(score.reduce((a, b) => a + b, 0));
|
||||
const score_parts = [
|
||||
"#clump_score",
|
||||
"#single_run_score",
|
||||
"#increasing_row_across_score",
|
||||
"#tot_sum_scores",
|
||||
"#all_number_scores",
|
||||
"#score",
|
||||
];
|
||||
score_parts.forEach((part, i) => {
|
||||
let text = score[i];
|
||||
if (new_score[i] > text) {
|
||||
text += ` <span style="color: green">+${new_score[i] - text}</span>`;
|
||||
} else if (new_score[i] < text) {
|
||||
text += ` <span style="color: red">-${text - new_score[i]}</span>`;
|
||||
}
|
||||
$(part).html(text);
|
||||
});
|
||||
let html = board
|
||||
.map((row, rowNum) => {
|
||||
return (
|
||||
"<tr>" +
|
||||
row
|
||||
.map((cell, rowCol) => {
|
||||
let highlight = "";
|
||||
let temp_card_text = "";
|
||||
let temp_card_class = "";
|
||||
if (
|
||||
state.picked_board_card &&
|
||||
rowNum === state.picked_board_card[0] &&
|
||||
rowCol === state.picked_board_card[1]
|
||||
) {
|
||||
highlight = "highlight-td";
|
||||
if (state.picked_hand_card !== null) {
|
||||
temp_card_text = state.hand[state.picked_hand_card].number;
|
||||
temp_card_class =
|
||||
state.hand[state.picked_hand_card].color + "-td";
|
||||
}
|
||||
}
|
||||
return cell
|
||||
? `<td class="${cell.color}-td">${cell.number}</td>`
|
||||
: `<td onClick="cellClicked(${rowNum}, ${rowCol})" class="${highlight} ${temp_card_class}">${temp_card_text}</td>`;
|
||||
})
|
||||
.join("") +
|
||||
"</tr>"
|
||||
);
|
||||
})
|
||||
.join("");
|
||||
$("#game").html(html);
|
||||
let hand = state.hand;
|
||||
html =
|
||||
"<tr>" +
|
||||
hand.map((cell, index) => {
|
||||
let highlight = "";
|
||||
if (index == state.picked_hand_card) {
|
||||
highlight = "highlight-td";
|
||||
}
|
||||
return cell
|
||||
? `<td onClick="cellClicked(${index})" class="${cell.color}-td ${highlight}">${cell.number}</td>`
|
||||
: `<td></td>`;
|
||||
}) +
|
||||
"</tr>";
|
||||
$("#hand").html(html);
|
||||
return score;
|
||||
}
|
||||
229
html/klumpy/score.js
Executable file
229
html/klumpy/score.js
Executable file
@@ -0,0 +1,229 @@
|
||||
const colors = ["red", "green", "blue", "yellow", "brown"];
|
||||
const rows = 4;
|
||||
const cols = 4;
|
||||
// Code until the next comment mentioned from this was made with help from Raj Tiller
|
||||
function color_fitting_adjecent_squares(object, nums) {
|
||||
let i = nums[0];
|
||||
let j = nums[1];
|
||||
const ret = [];
|
||||
if (object[i][j]) {
|
||||
const desired_color = object[i][j].color;
|
||||
if (
|
||||
i + 1 < rows &&
|
||||
object[i + 1][j] &&
|
||||
object[i + 1][j].color == desired_color
|
||||
) {
|
||||
ret.push([i + 1, j]);
|
||||
}
|
||||
if (i > 0 && object[i - 1][j] && object[i - 1][j].color == desired_color) {
|
||||
ret.push([i - 1, j]);
|
||||
}
|
||||
if (
|
||||
j + 1 < cols &&
|
||||
object[i][j + 1] &&
|
||||
object[i][j + 1].color == desired_color
|
||||
) {
|
||||
ret.push([i, j + 1]);
|
||||
}
|
||||
if (j > 0 && object[i][j - 1] && object[i][j - 1].color == desired_color) {
|
||||
ret.push([i, j - 1]);
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
function arr_to_num(arr) {
|
||||
return arr[0] * 4 + arr[1];
|
||||
}
|
||||
|
||||
function number_fitting_adjecent_squares(object, nums) {
|
||||
let i = nums[0];
|
||||
let j = nums[1];
|
||||
const desired_value = object[i][j].number + 1;
|
||||
let ret = [];
|
||||
if (
|
||||
i + 1 < rows &&
|
||||
object[i + 1][j] &&
|
||||
object[i + 1][j].number == desired_value
|
||||
) {
|
||||
ret.push([i + 1, j]);
|
||||
}
|
||||
if (i > 0 && object[i - 1][j] && object[i - 1][j].number == desired_value) {
|
||||
ret.push([i - 1, j]);
|
||||
}
|
||||
if (
|
||||
j + 1 < cols &&
|
||||
object[i][j + 1] &&
|
||||
object[i][j + 1].number == desired_value
|
||||
) {
|
||||
ret.push([i, j + 1]);
|
||||
}
|
||||
if (j > 0 && object[i][j - 1] && object[i][j - 1].number == desired_value) {
|
||||
ret.push([i, j - 1]);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
function clump_score(object) {
|
||||
const clumps = [];
|
||||
const inxs_done = [];
|
||||
for (let i = 0; i < rows; i++) {
|
||||
for (let j = 0; j < cols; j++) {
|
||||
if (object[i][j]) {
|
||||
curr_clump = [];
|
||||
if (inxs_done.indexOf(arr_to_num([i, j])) == -1) {
|
||||
curr_clump.push(arr_to_num([i, j]));
|
||||
inxs_done.push(arr_to_num([i, j]));
|
||||
let clumps_to_try = [[i, j]];
|
||||
while (clumps_to_try.length != 0) {
|
||||
let pot_new_squares = [];
|
||||
for (square of clumps_to_try) {
|
||||
to_add = color_fitting_adjecent_squares(object, square);
|
||||
if (to_add.length != 0) {
|
||||
pot_new_squares = pot_new_squares.concat(to_add);
|
||||
}
|
||||
}
|
||||
clumps_to_try = [];
|
||||
for (pot_square of pot_new_squares) {
|
||||
if (
|
||||
inxs_done.indexOf(arr_to_num(pot_square)) == -1 &&
|
||||
curr_clump.indexOf(arr_to_num(pot_square)) == -1
|
||||
) {
|
||||
curr_clump.push(arr_to_num(pot_square));
|
||||
inxs_done.push(arr_to_num(pot_square));
|
||||
clumps_to_try.push(pot_square);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (curr_clump.length != 0) {
|
||||
clumps.push(curr_clump);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
let ret = 0;
|
||||
for (clump of clumps) {
|
||||
ret += clump.length * clump.length;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
function single_run_score(object) {
|
||||
let longest_run_len = 0;
|
||||
let lowest_value = 0;
|
||||
let highest_value;
|
||||
for (let i = 0; i < rows; i++) {
|
||||
for (let j = 0; j < cols; j++) {
|
||||
if (object[i][j]) {
|
||||
let curr_squares = [];
|
||||
curr_squares.push([i, j]);
|
||||
let pot_long_run_length = 0;
|
||||
let pot_low_val = object[i][j].number;
|
||||
let pot_high_val = object[i][j].number - 1;
|
||||
while (curr_squares.length != 0) {
|
||||
let to_add = [];
|
||||
for (const nums of curr_squares) {
|
||||
if (nums.length != 0) {
|
||||
const new_squares = number_fitting_adjecent_squares(object, nums);
|
||||
if (new_squares.length > 0) {
|
||||
to_add = to_add.concat(
|
||||
number_fitting_adjecent_squares(object, nums)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
curr_squares = [...to_add];
|
||||
pot_high_val++;
|
||||
pot_long_run_length++;
|
||||
}
|
||||
if (
|
||||
pot_long_run_length > longest_run_len ||
|
||||
(pot_long_run_length == longest_run_len && pot_low_val < lowest_value)
|
||||
) {
|
||||
lowest_value = pot_low_val;
|
||||
highest_value = pot_high_val;
|
||||
longest_run_len = pot_long_run_length;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (highest_value === undefined) {
|
||||
return 0;
|
||||
}
|
||||
return (9 - lowest_value) * (highest_value - lowest_value + 1);
|
||||
}
|
||||
function increasing_row_across(object) {
|
||||
let ret = 0;
|
||||
let add = 0;
|
||||
for (let i = 0; i < rows; i++) {
|
||||
let curr_num = object[i][0] ? object[i][0].number : 0;
|
||||
for (let j = 1; j < cols; j++) {
|
||||
if (object[i][j] === null) {
|
||||
if (j == cols - 1) {
|
||||
ret += add;
|
||||
add += 5;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (object[i][j].number <= curr_num) {
|
||||
break;
|
||||
}
|
||||
if (j == cols - 1 && curr_num < object[i][j].number) {
|
||||
ret += add;
|
||||
add += 5;
|
||||
}
|
||||
curr_num = object[i][j].number;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
function tot_sum(object) {
|
||||
let ret = 0;
|
||||
for (let i = 0; i < rows; i++) {
|
||||
for (let j = 0; j < cols; j++) {
|
||||
num = object[i][j] ? object[i][j].number : 0;
|
||||
ret += num;
|
||||
}
|
||||
}
|
||||
return Math.floor(ret / 2);
|
||||
}
|
||||
function all_numbers(object) {
|
||||
const nums = [];
|
||||
for (let i = 0; i < rows; i++) {
|
||||
for (let j = 0; j < cols; j++) {
|
||||
if (object[i][j]) {
|
||||
let curr_num = object[i][j].number;
|
||||
if (nums.indexOf(curr_num) == -1) {
|
||||
nums.push(curr_num);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return nums.length * nums.length;
|
||||
}
|
||||
function calculate_score(object) {
|
||||
//object is an array of four arrays each of which is an array of four objects
|
||||
const clump_result = clump_score(object);
|
||||
// console.log("clump_result: ", clump_result);
|
||||
const single_run_result = single_run_score(object);
|
||||
// console.log("single_run_result: ", single_run_result);
|
||||
const increasing_row_across_result = increasing_row_across(object);
|
||||
// console.log("increasing_row_across_result: ", increasing_row_across_result);
|
||||
const tot_sum_result = tot_sum(object);
|
||||
// console.log("tot_sum_result: ", tot_sum_result);
|
||||
const all_numbers_result = all_numbers(object);
|
||||
// console.log("all_numbers_result: ", all_numbers_result);
|
||||
return [
|
||||
clump_result,
|
||||
single_run_result,
|
||||
increasing_row_across_result,
|
||||
tot_sum_result,
|
||||
all_numbers_result,
|
||||
];
|
||||
}
|
||||
// End of code made with help from Raj Tiller
|
||||
if (typeof window === "undefined") {
|
||||
const args = process.argv.slice(2);
|
||||
console.log(JSON.stringify(calculate_score(JSON.parse(args[0]))));
|
||||
}
|
||||
@@ -4,17 +4,22 @@ import os
|
||||
import json
|
||||
import time
|
||||
|
||||
def readFile(location): # Loads the location of a certain file and returns that file if it is json
|
||||
|
||||
def readFile(
|
||||
location,
|
||||
): # Loads the location of a certain file and returns that file if it is json
|
||||
with open(location) as f:
|
||||
return json.load(f)
|
||||
|
||||
def command(command): # Will just execute a sql command
|
||||
|
||||
def command(command): # Will just execute a sql command
|
||||
db, cursor = connect()
|
||||
cursor.execute(command)
|
||||
db.commit()
|
||||
db.close()
|
||||
|
||||
def trueSearch(command): # Will just execute sql command and return result
|
||||
|
||||
def trueSearch(command): # Will just execute sql command and return result
|
||||
db, cursor = connect()
|
||||
cursor.execute(command)
|
||||
value = cursor.fetchall()
|
||||
@@ -23,7 +28,9 @@ def trueSearch(command): # Will just execute sql command and return result
|
||||
|
||||
|
||||
def connect(database=""):
|
||||
dbInfo = readFile(__file__[: __file__.rindex("/python/database.py") + 1] + "html/config.json")
|
||||
dbInfo = readFile(
|
||||
__file__[: __file__.rindex("/python/database.py") + 1] + "html/config.json"
|
||||
)
|
||||
if not database:
|
||||
database = dbInfo["database"]["name"]
|
||||
try:
|
||||
@@ -33,14 +40,14 @@ def connect(database=""):
|
||||
user=dbInfo["database"]["username"],
|
||||
database=database,
|
||||
)
|
||||
except: # Used to automatically create the user and database
|
||||
except: # Used to automatically create the user and database
|
||||
path = __file__[: __file__.rindex("/") + 1]
|
||||
with open(path + "fix.sql") as f:
|
||||
text = f.read()
|
||||
text = text.replace("{username}", dbInfo["database"]["username"])
|
||||
text = text.replace("{password}", dbInfo["database"]["password"])
|
||||
text = text.replace("{database}", dbInfo["database"]["name"])
|
||||
with open(path + "fix2.sql", 'w') as f:
|
||||
with open(path + "fix2.sql", "w") as f:
|
||||
f.write(text)
|
||||
os.system(f"mysql < {path}fix2.sql")
|
||||
os.remove(path + "fix2.sql")
|
||||
@@ -104,23 +111,31 @@ def appendValue(table, value, coulumns=""): # Will add a value to a table
|
||||
|
||||
# Will backup a database to a certain location with a name of choosing
|
||||
def backUp(fileName):
|
||||
dbInfo = readFile(__file__[: __file__.rindex("/python/database.py") + 1] + "html/config.json")
|
||||
dbInfo = readFile(
|
||||
__file__[: __file__.rindex("/python/database.py") + 1] + "html/config.json"
|
||||
)
|
||||
username = dbInfo["database"]["username"]
|
||||
password = dbInfo["database"]["password"]
|
||||
database = dbInfo["database"]["name"]
|
||||
location = dbInfo["database"]["backupLocation"]
|
||||
locationdata = f"{location}/{fileName}"
|
||||
if (not os.path.exists(location)):
|
||||
if not os.path.exists(location):
|
||||
os.system(f"mkdir {location}")
|
||||
os.system(f"mysqldump -u {username} --password={password} --result-file={locationdata} {database}")
|
||||
os.system(
|
||||
f"mysqldump -u {username} --password={password} --result-file={locationdata} {database}"
|
||||
)
|
||||
|
||||
|
||||
def restore(fileName):
|
||||
dbInfo = readFile(__file__[: __file__.rindex("/python/database.py") + 1] + "html/config.json")
|
||||
dbInfo = readFile(
|
||||
__file__[: __file__.rindex("/python/database.py") + 1] + "html/config.json"
|
||||
)
|
||||
location = dbInfo["database"]["backupLocation"]
|
||||
database = dbInfo["database"]["name"]
|
||||
locationdata = f"{location}/{fileName}"
|
||||
os.system(f"mysql {database} < {locationdata}")
|
||||
|
||||
|
||||
def search(table, where, search="*"): # searches for value in table
|
||||
db, cursor = connect()
|
||||
cursor.execute("SELECT " + search + " FROM " + table + " WHERE " + where + ";")
|
||||
@@ -142,11 +157,13 @@ def delete(table, where): # deletes values in table
|
||||
|
||||
def repair(): # Repairs all tables or updates them if needed
|
||||
# Gets Infomation schema database
|
||||
dbInfo = readFile(__file__[: __file__.rindex("/python/database.py") + 1] + "html/config.json")
|
||||
dbInfo = readFile(
|
||||
__file__[: __file__.rindex("/python/database.py") + 1] + "html/config.json"
|
||||
)
|
||||
db2, cursor2 = connect("INFORMATION_SCHEMA")
|
||||
updatedVersions = []
|
||||
databaseDict = {
|
||||
"information" : [["pointer", 0], ["data", 0]],
|
||||
"information": [["pointer", 0], ["data", 0]],
|
||||
"cookies": [["cookie", 0], ["username", 0], ["expire", 1], ["lastIP", 0]],
|
||||
"internet": [
|
||||
["hour", 1],
|
||||
@@ -161,14 +178,66 @@ def repair(): # Repairs all tables or updates them if needed
|
||||
"privileges": [["username", 0], ["privilege", 0]],
|
||||
"users": [["username", 0], ["password", 0]],
|
||||
"requests": [["ip", 0], ["time", 1]],
|
||||
"cookieClicker": [["username", 0], ["room", 0], ["cookies", 2], ["cookiesPs", 2], ["lastUpdate", 3]],
|
||||
"localStorage" : [["username", 0], ["data", 4]],
|
||||
"space3" : [["id", 5], ["owner", 0], ["title", 0], ["description", 4], ["preferences", 4], ["likes", 1], ["downloads", 1]],
|
||||
"space3likes" : [["id", 1], ["account", 0]],
|
||||
"golfGamePlayers" : [["gameID", 1], ["multiplier", 1], ["user", 0], ["points", 1], ["orderID", 1], ["lastMode", 0], ["upToDate", 6], ["turnsSkipped", 1], ["bot", 6]],
|
||||
"golfGameCards" : [["gameID", 1], ["user", 0], ["card", 1], ["cardPlacement", 1], ["faceUp", 6]],
|
||||
"golfGame" : [["ID", 5], ["deck", 4], ["discard", 4], ["cardNumber", 1], ["flipNumber", 1], ["multiplierForFlip", 1], ["pointsToEnd", 1], ["name", 0], ["password", 0], ["players", 1], ["playersToStart", 1], ["currentPlayer", 1], ["turnStartTime", 1], ["locked", 6], ["decks", 1], ["skipTime", 1], ["timeLeft", 1], ["skipTurns", 1], ["resetPoints", 1], ["bots", 1]],
|
||||
"random_stuff" : [["type", 0], ["word", 0], ["definition", 4]]
|
||||
"cookieClicker": [
|
||||
["username", 0],
|
||||
["room", 0],
|
||||
["cookies", 2],
|
||||
["cookiesPs", 2],
|
||||
["lastUpdate", 3],
|
||||
],
|
||||
"localStorage": [["username", 0], ["data", 4]],
|
||||
"space3": [
|
||||
["id", 5],
|
||||
["owner", 0],
|
||||
["title", 0],
|
||||
["description", 4],
|
||||
["preferences", 4],
|
||||
["likes", 1],
|
||||
["downloads", 1],
|
||||
],
|
||||
"space3likes": [["id", 1], ["account", 0]],
|
||||
"golfGamePlayers": [
|
||||
["gameID", 1],
|
||||
["multiplier", 1],
|
||||
["user", 0],
|
||||
["points", 1],
|
||||
["orderID", 1],
|
||||
["lastMode", 0],
|
||||
["upToDate", 6],
|
||||
["turnsSkipped", 1],
|
||||
["bot", 6],
|
||||
],
|
||||
"golfGameCards": [
|
||||
["gameID", 1],
|
||||
["user", 0],
|
||||
["card", 1],
|
||||
["cardPlacement", 1],
|
||||
["faceUp", 6],
|
||||
],
|
||||
"golfGame": [
|
||||
["ID", 5],
|
||||
["deck", 4],
|
||||
["discard", 4],
|
||||
["cardNumber", 1],
|
||||
["flipNumber", 1],
|
||||
["multiplierForFlip", 1],
|
||||
["pointsToEnd", 1],
|
||||
["name", 0],
|
||||
["password", 0],
|
||||
["players", 1],
|
||||
["playersToStart", 1],
|
||||
["currentPlayer", 1],
|
||||
["turnStartTime", 1],
|
||||
["locked", 6],
|
||||
["decks", 1],
|
||||
["skipTime", 1],
|
||||
["timeLeft", 1],
|
||||
["skipTurns", 1],
|
||||
["resetPoints", 1],
|
||||
["bots", 1],
|
||||
],
|
||||
"random_stuff": [["type", 0], ["word", 0], ["definition", 4]],
|
||||
"klumpy": [["gameID", 1], ["type", 0], ["username", 0], ["score", 1], ["board", 4], ["history", 4]],
|
||||
}
|
||||
changedTables = []
|
||||
for x in databaseDict:
|
||||
@@ -211,7 +280,10 @@ def repair(): # Repairs all tables or updates them if needed
|
||||
1
|
||||
createTable(name, trueValues)
|
||||
if name == "logType":
|
||||
logTypes = readFile(__file__[: __file__.rindex("/python/database.py") + 1] + "html/logTypes.json")
|
||||
logTypes = readFile(
|
||||
__file__[: __file__.rindex("/python/database.py") + 1]
|
||||
+ "html/logTypes.json"
|
||||
)
|
||||
for x in logTypes:
|
||||
appendValue(name, [x["type"], x["name"], x["color"]])
|
||||
else:
|
||||
@@ -220,14 +292,19 @@ def repair(): # Repairs all tables or updates them if needed
|
||||
elif name == "users":
|
||||
appendValue(
|
||||
name,
|
||||
[dbInfo["database"]["username"], dbInfo["database"]["password"]],
|
||||
[
|
||||
dbInfo["database"]["username"],
|
||||
dbInfo["database"]["password"],
|
||||
],
|
||||
)
|
||||
changedTables.append(name)
|
||||
elif name == "information": # Used to check the information table to see if the database can be updated in a better way.
|
||||
elif (
|
||||
name == "information"
|
||||
): # Used to check the information table to see if the database can be updated in a better way.
|
||||
version = trueSearch("SELECT data FROM information WHERE pointer='version'")
|
||||
latest_version = "v2.4"
|
||||
if version: # Checks if the version tag still exists.
|
||||
try: # In here you can update the version to a new version
|
||||
latest_version = "v2.7"
|
||||
if version: # Checks if the version tag still exists.
|
||||
try: # In here you can update the version to a new version
|
||||
version = version[0][0]
|
||||
if version == "v1.0":
|
||||
try:
|
||||
@@ -241,47 +318,68 @@ def repair(): # Repairs all tables or updates them if needed
|
||||
command("ALTER TABLE cookies ADD lastIP varchar(255)")
|
||||
except Exception:
|
||||
1
|
||||
createTable("docker", [["link", 0], ["action", 0], ["image", 0], ["password", 0], ["owner", 0], ["port", 1], ["ID", 0]])
|
||||
createTable(
|
||||
"docker",
|
||||
[
|
||||
["link", 0],
|
||||
["action", 0],
|
||||
["image", 0],
|
||||
["password", 0],
|
||||
["owner", 0],
|
||||
["port", 1],
|
||||
["ID", 0],
|
||||
],
|
||||
)
|
||||
createTable("dockerImage", [["realName", 0], ["shortName", 0]])
|
||||
version = "v2.0"
|
||||
updatedVersions.append("v2.0")
|
||||
if version == "v2.0": # Adds support for multiple decks
|
||||
if version == "v2.0": # Adds support for multiple decks
|
||||
command("ALTER table golfGame ADD decks int")
|
||||
command("UPDATE golfGame SET decks='1'")
|
||||
version = "v2.1"
|
||||
updatedVersions.append("v2.1")
|
||||
if version == "v2.1": # Adds support for skip time
|
||||
if version == "v2.1": # Adds support for skip time
|
||||
command("ALTER table golfGame ADD skipTime int")
|
||||
command("ALTER table golfGame ADD timeLeft int")
|
||||
command("UPDATE golfGame SET skipTime='0'")
|
||||
command("UPDATE golfGame SET timeLeft='0'")
|
||||
version = "v2.2"
|
||||
updatedVersions.append("v2.2")
|
||||
if version == "v2.2": # Adds support for limited amount of turns to skip
|
||||
if (
|
||||
version == "v2.2"
|
||||
): # Adds support for limited amount of turns to skip
|
||||
command("ALTER table golfGame ADD skipTurns int")
|
||||
command("UPDATE golfGame SET skipTurns='0'")
|
||||
command("ALTER table golfGamePlayers ADD turnsSkipped int")
|
||||
command("UPDATE golfGamePlayers SET turnsSkipped='0'")
|
||||
version = "v2.3"
|
||||
updatedVersions.append("v2.3")
|
||||
if version == "v2.3": # Adds support for reset points when hitting a certain multiplier
|
||||
if (
|
||||
version == "v2.3"
|
||||
): # Adds support for reset points when hitting a certain multiplier
|
||||
command("ALTER table golfGame ADD resetPoints int")
|
||||
command("UPDATE golfGame SET resetPoints='0'")
|
||||
version = "v2.4"
|
||||
updatedVersions.append("v2.4")
|
||||
if version == "v2.4": # Drops support for docker
|
||||
if version == "v2.4": # Drops support for docker
|
||||
command("DROP TABLE docker")
|
||||
command("DROP TABLE dockerImages")
|
||||
command("DELETE FROM privileges WHERE privilege='docker' OR privilege='dockerAdmin'")
|
||||
command(
|
||||
"DELETE FROM privileges WHERE privilege='docker' OR privilege='dockerAdmin'"
|
||||
)
|
||||
version = "v2.5"
|
||||
updatedVersions.append("v2.5")
|
||||
if version == "v2.5": # Drops support for docker
|
||||
if version == "v2.5": # Drops support for docker
|
||||
command("ALTER TABLE golfGamePlayers ADD bot boolean")
|
||||
command("ALTER TABLE golfGame ADD bots int")
|
||||
command("ALTER TABLE golfGamePlayers SET bot=0")
|
||||
command("ALTER TABLE golfGame SET bots=0")
|
||||
version = "v2.6"
|
||||
updatedVersions.append("v2.6")
|
||||
if version == "v2.6":
|
||||
createTable("klumpy", [["gameID", 1], ["type", 6], ["username", 0], ["score", 1], ["board", 4], ["history", 4]])
|
||||
version = "v2.7"
|
||||
updatedVersions.append("v2.7")
|
||||
# Fixes the version if it is invalid to the latest version
|
||||
if version != latest_version:
|
||||
version = latest_version
|
||||
@@ -290,7 +388,9 @@ def repair(): # Repairs all tables or updates them if needed
|
||||
command("DELETE FROM information WHERE pointer='version'")
|
||||
command(f"INSERT INTO information VALUES('version', '{version}')")
|
||||
else:
|
||||
command(f"INSERT INTO information VALUES('version', '{latest_version}')")
|
||||
command(
|
||||
f"INSERT INTO information VALUES('version', '{latest_version}')"
|
||||
)
|
||||
changedTables.append("information")
|
||||
db2.close()
|
||||
return changedTables, updatedVersions
|
||||
return changedTables, updatedVersions
|
||||
|
||||
Reference in New Issue
Block a user