Gra snake w javascript

Ostatnio odkopałam na dysku prostą grę snake w javascript. Pragnę się z Wami podzielić kodem źródłowym.
Plik html:

<!doctype html>
<html>
    <head>
        <meta charset="utf-8">
        <title>snake</title>
		<meta name="description" content="">
		<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js"></script>
		<script type="text/javascript" src="js/rAF.js"></script>
		<script type="text/javascript" src="js/render_table.js"></script>
		<script type="text/javascript" src="js/snake.js"></script>
		<script type="text/javascript" src="js/input.js"></script>
		<style>
			table {
				position: fixed;
				top:0;
				bottom: 0;
				left: 0;
				right: 0;
				width: 100%;
				height: 100%;
			}
		</style>
	</head>
    <body>
	<script>
	var gra = new game(new gamescreen('sdfsdg',20,20));
	</script>
    </body>
</html>
Plik rAF.js:
(function() {
    var lastTime = 0;
    var vendors = ['ms', 'moz', 'webkit', 'o'];
    for(var x = 0; x < vendors.length && !window.requestAnimationFrame; ++x) {
        window.requestAnimationFrame = window[vendors[x]+'RequestAnimationFrame'];
        window.cancelAnimationFrame = window[vendors[x]+'CancelAnimationFrame'] 
                                   || window[vendors[x]+'CancelRequestAnimationFrame'];
    }
 
    if (!window.requestAnimationFrame)
        window.requestAnimationFrame = function(callback, element) {
            var currTime = new Date().getTime();
            var timeToCall = Math.max(0, 16 - (currTime - lastTime));
            var id = window.setTimeout(function() { callback(currTime + timeToCall); }, 
              timeToCall);
            lastTime = currTime + timeToCall;
            return id;
        };
 
    if (!window.cancelAnimationFrame)
        window.cancelAnimationFrame = function(id) {
            clearTimeout(id);
        };
}());
Plik render_table.js:
var gamescreen = function(id,width,height)
{
	this.id = id;
	this.width = width;
	this.height = height;
	var html = '<table id="'+this.id+'">';
	for(var x=0; x < this.width; x++)
	{
		html += '<tr>';
		for(var y=0; y < this.height; y++)
		{
			html += '<td></td>';
		}
		html += '</tr>';
	}
	html += '</table>';
	$('body').append(html);
};
gamescreen.prototype.clear_screen = function()
{
	$('#'+this.id+' td').removeAttr('style');
};
gamescreen.prototype.draw_snake = function(snake)
{
	$('#'+this.id+' tr').eq(snake.y).find('td').eq(snake.x).css('background-color','green');
};
gamescreen.prototype.draw_snake_tail = function(snake)
{
	$('#'+this.id+' tr').eq(snake.y).find('td').eq(snake.x).css('background-color','OliveDrab');
};
gamescreen.prototype.draw_apple = function(apple)
{
	$('#'+this.id+' tr').eq(apple.y).find('td').eq(apple.x).css('background-color','red');
};
Plik snake.js:
var game = function(gamescreen)
{
	this.gamescreen = gamescreen;
	this.snake = {
		x:Math.floor(gamescreen.width/2),
		y:Math.floor(gamescreen.height/2),
		dir:8,
		len:3,
		tail:[]
	};
	this.apples = [{x:Math.floor(Math.random()*gamescreen.width),y:Math.floor(Math.random()*gamescreen.height)}];
	this.animate();
	this.gametick();
}
game.prototype.snake_up = function()
{
	this.snake.dir = 8;
};
game.prototype.snake_down = function()
{
	this.snake.dir = 2;
};
game.prototype.snake_left = function()
{
	this.snake.dir = 4;
};
game.prototype.snake_right = function()
{
	this.snake.dir = 6;
};
game.prototype.draw_objects = function()
{
	this.gamescreen.clear_screen();
	this.gamescreen.draw_snake(this.snake);
	for(var i = this.snake.tail.length-1; i >= 0; i-=1)
	{
		this.gamescreen.draw_snake_tail(this.snake.tail[i]);
	}
	for(var i = this.apples.length-1; i >= 0; i-=1)
	{
		this.gamescreen.draw_apple(this.apples[i]);
	}
};
game.prototype.animate = function()
{
	this.draw_objects();
	var g = this;
	requestAnimationFrame(function(){
		g.animate();
	});
};
game.prototype.gametick = function()
{
	var oldx = this.snake.x, oldy = this.snake.y;
	if(this.snake.dir==8)
	{
		this.snake.y -= 1;
	}
	if(this.snake.dir==2)
	{
		this.snake.y += 1;
	}
	if(this.snake.dir==6)
	{
		this.snake.x += 1;
	}
	if(this.snake.dir==4)
	{
		this.snake.x -= 1;
	}
	this.snake.x %= this.gamescreen.width;
	this.snake.y %= this.gamescreen.height;

	for(var i = this.apples.length-1; i >= 0; i-=1)
	{
		if(this.snake.x==this.apples[i].x && this.snake.y==this.apples[i].y)
		{
			this.snake.len += 1;
			this.apples[i].x = Math.floor(Math.random()*this.gamescreen.width);
			this.apples[i].y = Math.floor(Math.random()*this.gamescreen.height);
		}
	}
	for(var i = this.snake.tail.length-1; i >= 0; i-=1)
	{
		if(this.snake.x==this.snake.tail[i].x && this.snake.y==this.snake.tail[i].y)
		{
			this.snake.len = i+1;
			break;
		}
	}
	if(this.snake.len>0)
	{
		this.snake.tail.unshift({x:oldx,y:oldy});
		while(this.snake.tail.length>this.snake.len)
		{
			this.snake.tail.pop();
		}
	}
	var g = this;
	setTimeout(function(){
		g.gametick();
	},500);
};
Plik input.js:
$(document).ready(function() {
	$("body").bind("keydown",function(e){
		var value = this.value + String.fromCharCode(e.keyCode);
		if(e.keyCode==13) {
			alert('Enter');
		}
		if(e.keyCode==38) {
			gra.snake_up();
		}
		if(e.keyCode==40) {
			gra.snake_down();
		}
		if(e.keyCode==37) {
			gra.snake_left();
		}
		if(e.keyCode==39) {
			gra.snake_right();
		}
		if(e.keyCode==27) {
			alert('esc');
		}
	});
});