Skip to content

Instantly share code, notes, and snippets.

@bbrewer97202
Last active May 19, 2016 17:40
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save bbrewer97202/cc1c9b7b7d6eca934dd788b75db91f2f to your computer and use it in GitHub Desktop.
Save bbrewer97202/cc1c9b7b7d6eca934dd788b75db91f2f to your computer and use it in GitHub Desktop.
15 puzzle in javascript
<!DOCTYPE html>
<html>
<head>
<title></title>
</head>
<body>
<div class="container" id="container"></div>
<style type="text/css">
.container {
width: 200px;
height: 200px;
background-color: black;
border: solid 10px black;
}
button {
display: block;
float: left;
width: 50px;
height: 50px;
-webkit-appearance: none;
-moz-appearance: none;
appearance: none;
margin: 0;
padding: 0;
border: 0;
background-color: red;
color: gold;
font-weight: bold;
font-size: 1em;
text-shadow: 1px 1px 2px black;
-webkit-box-shadow: inset 1px 0px 2px 0px rgba(0,0,0,0.25);
-moz-box-shadow: inset 1px 0px 2px 0px rgba(0,0,0,0.25);
box-shadow: inset 1px 0px 2px 0px rgba(0,0,0,0.25);
}
button.odd {
background-color: white;
}
.empty {
float: left;
width: 50px;
height: 50px;
background-color: black;
}
</style>
<script type="text/javascript">
const size = 4;
let positions = createInitialPositions(size);
render(positions);
document.getElementById('container').addEventListener('click', onButtonClick);
function createInitialPositions(count) {
let length = (count * count);
let values = [];
let initialPositions = [];
//fill initial values
for (let c = 0; c < length; c++) {
values.push(c);
}
//shuffle values
for (let i = length; i; i -= 1) {
let j = Math.floor(Math.random() * i);
let x = values[i - 1];
values[i - 1] = values[j];
values[j] = x;
}
//put values into multidimensional list
for (let c = 0, k = -1; c < length; c++) {
if (c % count === 0) {
k++;
initialPositions[k] = [];
}
initialPositions[k].push(values[c]);
}
return initialPositions;
}
function onButtonClick(e) {
e.preventDefault();
if (e.target.nodeName.toLowerCase() === 'button') {
let id = parseInt(e.target.getAttribute('data-number'), 10);
let selected = getTilePosition(positions, id);
let empty = getTilePosition(positions, 0);
//to the left or right
if (selected.row === empty.row) {
//re-order the row
let reorderedRow = positions[empty.row].slice();
reorderedRow.splice(empty.col, 1);
reorderedRow.splice(selected.col, 0, 0);
//format updated changes
let changedList = reorderedRow.map((value, index) => {
return {
row: empty.row,
col: index,
value
}
});
//notify changes
appyChanges(positions, changedList);
//above or below
} else if (selected.col === empty.col) {
let changedList = [];
if (empty.row > selected.row) {
while (empty.row > selected.row) {
empty.row--;
changedList.push({
row: empty.row + 1,
col: empty.col,
value: positions[empty.row][empty.col]
});
}
} else if (selected.row > empty.row) {
while (selected.row > empty.row) {
empty.row++;
changedList.push({
row: empty.row - 1,
col: empty.col,
value: positions[empty.row][empty.col]
});
}
}
changedList.push({
row: selected.row,
col: empty.col,
value: 0
});
//notify changes
appyChanges(positions, changedList);
}
}
}
function appyChanges(state, listOfChanges) {
//copy existing positions
let newState = state.map(row => row.slice());
//apply changes to newState
listOfChanges.map(update => newState[update.row][update.col] = update.value);
//re-render
render(newState);
}
function render(state) {
let container = document.getElementById('container');
//empty container
while (container.firstChild) {
container.removeChild(container.firstChild);
}
//redraw state
for (let i = 0; i < size; i++) {
for (let j = 0; j < size; j++) {
if (state[i][j] === 0) {
let empty = document.createElement('div');
empty.className = 'empty';
container.appendChild(empty);
} else {
let button = document.createElement('button');
button.setAttribute('data-number', state[i][j]);
button.className = (state[i][j] % 2 === 0) ? 'even' : 'odd';
button.appendChild(document.createTextNode(state[i][j]));
container.appendChild(button);
}
}
}
// console.table(state);
//update state, normally do not do this or use globals but state store
positions = state.map(row => row.slice());
}
function getTilePosition(grid, id) {
let pos = {};
grid.forEach(function(element, index) {
let i = element.indexOf(id);
if (i !== -1) {
pos.row = index;
pos.col = i;
}
});
return pos;
}
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment