Today I'm publishing a simple implemntation of the Snake game written in Python. This is another easy game to learn Pygame.
The Source Code
The full and working source code is available here.
Even though the code is pretty short and we discussed the basics of pygame in the previous article, I stumbled accross a few things that I thought would be interesting to share.
No signum Function in Python
First, it may sound surprising, but Python doesn't have a signum function out of the box. I ended up writing the following code:
def sign(num): if num < 0: return -1 elif num == 0: return 0 else: return 1
Second, the Python language is so expressive. Consider the part in the game when we have to check whether the snake leaves the screen. Normally, we should write something like that:
def snake_is_on_screen(self): return self.head.x >= 0 and self.head.x <= SCREEN_WDITH - UNIT_LENGTH and self.head.y >= 0 and self.head.y <= SCREEN_HEIGHT - UNIT_SIZE
Instead, we can write:
def snake_is_on_screen(self): return (0 <= self.head.x <= SCREEN_WIDTH - UNIT_SIZE) and (0 <= self.head.y <= SCREEN_HEIGHT - UNIT_SIZE)
It's not a question what version is more readable.
Readability vs Being Short
Also, even in this simple project there were many places where I could simplfy and shorten things. However, those "adjustments" would make the code very hard to understand for others. For example, the
Pos class' purpose is to hold the x and y position.
Basically that class was not needed. It would've been better to store the coordinates in a list — that would let me make the
move_function a one-liner as folows.
DOWN = 1 UP = -3 RIGHT = 2 LEFT = -4 def move_head(self, direction): self.body[abs(direction) % 2] += UNIT_SIZE * sign(direction)
Wow, what's that? Without comments and deep diving into the code it's not possible to understand what's going on. The
abs(direction) % 2 part first determines which coordinate x (0) or y (1) to increase or decrease. It'll be increased if the direction is greater than zero. Otherwise, it'll be decreased, that's taken care of by the
sign function. Of course, this idea also required properly selected values for the
direction variable, see the constans above.
So a one-liner solution at the cost of the readbility. Even though this code looks cool, it's not worth it at all.
Instead of that, I wound up writing this:
def move_head(self, direction): if direction == UP: self.head.y += UNIT_SIZE if directon == DOWN: self.head.y -= UNIT_SIZE if direction == LEFT: self.head.x -= UNIT_SIZE if direction == RIGHT: self.head.x += UNIT_SIZE
This code, unlike the previous solution, immediatly reveals its intention.
As a rule of thumb, be always clear about your intention, even if you end up writing more code. It's worth the effort.