-
Notifications
You must be signed in to change notification settings - Fork 5
/
ai.js
98 lines (81 loc) · 2.67 KB
/
ai.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
function triggerKey(key) {
var code = key === ' ' ? 32 :
key === 'Left' ? 37 :
key === 'Up' ? 38 :
key === 'Right' ? 39 :
key === 'Down' ? 40 : 0;
var e = document.createEvent('KeyboardEvent');
// Gah, screw chrome
Object.defineProperty(e, 'keyCode', {
get : function() { return code; }
});
Object.defineProperty(e, 'which', {
get : function() { return code; }
});
Object.defineProperty(e, 'metaKey', {
get : function() { return false; }
});
Object.defineProperty(e, 'shiftKey', {
get : function() { return false; }
});
if (e.initKeyboardEvent)
e.initKeyboardEvent("keydown", true, true, document.defaultView, false, false, false, false, code, code);
else
e.initKeyEvent("keydown", true, true, document.defaultView, false, false, false, false, code, 0);
document.body.dispatchEvent(e);
}
function getTiles() {
var tileElements = Array.prototype.slice.call(document.getElementsByClassName('tile'));
return tileElements.map(function(tile) {
return {
value: Number(tile.className.match(/tile-(\d)/)[1]),
x: Number(tile.className.match(/position-(\d)/)[1]) - 1, // zero-based numbering is best-based numbering
y: Number(tile.className.match(/position-\d-(\d)/)[1]) - 1
};
});
}
function adjacent(t1, t2) {
return (Math.abs(t1.x - t2.x) === 1 && t1.y === t2.y) ||
(Math.abs(t1.y - t2.y) === 1 && t1.x == t2.x);
}
function tileAt(x, y, tiles) {
return tiles.some(function(tile) {
return tile.x === x && tile.y === y;
});
}
function moveBetween(t1, t2, tiles) {
// Assumes adjacency
return t1.x !== t2.x ?
(t1.x === 0 || t2.x === 0 || ((t1.x === 1 || t2.x === 1) && tileAt(0, t1.y, tiles)) ? "Left" : "Right") :
(t1.y === 0 || t2.y === 0 || ((t1.y === 1 || t2.y === 1) && tileAt(t1.x, 0, tiles)) ? "Up" : "Down");
}
function randomMove() {
return ["Up", "Down", "Left", "Right"][Math.floor(Math.random() * 4)];
}
function move(tiles) {
var sorted = tiles.sort(function(t1, t2) {
return t1.value - t2.value;
});
for (var i = 0; i < sorted.length - 1; i++) {
if (adjacent(sorted[i], sorted[i + 1]))
return moveBetween(sorted[i], sorted[i + 1], tiles);
}
return randomMove();
}
function gameOver() {
return document.getElementsByClassName('game-over').length > 0;
}
function gameWon() {
return document.getElementsByClassName('game-won').length > 0;
}
(function tick() {
if (gameWon()) return;
var oldNumOfTiles = document.getElementsByClassName('tile').length;
if (gameOver())
document.getElementsByClassName('retry-button')[0].click();
else
triggerKey(move(getTiles()));
if (oldNumOfTiles === document.getElementsByClassName('tile').length)
triggerKey(randomMove()); // Prevents getting stuck
setTimeout(tick, 50);
})();