Last active
May 13, 2016 11:51
-
-
Save thelbane/2667910 to your computer and use it in GitHub Desktop.
Snake game solver/bot
This file contains hidden or 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
// A bot for this silly demo: http://www.webdeveloperjuice.com/demos/jquery/snake_jquery.html | |
// Compile with http://closure-compiler.appspot.com/home set to Advanced Optimization | |
// | |
// Automatically runs when compiled statement is pasted into console. Type "win()" to run it again. | |
(window['win'] = function () { | |
// direction mappings | |
var i, dirs = ['up', 'right', 'down', 'left'], | |
diffs = [[-1, 0], [0, 1], [1, 0], [0, -1]]; // don't ask me why the coords are ordered [y,x] | |
window['t'] = 1; // next Turn direction if we hit a wall (opposite of last turn direction) | |
window['m'] = 0; // My internally tracked direction | |
window['c'] = 14; // last drop Column | |
// reset the game (look at the game code to see what these affect) | |
clearInterval(ticker); | |
$('table').remove(); | |
renderBoard(); | |
renderFruitCell(); | |
direction = dirs[m]; | |
$('div.gameOver')['hide']()['css']('top', 0); | |
score = 0; | |
speed = 0; | |
// reset the snake | |
snakeHead = [10, i = c]; | |
snakeCells = []; | |
while (i > 6) { | |
snakeCells.push([10, i--]) | |
}; | |
// intercept game loop interval call | |
if (!window['o']) { | |
window['h'] = function(dir) { | |
var hit, nextCell = [snakeHead[0] + diffs[dir][0], snakeHead[1] + diffs[dir][1]]; | |
// check snake array for hits | |
$['each'](snakeCells, function (i, v) { | |
hit = hit || (v[0] == nextCell[0] && v[1] == nextCell[1]); | |
}); | |
return hit || nextCell[0] < 0 || nextCell[0] >= size || nextCell[1] < 0 || nextCell[1] >= size; // check for edge hit | |
}; | |
window['o'] = updateSnakeCell; | |
updateSnakeCell = function () { | |
// optimized max score pattern accounting for snake length | |
// we zigzag right to left but keep the top row empty to get back to the right | |
// if we are at the top and are about to turn left we check if we are more than square from the edge otherwise we start the return | |
var sx = snakeHead[1], | |
sy = snakeHead[0], | |
fx = fruitCell[1], | |
busyColumns = Math.ceil((snakeCells.length + 10) / (size-1)), // account for snake body length on return trip | |
upstroke; | |
upstroke = fx + busyColumns >= sx ? sx : fx + busyColumns + (1-(sx % 2)); // optimal time to move up from bottom row | |
var canReturn = (sx <= c-busyColumns) || sx == 0; // is there enough free space for a return trip? | |
m = sy == size - 1 ? (m == 2 ? 3 : (sx == upstroke || h(3) ? 0 : m)) : m; // bottom row steering logic | |
m = sy == 1 && m != 2 ? (m == 3 ? 2 : ((fx < sx || !canReturn) && sx != 1 ? 3 : m)) : m; // second from top row steering logic | |
if (sy == 0) { | |
if (m == 0) c = sx; | |
m = m == 0 ? 1 : (fx <= sx && (sx % 2) && (sx > c+busyColumns || sx >= size-1) ? 2 : m); // top row steering logic | |
if (m == 2) c = sx; // set the last drop Column | |
} | |
direction = dirs[m]; // set snake direction for game loop | |
o(); // call the original game loop function | |
}; | |
} | |
startGame(); | |
})(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
So it wins all the time? What about optimal solutions?