Snake is a game that the vast majority of us have played on those old Nokia telephones. It’s likewise an exemplary coding challenge for learning another programming language. As confounded as it might appear from the beginning, it’s preferably simple to code and takes less over 50 lines. We should attempt to reproduce this game in the terminal.
You can look at the source code and review here.
Declare Dependencies
We will utilize the arbitrary and condemnations libraries to take care of us. arbitrary is a module that will permit us to give irregular situations to the organic products that will bring forth on the guide. curses is the means by which we will deal with the UI and game mechanics.
Import these two libraries by adding the accompanying lines at the highest point of the main.py document:
import random
import curses

Initialize the screen
Underneath our imports how about we skirt a line and start our game. To start with, we need to some way or another pronounce that our terminal can be utilized as a UI. We’ll utilize condemnations to set a cursor, screen width, screen tallness, snake speed and empower keys.
# Define the screen
s = curses.initscr()
# Set the cursor to 0 so it's invisible
curses.curs_set(0)
# Get the width and the height
sh, sw, = s.getmaxyx()
# Create a new window from the height and width at the top left corner
w = curses.newwin(sh, sw, 0, 0)
# Enable all keys
w.keypad(1)
# Determine how fast the snake moves
w.timeout(100)
Amazing! We have characterized the screen aspects and set the cursor to be undetectable in the upper left corner. How about we continue on to the snake rationale. We’ll utilize these factors and definitions while making the remainder of the program.
Game of Thrones Season 8 Episode 5 – All that happened, Where and How to watch Online
Initialize the snake and food
Skip a line from the above code and let’s define the snake, its position and food.
# The snake's initial X position
snk_x = sw/4
# The snake's initial Y position
snk_y = sh/2
# Create the initial snake body parts
snake = [
[snk_y, snk_x],
[snk_y, snk_x - 1],
[snk_y, snk_x - 2]
]
# Set the first food item at the center of the screen
food = [sh/2, sw/2]
Consider the snake a gathering of squares. The main square is the head. The head is at the underlying snk_x and snk_y positions. This implies that the following body part must be at 1 less X situation than the head. The following body part is 2 less X from the head. The following 3, etc. Each rundown thing in the snake list is an underlying body part position.
How about we add that food to the screen.
# Add the food to the screen
w.addch(int(food[0]), int(food[1]), curses.ACS_PI)
In the above code, we utilize the food’s X and Y positions just as the ASCII PI character to set the principal food. We are involving PI image as the food.
How about we add the underlying bearing of the snake. We’ll set it to go right.
key = curses.KEY_RIGHT
Handle movement and game logic
Presently, we will deal with the game rationale. We need the accompanying code to run ceaselessly, so we will put it inside a boundless circle:
# Infinite loop repeating every time the snake moves
while True:
next_key = w.getch()
key = key if next_key == -1 else next_key
The above code really looks at each next key. On the off chance that the following key is equivalent to – 1, we leave the critical variable with no guarantees, in any case we set the vital variable to the next_key esteem.
How about we handle the individual losing. How would we lose in snake?
# Infinite loop repeating every time the snake moves
while True:
next_key = w.getch()
wrong_operation = True if (next_key==-1 or next_key==curses.KEY_DOWN and key == curses.KEY_UP\
or key==curses.KEY_DOWN and next_key == curses.KEY_UP \
or next_key==curses.KEY_LEFT and key == curses.KEY_RIGHT\
or key==curses.KEY_LEFT and next_key == curses.KEY_RIGHT) else False
key = key if wrong_operation else next_key
# Handle snake losing
if snake[0][0] in [0, sh] or snake[0][1] in [0, sw] or snake[0] in snake[1:]:
# Close the curses window and exit the program
curses.nocbreak()
s.keypad(False)
curses.echo()
curses.endwin()
print("Oops, you lost!")
break
quit()
The a few lines of this piece tests each conceivable mix we can move and where we are as of now moving. We do this to ensure the game doesn’t stop if, for instance, we are going ahead and we press to move in reverse.
In the above code, we likewise characterize an if explanation to check if:
The Y position of the snake is beyond the screen
The X place of the snake is beyond the screen
The snake is in itself
On the off chance that any of the above occur, we close the condemnations window and quit the program.
Presently, how about we decide the new top of the snake in light of our development.
while True:
# Code that we wrote before...
new_head = [snake[0][0], snake[0][1]]
# Player presses key down
if key == curses.KEY_DOWN:
new_head[0] += 1
# Player presses key up
if key == curses.KEY_UP:
new_head[0] -= 1
# Player presses key left
if key == curses.KEY_LEFT:
new_head[1] -= 1
# Player presses key right
if key == curses.KEY_RIGHT:
new_head[1] += 1
# Insert the new head of the snake
snake.insert(0, new_head)
The code above is the means by which we really control the snake. We start by taking the old top of the snake and afterward checking for what key is being squeezed. On the off chance that key down is squeezed, we take the snake’s Y position and add 1 to it. In the event that key up is squeezed, we take the snake’s Y position and deduct 1. On the off chance that key left is squeezed, we take the snake’s X position and take away 1. On the off chance that key right is squeezed, we take the snake’s X position and add 1.
After so much, we get something like this:
Handle food logic
Now let’s the handle the snake running into the food. The following code should go into the while True
statement, below the code above.
# Check if the snake ran into the food
if snake[0] == food:
# Since the snake ate the food, we need to set a new food position
food = None
while food is None:
# Randomize the position of the new food
nf = [
random.randint(1, sh-1),
random.randint(1, sw-1)
]
# Set the new food is the new food is not in the snake
food = nf if nf not in snake else None
# Add the new food position to the screen
w.addch(food[0], food[1], curses.ACS_PI)
else:
# Handle snake not running into the food
tail = snake.pop()
w.addch(int(tail[0]), int(tail[1]), ' ')
try:
w.addch(int(snake[0][0]), int(snake[0][1]), curses.ACS_CKBOARD)
except:
print("Oops, you lost!")
In the above code, we check assuming the snake has ran into the food. In the event that it has, we really want to set another food position and make the snake longer. We utilize the screen width and tallness aspects to randomize facilitates for the new food position. These arbitrary directions get an opportunity of landing right where the snake is. So to stay away from that disarray we possibly set the new food in the event that it’s not on the snake. In any case, we simply rehash the circle.
Notice at the base we wrap the rationale for adding a body part in an attempt with the exception of square. This is a hacky approach to ensuring that when we lose the game, the program says something and doesn’t simply crash.
At last, regardless, we’re adding the top of the snake to the screen.
The final product:
We are done! This is what your code should now look like:
import random
import curses
s = curses.initscr()
curses.curs_set(0)
sh, sw = s.getmaxyx()
w = curses.newwin(sh, sw, 0, 0)
w.keypad(1)
w.timeout(100)
snk_x = sw/4
snk_y = sh/2
snake = [
[snk_y, snk_x],
[snk_y, snk_x-1],
[snk_y, snk_x-2]
]
food = [sh/2, sw/2]
w.addch(int(food[0]), int(food[1]), curses.ACS_PI)
key = curses.KEY_RIGHT
while True:
next_key = w.getch()
wrong_operation = True if (next_key==-1 or next_key==curses.KEY_DOWN and key == curses.KEY_UP\
or key==curses.KEY_DOWN and next_key == curses.KEY_UP \
or next_key==curses.KEY_LEFT and key == curses.KEY_RIGHT\
or key==curses.KEY_LEFT and next_key == curses.KEY_RIGHT) else False
key = key if wrong_operation else next_key
if snake[0][0] in [0, sh] or snake[0][1] in [0, sw] or snake[0] in snake[1:]:
curses.nocbreak()
s.keypad(False)
curses.echo()
curses.endwin()
print("Oops, you lost!")
break
quit()
new_head = [snake[0][0], snake[0][1]]
if key == curses.KEY_DOWN:
new_head[0] += 1
if key == curses.KEY_UP:
new_head[0] -= 1
if key == curses.KEY_LEFT:
new_head[1] -= 1
if key == curses.KEY_RIGHT:
new_head[1] += 1
snake.insert(0, new_head)
if snake[0] == food:
food = None
while food is None:
nf = [
random.randint(1, sh-1),
random.randint(1, sw-1)
]
food = nf if nf not in snake else None
w.addch(food[0], food[1], curses.ACS_PI)
else:
tail = snake.pop()
w.addch(int(tail[0]), int(tail[1]), ' ')
try:
w.addch(int(snake[0][0]), int(snake[0][1]), curses.ACS_CKBOARD)
except:
print("Oops, you lost!")
Now you have control over this code. Go ahead and tinker with it to see if you can find ways to make it more fun. Here are some ideas:
- Add a play again option: Demo + Code
- Add colors to the snake: Demo + Code
- Create a score: Demo + Code
Enjoy playing and getting those apples! Happy hacking!