Skip to main content

snake.js

Created on Sat Jun 06 2020Last updated on Sat Jun 06 2020
/* global $*/
jQuery('body').append('<div id="board"></div><style>#board,body{overflow: hidden;z-index:99999999;background-color:#fff}#board{z-index:99999999;color:white; width:440px;height:440px;border:1px solid #000;}#highScore,#score,#timer{z-index:99999999;color:#fff}.apple,.snake{z-index:99999999;display:block;width:20px;height:20px;position:absolute;user-select:none}.snake{z-index:99999999;background-color:green;}#snake-head{z-index:99999999;background-color:#006400}.apple{z-index:99999999;background-color:red;}</style>');
// Set window sessionStorage to keep track of high scores (lowest time)
sessionStorage.setItem("highScore", 0);

// timer variables
var timer = $('#mega_menu_dd_31');
var timeStr;
var time;

// score variables
var scoreElement = $('#mega_menu_dd_11');
var score;
var highScoreElement = $('#mega_menu_dd_18');

// board variables
var board = $('#board');
board.rows = window.innerHeight / 20;
board.columns = window.innerWidth / 20;
var squareSize = 20;

// snake variables
var snake = {};
snake.speed = 10;

// apple
var apple;

// KeyCodes
var KEY = {
LEFT: 37,
UP: 38,
RIGHT: 39,
DOWN: 40
};

// interval variables
var updateInterval;
var timerInterval;

init();

function init() {
disableScrollingByKeyboard();
// initialize the snake
snake.body = [];
snake.head = makeSnakeSquare(localStorage.getItem("snakeRow"), localStorage.getItem("snakeColumn")).attr('id', 'snake-head');
snake.head.direction = "right";

// initialize the first apple
apple = makeApple();

//start timer ticking at 0
timer.text("Time: 0:00");
time = 0;
timerInterval = setInterval(updateTimer, 1000);

// set score to 0
scoreElement.text("Score: 0");
score = 0;

//high score element
highScoreElement.text("High Score : "+localStorage.getItem("highScore"));

// start update interval
updateInterval = setInterval(update, 100);

(function loop() {
setTimeout(function () {
score++;
loop()
}, 10000);
}());

// turn on keyboard inputs
$('body').on('keydown', setNextDirection);
}

function disableScrollingByKeyboard(){
window.addEventListener("keydown", function(e) {
// space, page up, page down and arrow keys:
if([32, 33, 34, 37, 38, 39, 40].indexOf(e.keyCode) > -1) {
e.preventDefault();
}
}, false);
}

/*
* On each update tick update each bubble's position and check for
* collisions with the walls.
*/
function update() {
moveSnake();

if (hasCollidedWithApple()) {
handleAppleCollision();
}

if (hasCollidedWithSnake() || hasHitWall()) {
endGame();
}
}

function moveSnake() {
// start at 1, the head is moved separately
for (var i = snake.body.length - 1; i >= 1; i--) {
var snakeSquare = snake.body[i];
var nextSnakeSquare = snake.body[i - 1];

snakeSquare.row = nextSnakeSquare.row;
snakeSquare.column = nextSnakeSquare.column;
snakeSquare.direction = nextSnakeSquare.direction;

localStorage.setItem("snakeRow", snakeSquare.row);
localStorage.setItem("snakeColumn", snakeSquare.column);
localStorage.setItem("snakeDirection", snakeSquare.direction);

repositionSquare(snakeSquare);
}

/* snake.nextDirection is set using keyboard input and only changes if the
next direction is perpendicular to snake.head.direction

only when the snake actually is making the turn does the next direction get
registered
*/
snake.head.direction = snake.nextDirection;
if (snake.head.direction === "left") {
snake.head.column--;
}
else if (snake.head.direction === "right") {
snake.head.column++;
}
else if (snake.head.direction === "up") {
snake.head.row--;
}
else if (snake.head.direction === "down") {
snake.head.row++;
}

repositionSquare(snake.head);
}

