R
E
A
C
T
O
xamples
epeat
ode
pproach
ptimize
est
{ Snake }
Background
In the popular game Snake, a snake moves across a two-dimensional grid seeking apples to eat. Every time the snake eats an apple, it grows in size.
The challenge is to eat as many apples as possible before the snake collides with itself or the boundaries of the playing field.
When the snake eats an apple, it may grow at the head, or at its tail - that's up to whoever made the game
The Question
Create your own implementation of Snake using Object Oriented JavaScript!
The snake should, at minimum, have a method to move (imagine this method being called every "tick"), and a method to grow whenever it eats an apple.
Don't worry about the specifics of rendering the Snake - focus on the data.
If you get done early, implement collision detection as well :)
Approach
- A snake with a head and a tail...hrm, this sounds familiar...
- You guessed it: a snake is a linked list!
- Whenever the snake moves, the head's x and y coordinates should increment in the direction of the current movement
- Each subsequent node in the Snake should become equal to the previous node's x and y coordinate
- When the snake grows, simply implement addToHead with the apple's coordinates
Possible Solution
function Vector (x, y) {
this.x = x;
this.y = y;
this.next = null;
}
function Snake () {
this.head = new Vector(0, 0);
this.direction = new Vector(0, 1); // initially moving up
}
Snake.prototype.move = function (newDirection) { /* next slide */ };
Snake.prototype.grow = function (apple) { /* next slide */ };
Possible Solution con't
Snake.prototype.move = function (newDirection) {
this.direction = newDirection || this.direction;
var prevX = this.head.x,
prevY = this.head.y,
current = this.head.next;
this.head.x += this.direction.x;
this.head.y += this.direction.y;
while (current) {
var curX = current.x,
curY = current.y;
current.x = prevX;
current.y = prevY;
prevX = curX;
prevY = curY;
current = current.next;
}
};
Snake.prototype.grow = function (apple) {
var newHead = new Node(apple.x, apple.y);
newHead.next = this.head;
this.head = newHead;
};
Possible Solution ES2015
class Vector {
constructor (x, y) {
this.x = x;
this.y = y;
this.next = null;
}
}
class Snake {
constructor () {
this.head = new Vector(0, 0);
this.direction = new Vector(0, 1)
}
move (newDirection) { /* next slide */ }
grow (apple) { /* next slide */ }
}
Possible Solution ES2015 con't
move (newDirection) {
this.direction = newDirection || this.direction;
let prevX = this.head.x,
prevY = this.head.y,
current = this.head.next;
this.head.x += this.direction.x;
this.head.y += this.direction.y;
while (current) {
let [curX, curY] = [current.x, current.y];
[current.x, current.y] = [prevX, prevY];
[prevX, prevY] = [curX, curY];
current = current.next;
}
}
grow (apple) {
let newHead = new Vector(apple.x, apple.y);
newHead.next = this.head;
this.head = newHead;
}
Conclusion
REPL.IT solutions
Linked Lists are very popular interview topics - make sure to brush up!
ES6 introduces some cool syntax for object-oriented programming
Destructured assignment makes it easier to swap temporary values
Snake
By Tom Kelly
Snake
Technical interview problem to implement a the game Snake
- 1,849