Snake Game with Deep Learning

Developing a neural network to play a snake game usually consists of three steps.

  1. Training data generation
  2. Training neural network
  3. Testing

The full code can be found here

In this tutorial, I will guide you to generate training data. To do this, first, we need to develop a snake game for which you can follow this blog.

Training data consists of inputs and corresponding outputs. Here, I have used the following inputs and outputs.

Input is comprised of 7 nodes:

  1. Is left blocked or is there any obstacle in left ( 1 or 0)
  2. is front blocked or is there any obstacle in front (1 or 0)
  3. Is right blocked  or is there any obstacle in right(1 or 0)
  4. Apple direction vector from snake (X)
  5. Apple direction vector from snake (Y)
  6. Snake’s current direction vector (X)
  7. Snake’s current direction vector (Y)

our input data will look like this:

The output is comprised of 3 node:

  1.  [1,0,0] will move snake left
  2.  [0,1,0] will continue snake in same direction
  3.  [0,0,1] will move snake right

Now the big question, how to generate this data? You can sit and play as many games as you can, but it is always good when you can generate data automatically. Let’s see how to do this.

Generating Training Data

Here I have generated training data automatically. To do this I have used angle between snake and apple. On the basis of that angle, I have decided in which direction snake should move. First, let’s calculate these.

Calculating angle b/w snake and apple:

To calculate the angle between snake and apple we only require two parameters, snake position and apple position.

In the following code, I have first calculated the snake’s current direction vector and Apple’s direction from the snake’s current position. Snake direction vector can be calculated by simply subtracting 0th index of the snake’s list from the 1st index. And to calculate apple direction from the snake, just subtract 0th index of snake’s list from Apple’s position.

Then normalize these direction vectors and calculate the angle with the help of the math library. The code is as follows:

After calculating the angle, next thing is to decide in which direction snake should move.

Calculating direction according to the angle:

If above-calculated angle > 0, this means Apple is on the right side of the snake. So snake should move to the right. For  < 0, move left and =0 means continue in same direction. I have used 1, – 1 and 0 for the right, left and front respectively.

I have used the following steps to get the correct button direction (up, down, right, left or 3, 2, 1, 0 respectively) for the next step of the snake.

  1. First, I have calculated the snake’s current direction.
  2. Then to turn the snake to the left or right direction, I have calculated left direction vector or right direction vector from snake’s current direction vector.
  3. Then I have converted the above-calculated direction vector into the button direction.

Now, for every step, angle and corresponding next direction are calculated and snake moves according to that. And for each step inputs and outputs are calculated which are appended to a list of training data.To generate training data, we need to keep a record of 7 inputs and 3 outputs for every step the snake takes. First, let’s see how I have calculated the inputs for every step the snake takes.

  1. To check if the direction is blocked, we look one step ahead in each direction.
  2. Snake direction vector = Snake’s Head (0th index) – Snake’s 1st index
  3. Apple direction from the snake = Apple’s position – Snake’s head position (See the figure below)

For every step, the output is generated by first calculating the direction for the given snake and apple position, using angle between them. Now, we need to convert our directions( -1, 0 or 1 ) to output(Y), a one hot vector. For every predicted direction we need to see that if that direction is blocked or not and according to that create output (Y) for training data. The code given below seems to be a bit longer but it calculates our training data output (Y).

Here, I have used 1000 games for generating training data, each of which consists of 2000 steps. For every game, I have re-initialized snake position, apple position, and score. Then, created two empty lists, one for input training data(X) and another output training data(Y), those will contain our whole training data.The code is as follows:

You might have got some feeling about the training data generation for the snake game with deep learning. In the next blog, we will use this data to train and test our neural network. Hope you enjoy reading.

If you have any doubt/suggestion please feel free to ask and I will do my best to help or improve myself. Good-bye until next time.

4 thoughts on “Snake Game with Deep Learning

  1. parz3val

    Hi!

    Thank you for creating this series of blog posts. Its helping me a lot with my project. I just noticed something in your code and I’m not sure if it is a bug.

    def is_direction_blocked(snake_position, current_direction_vector):
    next_step = snake_position[0]+ current_direction_vector
    snake_start = snake_position[0]
    if collision_with_boundaries(snake_start) == 1 or collision_with_self(snake_position) == 1:
    return 1
    else:
    return 0

    This is a part of the script that generates the test dataset. I noticed that the test dataset produced by the script are all 0’s even if the snake is on the edge or near itself for the is_blocked fields. I modified this part of the script to fix it.

    def is_direction_blocked(snake_position, current_direction_vector):
    next_step = snake_position[0]+ current_direction_vector
    next_snake_position = copy.deepcopy(snake_position)
    next_snake_position.insert(0,list(next_step))
    next_snake_position.pop()
    if collision_with_boundaries(next_step) == 1 or collision_with_self(next_snake_position) == 1:
    return 1
    else:
    return 0

    In the modified script i took into consideration the future step that the snake will take and check if it will collide with itself or the boundaries. Then again I’m not sure if it was a bug or intentional.

    Thank you!

    Reply
    1. kang & atul Post author

      Thanks!
      Yes it was intentional as i have already moved the snake 1 step in the generate_training_data() function before blocked_directions() function. So, if you again move it by 1 step in the is_direction_blocked() function, it will be 2 steps ahead. If u want to do it by your way, then call play_game() after the blocked_directions() function.

      Reply
  2. Cyril

    I am stumped on finding the snake’s current direction vector and Apple’s direction from the snake’s current position. The formula doesn’t make sense and I don’t understand the reason for normalizing the vectors. Can you show a diagram explaining the formula further?

    Thanks

    Reply
  3. mawt

    1) angle, snake_direction_vector, apple_direction_vector_normalized, snake_direction_vector_normalized = angle_with_apple(snake_position, apple_position)
    2) direction, button_direction = generate_random_direction(snake_position, angle)
    3) current_direction_vector, is_front_blocked, is_left_blocked ,is_right_blocked = blocked_directions(snake_position)
    4) direction, button_direction, training_data_y = generate_training_data_y(snake_position, angle_with_apple, button_direction, direction, training_data_y, is_front_blocked, is_left_blocked ,is_right_blocked)

    Where does the argument “angle_with_apple” on line 4 come from ? Did you mean “angle” instead ?

    Reply

Leave a Reply