I've been reading Dive Into Python and I needed to actually program something before I forget everything I learned. So, this is my first Python project (apart from trying the basics and playing with console).I first wrote this using lots of globals but that looked stupid so I rewrote it as a class. It was more-or-less main loop that called restart_game() which reset variables. But, I had self everywhere (eg. before every x, is this normal?) and that seemed weird so I rewrote it. Now I have run_game() which runs single game and is called from infinite loop.Still, this being my first real Python program, I'm sure there's room for improvement.snake.py'''Simple snake game using pygame.'''import pygameimport random#              R    G    BWHITE      = (255, 255, 255)BLACK      = (  0,   0,   0)RED        = (255,   0,   0)GREEN      = (  0, 210,   0)DARK_GREEN = (  0, 155,   0)DARK_GRAY  = ( 40,  40,  40)BG_COLOR = BLACKHEAD_COLOR = GREENSNAKE_COLOR = DARK_GREENFONT_SIZE = 36# (dx, dy)LEFT = (-1, 0)RIGHT = (1, 0)UP = (0, -1)DOWN = (0, 1)key_mapping = { pygame.K_LEFT : LEFT, pygame.K_a : LEFT,                 pygame.K_RIGHT : RIGHT, pygame.K_d : RIGHT,                pygame.K_UP : UP, pygame.K_w : UP,                pygame.K_DOWN : DOWN, pygame.K_s : DOWN }class Snake():    Simple snake game.    title - game title    width - window width    height - window height    cell_size - size of one tile        height and width need to be multiples of cell_size    game_speed - must be >1        def __init__(self, title=Snake, width=640, height=480, cell_size=20, game_speed=8):        self.width = width        self.height = height        self.cell_size = cell_size        if height % cell_size != 0 or width % cell_size != 0:            raise ValueError(height and width need to be multiples of cell_size)        self.game_speed = game_speed        if game_speed < 1:            raise ValueError(game_speed must be bigger than 0)        pygame.init()        self.font = pygame.font.Font(None, FONT_SIZE)        self.clock = pygame.time.Clock()        self.display = pygame.display.set_mode((width, height))        pygame.display.set_caption(title)        self.display.fill(BG_COLOR)    def loop_games(self):        Start new game and keep restarting until player quits.        while True:            self.run_game()    def run_game(self):        Run one game.        row_count = self.height/self.cell_size        col_count = self.width/self.cell_size        x, y = self.get_starting_point()        snake = [(x, y), (x - 1, y), (x - 2, y)]        dx, dy = RIGHT        apple_x, apple_y = self.generate_apple()        while True:            current_dx, current_dy = dx, dy            for event in pygame.event.get():                if event.type == pygame.QUIT:                    pygame.quit()                    raise SystemExit(0)                elif event.type == pygame.KEYDOWN:                    if event.key in key_mapping:                        new_dx, new_dy = key_mapping[event.key]                        # So you can't go from right to left and eat yourself.                        # You can't check against new_dx/new_dy because it                        # could be changed multiple times (eg. going right                        # and pressing up and left quickly).                        if new_dx != -current_dx and new_dy != -current_dy:                            dx, dy = new_dx, new_dy            # move head            x += dx;            y += dy            snake.insert(0, (x, y))            if x == apple_x and y == apple_y:                apple_x, apple_y = self.generate_apple()            else:                # remove last part of snake                snake.pop()            self.display.fill(BG_COLOR)            # apple            apple_rect = pygame.Rect(apple_x * self.cell_size,                                     apple_y * self.cell_size,                                     self.cell_size, self.cell_size)            pygame.draw.rect(self.display, RED, apple_rect)            # body            game_over = False            for snake_x, snake_y in snake[1:]:                body_rect = pygame.Rect(snake_x * self.cell_size, snake_y * self.cell_size,                                         self.cell_size, self.cell_size)                pygame.draw.rect(self.display, SNAKE_COLOR, body_rect)                # border                pygame.draw.rect(self.display, DARK_GRAY, body_rect, 1)                if x == snake_x and y == snake_y:                    game_over = True            # head            head_rect = pygame.Rect(x * self.cell_size, y * self.cell_size,                                     self.cell_size, self.cell_size)            pygame.draw.rect(self.display, HEAD_COLOR, head_rect)            pygame.display.flip()            self.clock.tick(self.game_speed)            if x < 0 or x >= col_count \                or y < 0 or y >= row_count \                or game_over:                self.show_game_over()                return    def show_game_over(self):        Show game over text.        text = self.font.render(Game Over, True, WHITE)        text_rect = text.get_rect()        text_x = self.width / 2 - text_rect.width / 2        text_y = self.height / 2 - text_rect.height / 2        self.display.blit(text, (text_x, text_y))        pygame.display.flip()        pygame.time.wait(300)    def generate_apple(self):        Generate new apple coordinates (x, y).        return (random.randrange(0, self.width / self.cell_size),                 random.randrange(0, self.height / self.cell_size))    def get_starting_point(self):        Return starting location of snake's head (x, y).        return (random.randrange(5, (self.width / self.cell_size) - 5),                 random.randrange(5, (self.height / self.cell_size) - 5))if __name__ == '__main__':    snake = Snake()    snake.loop_games()
Simple Snake with pygame
python;python 3.x;pygame;snake game