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,862