Add initial codes.
This commit is contained in:
commit
b2ba582cec
|
|
@ -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.
|
||||
|
|
@ -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%); }
|
||||
|
|
@ -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;
|
||||
|
|
@ -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 © <a href="https://johnespiritu.dev">John Espiritu</a>
|
||||
</footer>
|
||||
</div>
|
||||
<script src="app.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 22 KiB |
Reference in New Issue