Created
July 5, 2016 14:33
-
-
Save anonymous/785b708c8faf76a9afeaa18337062ede to your computer and use it in GitHub Desktop.
Dodgy game AI
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* @author Dongjun Lee <[email protected]> | |
* Game AI for dodgygame. (http://brandonstilson.com/dodgygame/) | |
* | |
* How to use | |
* Copy and paste in browser's inspector console. | |
*/ | |
// constants | |
var BOARD_SIZE = 11; | |
var NOT_DETECTED = '?'; | |
var DIRECTION_UP = '↑'; | |
var DIRECTION_LEFT = '←'; | |
var DIRECTION_DOWN = '↓'; | |
var DIRECTION_RIGHT = '→'; | |
var DANGER_RANGE = 2; | |
var AI = { | |
fps: 60, | |
matrix: [], | |
player: { | |
x: 5, | |
y: 5 | |
}, | |
init: function() { | |
// init threads | |
window.clearInterval(this.__intervalId); | |
this.__initThreads(); | |
var _this = this; | |
this.__intervalId = window.setInterval(function() { | |
_this.__threadRunner(_this); | |
}, 1000 / this.fps); | |
// init data | |
this.initMatrix(); | |
// debug | |
this.initDebug(); | |
}, | |
reset: function(score) { | |
if (isNaN(score) === false) { | |
console.log(':: reset game, score=' + score); | |
} | |
this.init(); | |
}, | |
initMatrix: function() { | |
this.matrix = []; | |
for (var i = 0; i < BOARD_SIZE; i++) { | |
this.matrix.push([]); | |
for (var j = 0; j < BOARD_SIZE; j++) { | |
this.matrix[i].push(100); | |
} | |
} | |
}, | |
clearMatrix: function() { | |
for (var i = 0; i < BOARD_SIZE; i++) { | |
for (var j = 0; j < BOARD_SIZE; j++) { | |
this.matrix[i][j] = 100; | |
} | |
} | |
}, | |
debugMatrixMarkers: [], | |
initDebug: function() { | |
//draw grid | |
if (this.debugMatrixMarkers.length == 0) { | |
var parent = document.querySelector('#root>div:nth-child(1)'); | |
var debugRoot = document.createElement('div'); | |
debugRoot.style.width = '275px'; | |
debugRoot.style.height = '275px'; | |
debugRoot.style.border = '1px solid black'; | |
debugRoot.style.position = 'relative'; | |
debugRoot.style.margin = '25px auto'; | |
debugRoot.style.overflow = 'hidden'; | |
debugRoot.style.marginTop = '-302px'; | |
parent.appendChild(debugRoot); | |
for (var x = 0; x < BOARD_SIZE; x++) { | |
this.debugMatrixMarkers.push([]); | |
for (var y = 0; y < BOARD_SIZE; y++) { | |
var marker = document.createElement('div'); | |
marker.style.position = 'absolute'; | |
marker.style.width = marker.style.height = '25px'; | |
marker.style.left = x * 25 + 'px'; | |
marker.style.top = y * 25 + 'px'; | |
marker.style.lineHeight = '25px'; | |
marker.style.textAlign = 'center'; | |
debugRoot.appendChild(marker); | |
this.debugMatrixMarkers[x].push(marker); | |
} | |
} | |
} | |
for (var x = 0; x < BOARD_SIZE; x++) { | |
for (var y = 0; y < BOARD_SIZE; y++) { | |
this.debugMark(x, y, 100); | |
} | |
} | |
}, | |
debugMark: function(x, y, score) { | |
this.debugMatrixMarkers[x][y].style.background = 'rgba(255, 0, 255, ' + ((100 - score) / 100) * 0.5 + ')'; | |
}, | |
drawDebugMark: function() { | |
for (var x = 0; x < BOARD_SIZE; x++) { | |
for (var y = 0; y < BOARD_SIZE; y++) { | |
this.debugMark(x, y, this.matrix[x][y]); | |
} | |
} | |
}, | |
destroy: function() { | |
window.clearInterval(this.__intervalId); | |
}, | |
doMove: function() { | |
var avail = []; | |
var x = this.player.x; | |
var y = this.player.y; | |
if (x > 0) { | |
avail.push({ | |
score: this.matrix[x - 1][y], | |
dir: DIRECTION_LEFT | |
}); | |
} | |
if (x < BOARD_SIZE - 1) { | |
avail.push({ | |
score: this.matrix[x + 1][y], | |
dir: DIRECTION_RIGHT | |
}); | |
} | |
if (y > 0) { | |
avail.push({ | |
score: this.matrix[x][y - 1], | |
dir: DIRECTION_UP | |
}); | |
} | |
if (y < BOARD_SIZE - 1) { | |
avail.push({ | |
score: this.matrix[x][y + 1], | |
dir: DIRECTION_DOWN | |
}); | |
} | |
for (var i = 0; i < avail.length; i++) { | |
for (var j = i + 1; j < avail.length; j++) { | |
if (avail[i].score < avail[j].score) { | |
tmp = avail[i]; | |
avail[i] = avail[j]; | |
avail[j] = tmp; | |
} | |
} | |
} | |
// console.log(JSON.stringify(avail)); | |
function simKey(keyCode) { | |
window.onkeydown({ keyCode: keyCode }); | |
} | |
if (avail[0].score > this.matrix[x][y]) { | |
switch(avail[0].dir) { | |
case DIRECTION_LEFT: simKey(37); break; | |
case DIRECTION_RIGHT: simKey(39); break; | |
case DIRECTION_UP: simKey(38); break; | |
case DIRECTION_DOWN: simKey(40); break; | |
} | |
} | |
}, | |
calculateMatrix: function() { | |
this.clearMatrix(); | |
var objects = document.querySelectorAll('#root>div:nth-child(1)>div:nth-child(2)>div'); | |
for (i = 1; i < objects.length; i++) { | |
var hurdle = objects[i]; | |
var direction = hurdle.getAttribute('direction'); | |
var x = parseInt(parseFloat(hurdle.style.left) / 25); | |
var y = parseInt(parseFloat(hurdle.style.top) / 25); | |
switch (direction) { | |
case DIRECTION_UP: | |
for (j = y + 1; j >= 0; j--) { | |
this.matrix[x][Math.min(BOARD_SIZE - 1, j)] -= Math.max(0, j - y + DANGER_RANGE) * 60 + 5; | |
} | |
break; | |
case DIRECTION_LEFT: | |
for (j = x + 1; j >= 0; j--) { | |
this.matrix[Math.min(BOARD_SIZE - 1, j)][y] -= Math.max(0, j - x + DANGER_RANGE) * 60 + 5; | |
} | |
break; | |
case DIRECTION_DOWN: | |
for (j = y; j < BOARD_SIZE; j++) { | |
this.matrix[x][Math.min(BOARD_SIZE - 1, j)] -= Math.max(0, y - j + DANGER_RANGE + 1) * 60 + 5; | |
} | |
break; | |
case DIRECTION_RIGHT: | |
for (j = x; j < BOARD_SIZE; j++) { | |
this.matrix[Math.min(BOARD_SIZE - 1, j)][y] -= Math.max(0, x - j + DANGER_RANGE + 1) * 60 + 5; | |
} | |
break; | |
} | |
} | |
for (var x = 0; x < BOARD_SIZE; x++) { | |
for (var y = 0; y < BOARD_SIZE; y++) { | |
this.matrix[x][y] -= parseInt(Math.sqrt( | |
(x - 5) * (x - 5) + | |
(y - 5) * (y - 5) | |
) * 5); | |
} | |
} | |
for (i = 0; i < BOARD_SIZE; i++) { | |
this.matrix[i][0] -= 40; | |
this.matrix[0][i] -= 40; | |
this.matrix[i][BOARD_SIZE - 1] -= 40; | |
this.matrix[BOARD_SIZE - 1][i] -= 40; | |
} | |
}, | |
__initThreads: function() { | |
this.__threads['calculate-directions-thread'] = this.__calculateDirections; | |
this.__threads['detect-game-reset'] = this.__detectGameReset; | |
this.__threads['calculate-matrix-score'] = this.calculateMatrix; | |
this.__threads['check-player-position'] = this.__checkPlayerPosition; | |
this.__threads['draw-debug-mark'] = this.drawDebugMark; | |
this.__threads['do-player-move'] = this.doMove; | |
}, | |
__calculateDirections: function() { | |
var objects = document.querySelectorAll('#root>div:nth-child(1)>div:nth-child(2)>div'); | |
for (i = 1; i < objects.length; i++) { | |
var hurdle = objects[i]; | |
var direction = hurdle.getAttribute('direction'); | |
var x = parseFloat(hurdle.style.left); | |
var y = parseFloat(hurdle.style.top); | |
var pX = parseFloat(hurdle.getAttribute('x')); | |
var pY = parseFloat(hurdle.getAttribute('y')); | |
if (direction === null) { | |
hurdle.setAttribute('direction', NOT_DETECTED); | |
} else { | |
if (x < pX) { | |
hurdle.setAttribute('direction', DIRECTION_LEFT) | |
} else if (pX < x) { | |
hurdle.setAttribute('direction', DIRECTION_RIGHT) | |
} else if (y < pY) { | |
hurdle.setAttribute('direction', DIRECTION_UP) | |
} else if (pY < y) { | |
hurdle.setAttribute('direction', DIRECTION_DOWN) | |
} | |
} | |
hurdle.setAttribute('x', x); | |
hurdle.setAttribute('y', y) | |
hurdle.innerHTML = hurdle.getAttribute('direction'); | |
} | |
}, | |
__checkPlayerPosition: function() { | |
var player = document.querySelector('#root div div div div'); | |
var x = parseFloat(player.style.left); | |
var y = parseFloat(player.style.top); | |
this.player.x = parseInt(x / 25); | |
this.player.y = parseInt(y / 25); | |
}, | |
__detectGameReset: function() { | |
var time = parseInt( | |
document | |
.querySelector('#root>div>div>div>p') | |
.innerText.replace('Time:', '') | |
.trim() | |
); | |
var prevTime = parseInt(document.body.getAttribute('time')); | |
if (prevTime !== null && prevTime !== time) { | |
if (time === 0) { | |
this.reset(prevTime * 10); | |
} | |
} | |
document.body.setAttribute('time', time); | |
}, | |
__threads: [], | |
__threadRunner: function(caller) { | |
for (key in this.__threads) { | |
try { | |
this.__threads[key].apply(caller); | |
} catch (e) { | |
console.error(e); | |
this.destroy(); | |
break; | |
} | |
} | |
}, | |
__intervalId: -1, | |
}; | |
AI.init(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment