Add initial codes.

This commit is contained in:
John Espiritu 2021-07-25 22:26:58 +08:00
commit b2ba582cec
5 changed files with 410 additions and 0 deletions

12
README.md Normal file
View File

@ -0,0 +1,12 @@
# Number Slide
Simple number slide game using HTML and vanila JavaScript.
<div align="center">
<img src="screenshot.png"/>
</div>
## Development
- Open `index.html` on a modern browser.
- Edit the files on your favorite text editor.

115
dist/app.css vendored Normal file
View File

@ -0,0 +1,115 @@
body {
padding: 0;
margin: 0;
background-color: rgb(240, 240, 244);
font-family: sans-serif;
}
main {
background-color: rgb(230, 230, 234);
border-radius: 8px;
}
h1 {
font-size: 2.5em;
color: rgb(57, 57, 61);
margin: 0;
width: 100%;
}
footer {
text-align: center;
font-size: 12px;
color: rgb(110, 110, 114);
text-transform: uppercase;
}
footer a {
color: rgb(110, 110, 114);
text-decoration: none;
}
footer a:hover {
text-decoration: underline;
}
#wrapper {
margin: 0 auto;
max-width: 500px;
width: 100%;
margin: 0 auto;
padding: 0 2em;
box-sizing: border-box;
}
#controls {
display: flex;
margin: 2em 0 1em 0;
justify-content: center;
align-items: center;
}
#controls button {
background-color: rgb(220, 220, 224);
border: 0;
border-radius: 6px;
padding: 0.7em 1.5em;
transition: all 0.12s ease-out;
}
#controls button:not([disabled]):hover {
cursor: pointer;
background-color: #04bbd9;
color: white;
}
#stage {
margin: 4em auto 6em auto;
}
#stage section {
width: 100%;
min-height: 130px;
border-radius: 8px;
position: relative;
display: grid;
grid-template-columns: [c1] 33.33% [c2] 33.33% [c3] 33.33% [c-end];
grid-template-rows: [r1] 33.33% [r2] 33.33% [r3] 33.33% [r-end];
filter: drop-shadow(0 0 8px rgba(0, 0, 0, 0.15));
}
#stage button {
margin: 0;
padding: 0;
font-size: 3em;
background: rgb(250, 250, 252);
color: rgb(50, 50, 55);
overflow: hidden;
transition: transform 0.12s ease-out, background-color 0.12s ease-out;
border-radius: 8px;
border: 1px solid rgb(198, 198, 201);
grid-column-start: c1;
grid-row-start: r1;
z-index: 1;
}
#stage button.fast {
transition: transform 0.08s ease-out;
}
#stage.done button[disabled] {
background-color: #20a076;
color: white;
}
.c1.r1 { transform: translate(0, 0); }
.c1.r2 { transform: translate(0, 100%); }
.c1.r3 { transform: translate(0, 200%); }
.c2.r1 { transform: translate(100%, 0); }
.c2.r2 { transform: translate(100%, 100%); }
.c2.r3 { transform: translate(100%, 200%); }
.c3.r1 { transform: translate(200%, 0); }
.c3.r2 { transform: translate(200%, 100%); }
.c3.r3 { transform: translate(200%, 200%); }

249
dist/app.js vendored Normal file
View File

