Skip to content

Instantly share code, notes, and snippets.

@thelbane
Last active May 13, 2016 11:51
Show Gist options
  • Save thelbane/2667910 to your computer and use it in GitHub Desktop.
Save thelbane/2667910 to your computer and use it in GitHub Desktop.
Snake game solver/bot
// 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();
})();
@cirosantilli
Copy link

So it wins all the time? What about optimal solutions?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment