Skip to content

Commit

Permalink
Solvability
Browse files Browse the repository at this point in the history
  • Loading branch information
hugomosh committed Jun 24, 2020
1 parent 0eb62d8 commit 9d1ebfd
Show file tree
Hide file tree
Showing 4 changed files with 118 additions and 8 deletions.
5 changes: 5 additions & 0 deletions Notes.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
Calculate the solvability

[Solvability of the Tiles Game](https://www.cs.bham.ac.uk/~mdr/teaching/modules04/java2/TilesSolvability.html)

Calculate the number of inversions. An inversion is when a tile precedes another tile with a lower number on it.
3 changes: 3 additions & 0 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@
</head>
<body>
<div id="puzzle-15"></div>
<div id="controls">
<button id="shuffle"> Shuffle</button>
</div>
<script src="./index.ts"></script>
</body>
<!-- Global site tag (gtag.js) - Google Analytics -->
Expand Down
28 changes: 27 additions & 1 deletion index.scss
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ $palette4: #ffadadff, #ffd6a5ff, #fdffb6ff, #caffbfff, #9bf6ffff, #a0c4ffff,
$colorList: ();
$newColorList: ();

$font-family: Arial, Helvetica, sans-serif;
@function shuffle($list) {
$list-length: length($list);

Expand All @@ -34,6 +35,7 @@ $color4: nth($colors, 5) !default;
html,
body {
overflow-x: hidden;
font-family: $font-family;
}
body {
position: relative;
Expand Down Expand Up @@ -85,7 +87,7 @@ svg text::selection {
background: none;
}
text {
font-family: Arial, Helvetica, sans-serif;
font-family: $font-family;
font-size: 2rem;
fill: $color4;
}
Expand All @@ -95,3 +97,27 @@ text {
fill: $color3;
background-color: $color3;
}

#controls{
position: absolute;
bottom: 30px;
}

button{
border-radius: 10px;
background-color: $color3;
min-height: 70px;
min-width: 70*2px;
border: none;
outline: none;
box-shadow: none;
font-size: 2rem;
&:hover {
background: $color4;

}
&:active{
background: $color1;

}
}
90 changes: 83 additions & 7 deletions index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import { SVG, Timeline, Svg } from "@svgdotjs/svg.js";
const IMPOSSIBLE = [15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0];
const GOAL_ORDINAL = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 0, 15];

let currentState = [];
const DIRECTIONS = {
l: { text: "left", id: "l", emoji: "⬅", key: 37 },
Expand All @@ -10,11 +12,6 @@ const DIRECTIONS = {

let board;

function main() {
board = createBoard();
addKeyboardListeners();
}

function getXforMN(m, n) {
return (index) => index % n;
}
Expand Down Expand Up @@ -110,7 +107,6 @@ function executeStep(currentState, step) {

function tilePressed(index) {
return (e) => {
console.log("tile pressed", index, e);
const newSteps = calculateNextSteps(board, index);
const newState = executeSteps(board, newSteps);
console.log({ newState, newSteps });
Expand Down Expand Up @@ -253,8 +249,88 @@ function checkKey(e) {
board.steps = [...board.steps, validDirection.id];
}
}
main();

function arraysEqual(a1, a2) {
return JSON.stringify(a1) == JSON.stringify(a2);
}

function getValidShuffle(currentState = GOAL_ORDINAL) {
let newState = randomSwap(randomSwap(currentState));
console.log({newState});
const originalSolvability = isSolvableToOriginal(currentState);
while(isSolvableToOriginal(newState)!==originalSolvability ){
newState = randomSwap(currentState);
console.log({newState});

}
return newState;
}

/* New array with random swapped elements. */
function randomSwap(arr) {
const a = getRandomInt(0, arr.length);
let b = a;
while (b === a) {
b = getRandomInt(0, arr.length);
}
const newArr = [...arr];
newArr[a] = newArr[b];
newArr[b] = arr[a];
return newArr;
}

function calculateHeuristic(objectiveState, currentState) {
let h = 0;
currentState.forEach((e, i) => {});
return h;
}

function getRandomInt(min, max) {
return Math.floor(Math.random() * (max - min)) + min;
}

function prepareShuffleControl() {
document.getElementById("shuffle").addEventListener(
"click",
() => {
console.log("Shuffle");

const newState = getValidShuffle(board.currentState);
animateToNewState(newState).play();
board.currentState = newState;
},
false
);
}

function getInversionCount(state) {
//TODO: find O(nLogn) solution
let count = 0;
for (let i = 0; i < state.length - 1; i++) {
const ti = state[i];
for (let j = i + 1; j < state.length; j++) {
const tj = state[j];
if (ti && tj && ti > tj) {
count++;
}
}
}
return count;
}

function isSolvableToOriginal(state) {
const inversionCount = getInversionCount(state);
// As puzzle15 is 4x4, the pos of the empty cell matters.
const zeroTilePosition = state.indexOf(0);
// xor
return !!((Math.floor(zeroTilePosition / 4)& 1) ^ (inversionCount & 1));
}

function main() {
board = createBoard();
addKeyboardListeners();
prepareShuffleControl();
console.log({ getValidShuffle, calculateHeuristic });
}

main();

0 comments on commit 9d1ebfd

Please sign in to comment.