@ -0,0 +1,249 @@
var grid = [1, 2, 3, 4, 5, 6, 7, 8, 0 ];
var COLS = 3;
var ROWS = grid.length / COLS;
var SHUFFLES = 35;
var MOV_LEFT = 0;
var MOV_RIGHT = 1;
var MOV_UP = 2;
var MOV_DOWN = 3;
var tiles = document.querySelectorAll('#stage button');
var textTime = document.getElementById('time');
var buttonShuffle = document.getElementById('shuffle');
var stage = document.getElementById('stage');
var stageSection = document.querySelector('#stage section');
var wrapper = document.getElementById('wrapper');
var timer = null;
var startTime = 0;
function getRow(index) {
return Math.floor(index / COLS);
}
function getCol(index) {
return (index % COLS);
}
function render() {
grid.forEach(function (value, index) {
var col = getCol(index) + 1;
var row = getRow(index) + 1;
var element = document.getElementById(value);
if (element === null) {
return;
}
element.classList.remove('c1', 'c2', 'c3', 'r1', 'r2', 'r3');
element.classList.add('c' + col, 'r' + row);
});
}
function swap(a, b) {
var tmp = grid[a];
grid[a] = grid[b];
grid[b] = tmp;
}
function getSpacePossibleMoves(reverseDir) {
var index = grid.indexOf(0);
var possibleMoves = new Set([MOV_LEFT, MOV_RIGHT, MOV_UP, MOV_DOWN]);
if (index % COLS == COLS - 1)
possibleMoves.delete(MOV_RIGHT);
if (index % COLS == 0)
possibleMoves.delete(MOV_LEFT);
if (Math.floor(index / ROWS) == 0)
possibleMoves.delete(MOV_UP);
if (Math.floor(index / ROWS) == ROWS - 1)
possibleMoves.delete(MOV_DOWN);
possibleMoves.delete(reverseDir);
return Array.from(possibleMoves);
}
function moveSpace(direction) {
var index = grid.indexOf(0);
var step = 0;
switch (direction) {
case MOV_LEFT: case MOV_UP:
step = -1;
break;
case MOV_RIGHT: case MOV_DOWN:
step = 1;
break;
default:
step = 0;
}
if ([MOV_LEFT, MOV_RIGHT].indexOf(direction) > -1) {
// horizontal
var inc = index + step;
if (inc < 2 || inc >= 0) {
swap(index, inc);
}
} else {
// vertical
var inc = index + (ROWS * step);
if (inc < grid.length || inc >= 0) {
swap(index, inc);
}
}
render();
}
function moveHorizontal(index) {
var col = getCol(index);
if (col == 0) {
if (grid[index + 1] == 0)
swap(index, index + 1);
} else if (col == COLS - 1) {
if (grid[index - 1] == 0)
swap(index, index - 1);
} else {
if (grid[index + 1] == 0)
swap(index, index + 1);
else if (grid[index - 1] == 0)
swap(index, index - 1);
}
}
function moveVertical(index) {
var row = getRow(index);
if (row == 0) {
if (grid[index + ROWS] == 0)
swap(index, index + ROWS);
} else if (row == ROWS - 1) {
if (grid[index - ROWS] == 0)
swap(index, index - ROWS);
} else {
if (grid[index + ROWS] == 0)
swap(index, index + ROWS);
else if (grid[index - ROWS] == 0)
swap(index, index - ROWS);
}
}
function shuffle(steps) {
var i = 0;
var prevDir = -1;
tiles.forEach(function (tile) {
tile.classList.add('fast');
});
var loop = setInterval(function () {
var reverseDir = -1;
if (prevDir == MOV_DOWN)
reverseDir = MOV_UP;
if (prevDir == MOV_UP)
reverseDir = MOV_DOWN;
if (prevDir == MOV_LEFT)
reverseDir = MOV_RIGHT;
if (prevDir == MOV_RIGHT)
reverseDir = MOV_LEFT;
var possibleMoves = getSpacePossibleMoves(reverseDir);
var dir = possibleMoves[Math.floor(Math.random() * possibleMoves.length)];
moveSpace(dir);
prevDir = dir;
i++;
if (i >= steps) {
clearInterval(loop);
enableTiles();
document.getElementById('stage').classList.remove('done');
buttonShuffle.disabled = false;
tiles.forEach(function (tile) {
tile.classList.remove('fast');
});
return;
}
}, 90);
disableTiles();
buttonShuffle.disabled = true;
}
function formatTime(time) {
var minutes = Math.floor(time / 60).toString().padStart(2, '0');
var seconds = Math.floor(time % 60).toString().padStart(2, '0');
var millis = Math.floor((time % 1) * 100).toString().padStart(2, '0');
return minutes + ':' + seconds + '.<small>' + millis + '</small>';
}
function startTimer() {
if (timer !== null) {
return;
}
startTime = (new Date()).getTime();
timer = setInterval(function () {
var diff = ((new Date()).getTime() - startTime) / 1000;
textTime.innerHTML = formatTime(diff);
}, 16);
}
function stopTimer() {
clearInterval(timer);
timer = null;
}
function resetTimer() {
stopTimer();
startTime = 0;
textTime.innerHTML = formatTime(0);
}
function checkCompleted() {
for (var i = 0; i < grid.length - 2; ++i) {
if (grid[i + 1] < grid[i]) {
return;
}
}
document.getElementById('stage').classList.add('done');
disableTiles();
stopTimer();
}
function disableTiles() {
tiles.forEach(function (button) {
button.disabled = true;
});
}
function enableTiles() {
tiles.forEach(function (button) {
button.disabled = false;
});
}
function resizeStage() {
var wrapperStyle = getComputedStyle(wrapper);
var paddingLeft = parseInt(wrapperStyle.getPropertyValue('padding-left'));
var paddingRight = parseInt(wrapperStyle.getPropertyValue('padding-right'));
var width = parseInt(wrapperStyle.getPropertyValue('width'));
var adjustedWidth = width - paddingLeft - paddingRight;
while (adjustedWidth % 3 != 0) {
adjustedWidth--;
}
stage.style.fontSize = (adjustedWidth / 24) + 'px';
stage.style.width = adjustedWidth + 'px';
stageSection.style.height = adjustedWidth + 'px';
}
tiles.forEach(function (button) {
button.onclick = function (e) {
var tileId = e.target.id;
var index = grid.indexOf(parseInt(tileId));
moveHorizontal(index);
moveVertical(index);
render();
startTimer();
checkCompleted();
}
});
buttonShuffle.onclick = function () {
resetTimer();
shuffle(SHUFFLES);
}
window.onload = function () {
resizeStage();
render();
shuffle(SHUFFLES);
};
window.onresize = resizeStage;

34
dist/index.html vendored Normal file
View File

@ -0,0 +1,34 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="app.css"/>
<title>Number Slide</title>
</head>
<body>
<div id="wrapper">
<div id="controls">
<h1 id="time">00:00.<small>00</small></h1>
<button id="shuffle" disabled>Shuffle</button>
</div>
<main id="stage">
<section>
<button id="1" class="c1 r1">1</button>
<button id="2" class="c2 r1">2</button>
<button id="3" class="c3 r1">3</button>
<button id="4" class="c1 r2">4</button>
<button id="5" class="c2 r2">5</button>
<button id="6" class="c3 r2">6</button>
<button id="7" class="c1 r3">7</button>
<button id="8" class="c2 r3">8</button>
</section>
</main>
<footer>
2021 &copy; <a href="https://johnespiritu.dev">John Espiritu</a>
</footer>
</div>
<script src="app.js"></script>
</body>
</html>

BIN
screenshot.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB