Course Content
Building a Classic Snake Game
Snake Movement
To achieve movement, we need to update the snake's position based on its current direction. To do this we need to add direction (right, left, up, down) to the s
Updating positions
To update positions we will use zip()
function and generator expression that we will convert to tuple.
zip()
is a built-in function that takes iterables (such as lists, tuples, or strings) as arguments and returns an iterator that produces tuples where the i-th tuple contains the i-th element from each of the input iterables. The returned iterator stops when the shortest input iterable is exhausted.
Note
It might seems hard to understand but it is really quite simple, look at the example below.
In this example, zip()
combines the numbers list and the letters list element-wise and returns an iterator that yields tuples. We need it to update the position of snake segments.
Updating the snake head position
We represent direction and position using tuples. To derive the new position, we simply add the first element of the direction tuple to the first element of the position tuple, and then repeat this process for the second elements.
After obtaining the two new tuples (10, 1) and (10, 0), the final step is to add their respective values together and combine them into a single tuple, resulting in (11, 10).
Great! Now let's think what will happen if we applied our algorithms to the head of the snake. The problem is that if we call this function for each iteration of our game only head of the snake will move and its body will stay in place.
Note
While our snake moves forward, its body stays at the same position it was before.
To address this issue, we need to update the positions of the body segments. We'll begin iterating from the tail, setting each position to the previous one until we reach the head of the snake. Look at the example below:
The value of the last element at index 3, initially (0, 4), is now updated to (0, 3) with the value of the element at index 2. Similarly, the value of the previous element at index 2, originally (0, 3), is now (0, 2) with the value of the element at index 1. Finally, the values of the element at index 1 correspond to those of the snake's head. If we combine this with the updating the head of the snake we will get:
Boundary Wrapping
If you watch the animation of our snake's movement above, you'll notice it slithers out of view and keeps on going beyond the boundaries of the playing field. We can fix it by checking the collision of the snake head with invisible "walls" or we can approach this issue in amore creative way.
Note
In this loop that runs 10 times, each time
i
is calculated modulo 3 to keep its value within the range of 0 to 2.
The solution lies in the example above, we can use %
operator to wrap our snake and limit its position values to the game field size. We can use zip()
function again and it will look something like this:
The position increases from (9, 9) to (10, 9). However, since the field size is (10, 10), the x
value of the position wraps around and resets to zero. As a result, our snake's movement pattern will look like this:
Task
- Implement the move function.
- Update the positions of the snake's body segments. Use a reverse range loop to iterate over the snake segments starting from the tail up to, but not including, the head. Within the loop, update the position of each segment to the position of the segment in front of it.
- Update the positions of the snake's head based on current direction. After updating the segment positions, calculate the new position of the head. Remember that the head is the first element in the snake list.
- Handle the boundary wrapping when the snake moves beyond the edges of the game field. Use the modulo operation to wrap the new head position within the boundaries of the game field.
Thanks for your feedback!
To achieve movement, we need to update the snake's position based on its current direction. To do this we need to add direction (right, left, up, down) to the s
Updating positions
To update positions we will use zip()
function and generator expression that we will convert to tuple.
zip()
is a built-in function that takes iterables (such as lists, tuples, or strings) as arguments and returns an iterator that produces tuples where the i-th tuple contains the i-th element from each of the input iterables. The returned iterator stops when the shortest input iterable is exhausted.
Note
It might seems hard to understand but it is really quite simple, look at the example below.
In this example, zip()
combines the numbers list and the letters list element-wise and returns an iterator that yields tuples. We need it to update the position of snake segments.
Updating the snake head position
We represent direction and position using tuples. To derive the new position, we simply add the first element of the direction tuple to the first element of the position tuple, and then repeat this process for the second elements.
After obtaining the two new tuples (10, 1) and (10, 0), the final step is to add their respective values together and combine them into a single tuple, resulting in (11, 10).
Great! Now let's think what will happen if we applied our algorithms to the head of the snake. The problem is that if we call this function for each iteration of our game only head of the snake will move and its body will stay in place.
Note
While our snake moves forward, its body stays at the same position it was before.
To address this issue, we need to update the positions of the body segments. We'll begin iterating from the tail, setting each position to the previous one until we reach the head of the snake. Look at the example below:
The value of the last element at index 3, initially (0, 4), is now updated to (0, 3) with the value of the element at index 2. Similarly, the value of the previous element at index 2, originally (0, 3), is now (0, 2) with the value of the element at index 1. Finally, the values of the element at index 1 correspond to those of the snake's head. If we combine this with the updating the head of the snake we will get:
Boundary Wrapping
If you watch the animation of our snake's movement above, you'll notice it slithers out of view and keeps on going beyond the boundaries of the playing field. We can fix it by checking the collision of the snake head with invisible "walls" or we can approach this issue in amore creative way.
Note
In this loop that runs 10 times, each time
i
is calculated modulo 3 to keep its value within the range of 0 to 2.
The solution lies in the example above, we can use %
operator to wrap our snake and limit its position values to the game field size. We can use zip()
function again and it will look something like this:
The position increases from (9, 9) to (10, 9). However, since the field size is (10, 10), the x
value of the position wraps around and resets to zero. As a result, our snake's movement pattern will look like this:
Task
- Implement the move function.
- Update the positions of the snake's body segments. Use a reverse range loop to iterate over the snake segments starting from the tail up to, but not including, the head. Within the loop, update the position of each segment to the position of the segment in front of it.
- Update the positions of the snake's head based on current direction. After updating the segment positions, calculate the new position of the head. Remember that the head is the first element in the snake list.
- Handle the boundary wrapping when the snake moves beyond the edges of the game field. Use the modulo operation to wrap the new head position within the boundaries of the game field.