function hasCollidedWithApple() {
return snake.head.row === apple.row && snake.head.column === apple.column;
}
function handleAppleCollision() {
// Remove existing Apple and create a new one
console.log('apple eaten');
apple.remove();
apple = null;
makeApple();


var row = snake.tail.row;
var column = snake.tail.column;
if (snake.tail.direction === "left") {
column++;
}
else if (snake.tail.direction === "right") {
column--;
}
else if (snake.tail.direction === "up") {
row++;
}
else if (snake.tail.direction === "down") {
row--;
}
makeSnakeSquare(row, column);

score++;
score++;
scoreElement.text("Score: " + score);
}

function hasCollidedWithSnake() {
for (var i = 1; i < snake.body.length; i++) {
if (snake.head.row === snake.body[i].row && snake.head.column === snake.body[i].column) {
console.log('snake collision');
return true;
}
}
}
function hasHitWall() {
return snake.head.row > board.row || snake.head.row < 0 || snake.head.column > board.columns || snake.head.column < 0;
}

function makeSnakeSquare(row, column) {
// make the snake jQuery Object
var snakeSquare = $('<div>').addClass('snake');

// set snake position properties
snakeSquare.column = column;
snakeSquare.row = row;
repositionSquare(snakeSquare);

// add snakeSquare to body and set a new tail
snake.body.push(snakeSquare);
snake.tail = snakeSquare;

board.append(snakeSquare);

return snakeSquare;
}

function makeApple() {
// make the snake jQuery Object if one doesn't already exist
if (!apple) {
apple = $('<div>').addClass('apple');

// set snake position properties
var randomPosition = getRandomAvailablePosition();
apple.column = randomPosition.column;
apple.row = randomPosition.row;
repositionSquare(apple);

board.append(apple);
}

return apple;
}
function getRandomAvailablePosition() {

var spaceIsAvailable = false;
var randomPosition = {};

while (!spaceIsAvailable) {
randomPosition.column = Math.floor(Math.random() * board.rows);
randomPosition.row = Math.floor(Math.random() * board.rows);
spaceIsAvailable = true;

snake.body.forEach(function(snakeSquare) {
if (snakeSquare.row === randomPosition.row && snakeSquare.column === randomPosition.column) {
spaceIsAvailable = false;
}
});

}

return randomPosition;
}

function setNextDirection(event) {
var keyPressed = event.which;
if (keyPressed === KEY.LEFT && snake.head.direction !== "left" && snake.head.direction !== "right") {
snake.nextDirection = "left";
}
else if (keyPressed === KEY.RIGHT && snake.head.direction !== "left" && snake.head.direction !== "right") {
snake.nextDirection = "right";
}
else if (keyPressed === KEY.UP && snake.head.direction !== "up" && snake.head.direction !== "down") {
snake.nextDirection = "up";
}
else if (keyPressed === KEY.DOWN && snake.head.direction !== "up" && snake.head.direction !== "down") {
snake.nextDirection = "down";
}
}

function updateTimer() {
time++;

var secondsOnes = (time % 60) % 10;
var secondsTens = Math.floor((time % 60) / 10);
var minutes = Math.floor(time / 60);

timeStr = minutes + ":" + secondsTens + secondsOnes;
timer.text("Time: " + timeStr);
}
function endGame() {
// turn off intervals
clearInterval(updateInterval);
clearInterval(timerInterval);

// turn off keyboard input
$('body').off('keydown');

// clear board of all elements
board.empty();

// reset the apple
apple = null;

// calculate high score and restart the game
calculateAndDisplayHighScore();
setTimeout(function() { init(); }, 500);
}
function calculateAndDisplayHighScore() {
var highScore = localStorage.getItem("highScore");

if (score > highScore) {
sessionStorage.setItem("highScore", score);
highScore = score;
highScoreElement.text("High Score: " + highScore);
localStorage.setItem("highScore", highScore);
alert("New High Score! Your Score :" + highScore);

}
}

////////////////////////////////////////////////////////////////////////////////
///////////////////////// HELPER FUNCTIONS /////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////


/* Called on each update to move the snake to it's next position. Also called
by makeApple when a new apple is created */
function repositionSquare(square) {
square.css('left', square.column * squareSize + 20);
square.css('top', square.row * squareSize + 20);
}