Skip to content

Instantly share code, notes, and snippets.

Created July 5, 2016 14:33
Show Gist options
  • Save anonymous/785b708c8faf76a9afeaa18337062ede to your computer and use it in GitHub Desktop.
Save anonymous/785b708c8faf76a9afeaa18337062ede to your computer and use it in GitHub Desktop.
Dodgy game AI
/**
* @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