Skip to main content
Code Review

Return to Answer

replaced http://stackoverflow.com/ with https://stackoverflow.com/
Source Link

The actual game code I would put into a main function which you can call within a if __name__ == "__main__": if __name__ == "__main__": guard to allow importing this from another script. With these changes, your code becomes:

The actual game code I would put into a main function which you can call within a if __name__ == "__main__": guard to allow importing this from another script. With these changes, your code becomes:

The actual game code I would put into a main function which you can call within a if __name__ == "__main__": guard to allow importing this from another script. With these changes, your code becomes:

Currently you, your full snake is just a list of body parts. While this is nice, you also have a few functions that just operate on a snake, so it would be nice to add these two things together and make snake a class as well. I would doedo something like this, which inherits from list so the rest of your code stays basically unchanged, except that instead of draw_snake() you now have snake.draw(), etc:

import pygame
import time
import random
pygame.init()
# defines the width and height of the display
display_width = 800
display_height = 600
white = (255, 255, 255)
d_white = (250, 250, 250)
black = (0, 0, 0)
teal = (0, 128, 128)
blue_black = (50, 50, 50)
game_display = pygame.display.set_mode((display_width, display_height))
factor = 10
clock = pygame.time.Clock()
class SnakeBody:
 def __init__(self, x, y):
 self.x, self.y = x, y
 def __repr__(self):
 return "SnakeBody({self.x}, {self.y})".format(self=self)
class Snake(list):
 def __init__(self, start_x, start_y, n):
 list.__init__(self, [SnakeBody(start_x, start_y + i * factor)
 for i in range(n)])
 def move_head(self, dx, dy):
 self[0].x += dx
 self[0].y += dy
 def update(self, score):
 for i in range(len(self) - 1, 0, -1):
 self[i].x = self[i - 1].x
 self[i].y = self[i - 1].y
 def check_death(self):
 if not (1 <= self[0].x <= display_width and 1 <= self[0].y <= display_height):
 return True
 return any(body_part.x == self[0].x and body_part.y == self[0].y for body_part in self[1:])
 def draw(self):
 for body_part in self:
 pygame.draw.rect(game_display, teal,
 (body_part.x, body_part.y, factor, factor))
def main():
 food_x = random.randrange(5, display_width - 5)
 food_y = random.randrange(5, display_height - 5)
 print(food_x, food_y)
 score = 60
 snake = Snake(20, 20, 16)
 x = 0
 y = 0
 x_change = 0
 y_change = 0
 first_time = True
 eat = True
 while True:
 for event in pygame.event.get():
 if event.type == pygame.QUIT:
 pygame.quit()
 quit()
 if event.type == pygame.KEYDOWN:
 first_time = False
 if event.key == pygame.K_a:
 if x_change != 10:
 x_change = -10
 y_change = 0
 elif event.key == pygame.K_d:
 if x_change != -10:
 x_change = 10
 y_change = 0
 elif event.key == pygame.K_w:
 if y_change != 10:
 x_change = 0
 y_change = -10
 elif event.key == pygame.K_s:
 if y_change != -10:
 x_change = 0
 y_change = 10
 elif event.key == pygame.K_c:
 x_change = 0
 y_change = 0
 if not first_time:
 snake.update(score)
 if score % 10 == 0 and eat:
 snake.append(snake_body(
 snake[len(snake) - 1].x, snake[len(snake) - 1].y))
 print(len(snake))
 eat = False
 snake.move_head(x_change, y_change)
 if snake[0].x < food_x + 10 and snake[0].x > food_x - 10 and snake[0].y < food_y + 10 and snake[0].y > food_y - 10:
 score += 10
 food_x = random.randrange(5, display_width - 5)
 food_y = random.randrange(5, display_height - 5)
 eat = True
 if snake.check_death():
 pygame.quit()
 quit()
 # update game display
 game_display.fill(white)
 pygame.draw.rect(game_display, black, (food_x, food_y, factor, factor))
 snake.draw()
 pygame.display.flip()
 time.sleep(0.035)
 clock.tick(60)
if __name__ == "__main__":
 main()

 <br>

Currently you full snake is just a list of body parts. While this is nice, you also have a few functions that just operate on a snake, so it would be nice to add these two things together and make snake a class as well. I would doe something like this, which inherits from list so the rest of your code stays basically unchanged, except that instead of draw_snake() you now have snake.draw(), etc:

import pygame
import time
import random
pygame.init()
# defines the width and height of the display
display_width = 800
display_height = 600
white = (255, 255, 255)
d_white = (250, 250, 250)
black = (0, 0, 0)
teal = (0, 128, 128)
blue_black = (50, 50, 50)
game_display = pygame.display.set_mode((display_width, display_height))
factor = 10
clock = pygame.time.Clock()
class SnakeBody:
 def __init__(self, x, y):
 self.x, self.y = x, y
 def __repr__(self):
 return "SnakeBody({self.x}, {self.y})".format(self=self)
class Snake(list):
 def __init__(self, start_x, start_y, n):
 list.__init__(self, [SnakeBody(start_x, start_y + i * factor)
 for i in range(n)])
 def move_head(self, dx, dy):
 self[0].x += dx
 self[0].y += dy
 def update(self, score):
 for i in range(len(self) - 1, 0, -1):
 self[i].x = self[i - 1].x
 self[i].y = self[i - 1].y
 def check_death(self):
 if not (1 <= self[0].x <= display_width and 1 <= self[0].y <= display_height):
 return True
 return any(body_part.x == self[0].x and body_part.y == self[0].y for body_part in self[1:])
 def draw(self):
 for body_part in self:
 pygame.draw.rect(game_display, teal,
 (body_part.x, body_part.y, factor, factor))
def main():
 food_x = random.randrange(5, display_width - 5)
 food_y = random.randrange(5, display_height - 5)
 print(food_x, food_y)
 score = 60
 snake = Snake(20, 20, 16)
 x = 0
 y = 0
 x_change = 0
 y_change = 0
 first_time = True
 eat = True
 while True:
 for event in pygame.event.get():
 if event.type == pygame.QUIT:
 pygame.quit()
 quit()
 if event.type == pygame.KEYDOWN:
 first_time = False
 if event.key == pygame.K_a:
 if x_change != 10:
 x_change = -10
 y_change = 0
 elif event.key == pygame.K_d:
 if x_change != -10:
 x_change = 10
 y_change = 0
 elif event.key == pygame.K_w:
 if y_change != 10:
 x_change = 0
 y_change = -10
 elif event.key == pygame.K_s:
 if y_change != -10:
 x_change = 0
 y_change = 10
 elif event.key == pygame.K_c:
 x_change = 0
 y_change = 0
 if not first_time:
 snake.update(score)
 if score % 10 == 0 and eat:
 snake.append(snake_body(
 snake[len(snake) - 1].x, snake[len(snake) - 1].y))
 print(len(snake))
 eat = False
 snake.move_head(x_change, y_change)
 if snake[0].x < food_x + 10 and snake[0].x > food_x - 10 and snake[0].y < food_y + 10 and snake[0].y > food_y - 10:
 score += 10
 food_x = random.randrange(5, display_width - 5)
 food_y = random.randrange(5, display_height - 5)
 eat = True
 if snake.check_death():
 pygame.quit()
 quit()
 # update game display
 game_display.fill(white)
 pygame.draw.rect(game_display, black, (food_x, food_y, factor, factor))
 snake.draw()
 pygame.display.flip()
 time.sleep(0.035)
 clock.tick(60)
if __name__ == "__main__":
 main()

Currently, your full snake is just a list of body parts. While this is nice, you also have a few functions that just operate on a snake, so it would be nice to add these two things together and make snake a class as well. I would do something like this, which inherits from list so the rest of your code stays basically unchanged, except that instead of draw_snake() you now have snake.draw(), etc:

import pygame
import time
import random
pygame.init()
# defines the width and height of the display
display_width = 800
display_height = 600
white = (255, 255, 255)
d_white = (250, 250, 250)
black = (0, 0, 0)
teal = (0, 128, 128)
blue_black = (50, 50, 50)
game_display = pygame.display.set_mode((display_width, display_height))
factor = 10
clock = pygame.time.Clock()
class SnakeBody:
 def __init__(self, x, y):
 self.x, self.y = x, y
 def __repr__(self):
 return "SnakeBody({self.x}, {self.y})".format(self=self)
class Snake(list):
 def __init__(self, start_x, start_y, n):
 list.__init__(self, [SnakeBody(start_x, start_y + i * factor)
 for i in range(n)])
 def move_head(self, dx, dy):
 self[0].x += dx
 self[0].y += dy
 def update(self, score):
 for i in range(len(self) - 1, 0, -1):
 self[i].x = self[i - 1].x
 self[i].y = self[i - 1].y
 def check_death(self):
 if not (1 <= self[0].x <= display_width and 1 <= self[0].y <= display_height):
 return True
 return any(body_part.x == self[0].x and body_part.y == self[0].y for body_part in self[1:])
 def draw(self):
 for body_part in self:
 pygame.draw.rect(game_display, teal,
 (body_part.x, body_part.y, factor, factor))
def main():
 food_x = random.randrange(5, display_width - 5)
 food_y = random.randrange(5, display_height - 5)
 print(food_x, food_y)
 score = 60
 snake = Snake(20, 20, 16)
 x = 0
 y = 0
 x_change = 0
 y_change = 0
 first_time = True
 eat = True
 while True:
 for event in pygame.event.get():
 if event.type == pygame.QUIT:
 pygame.quit()
 quit()
 if event.type == pygame.KEYDOWN:
 first_time = False
 if event.key == pygame.K_a:
 if x_change != 10:
 x_change = -10
 y_change = 0
 elif event.key == pygame.K_d:
 if x_change != -10:
 x_change = 10
 y_change = 0
 elif event.key == pygame.K_w:
 if y_change != 10:
 x_change = 0
 y_change = -10
 elif event.key == pygame.K_s:
 if y_change != -10:
 x_change = 0
 y_change = 10
 elif event.key == pygame.K_c:
 x_change = 0
 y_change = 0
 if not first_time:
 snake.update(score)
 if score % 10 == 0 and eat:
 snake.append(snake_body(
 snake[len(snake) - 1].x, snake[len(snake) - 1].y))
 print(len(snake))
 eat = False
 snake.move_head(x_change, y_change)
 if snake[0].x < food_x + 10 and snake[0].x > food_x - 10 and snake[0].y < food_y + 10 and snake[0].y > food_y - 10:
 score += 10
 food_x = random.randrange(5, display_width - 5)
 food_y = random.randrange(5, display_height - 5)
 eat = True
 if snake.check_death():
 pygame.quit()
 quit()
 # update game display
 game_display.fill(white)
 pygame.draw.rect(game_display, black, (food_x, food_y, factor, factor))
 snake.draw()
 pygame.display.flip()
 time.sleep(0.035)
 clock.tick(60)
if __name__ == "__main__":
 main()

 <br>
Source Link
Graipher
  • 41.7k
  • 7
  • 70
  • 134

Here are some changes I would make:

Your snake_body class (which should be called SnakeBody, according to PEP8), does not need to initialize its attributes before the initialization, so you can just have:

class SnakeBody:
 def __init__(self, x, y):
 self.x, self.y = x, y
 def __repr__(self):
 return "SnakeBody({self.x}, {self.y})".format(self=self)

I also gave it a __repr__ method so it prints nicer.

Currently you full snake is just a list of body parts. While this is nice, you also have a few functions that just operate on a snake, so it would be nice to add these two things together and make snake a class as well. I would doe something like this, which inherits from list so the rest of your code stays basically unchanged, except that instead of draw_snake() you now have snake.draw(), etc:

class Snake(list):
 def __init__(self, start_x, start_y, n):
 list.__init__(self, [SnakeBody(start_x, start_y + i * factor)
 for i in range(n)])
 def move_head(self, dx, dy):
 self[0].x += dx
 self[0].y += dy
 def update(self, score):
 for i in range(len(self) - 1, 0, -1):
 self[i].x = self[i - 1].x
 self[i].y = self[i - 1].y
 def check_death(self):
 if not (1 <= self[0].x <= display_width and 1 <= self[0].y <= display_height):
 return True
 return any(body_part.x == self[0].x and body_part.y == self[0].y for body_part in self[1:])
 def draw(self):
 for body_part in self:
 pygame.draw.rect(game_display, teal,
 (body_part.x, body_part.y, factor, factor))

Note that I also simplified the check_death function. It now returns True if the snake needs to die. I used the fact that Python can do multiple comparisons, so a <= x <= b is legal in Python.

The actual game code I would put into a main function which you can call within a if __name__ == "__main__": guard to allow importing this from another script. With these changes, your code becomes:

Final code:

import pygame
import time
import random
pygame.init()
# defines the width and height of the display
display_width = 800
display_height = 600
white = (255, 255, 255)
d_white = (250, 250, 250)
black = (0, 0, 0)
teal = (0, 128, 128)
blue_black = (50, 50, 50)
game_display = pygame.display.set_mode((display_width, display_height))
factor = 10
clock = pygame.time.Clock()
class SnakeBody:
 def __init__(self, x, y):
 self.x, self.y = x, y
 def __repr__(self):
 return "SnakeBody({self.x}, {self.y})".format(self=self)
class Snake(list):
 def __init__(self, start_x, start_y, n):
 list.__init__(self, [SnakeBody(start_x, start_y + i * factor)
 for i in range(n)])
 def move_head(self, dx, dy):
 self[0].x += dx
 self[0].y += dy
 def update(self, score):
 for i in range(len(self) - 1, 0, -1):
 self[i].x = self[i - 1].x
 self[i].y = self[i - 1].y
 def check_death(self):
 if not (1 <= self[0].x <= display_width and 1 <= self[0].y <= display_height):
 return True
 return any(body_part.x == self[0].x and body_part.y == self[0].y for body_part in self[1:])
 def draw(self):
 for body_part in self:
 pygame.draw.rect(game_display, teal,
 (body_part.x, body_part.y, factor, factor))
def main():
 food_x = random.randrange(5, display_width - 5)
 food_y = random.randrange(5, display_height - 5)
 print(food_x, food_y)
 score = 60
 snake = Snake(20, 20, 16)
 x = 0
 y = 0
 x_change = 0
 y_change = 0
 first_time = True
 eat = True
 while True:
 for event in pygame.event.get():
 if event.type == pygame.QUIT:
 pygame.quit()
 quit()
 if event.type == pygame.KEYDOWN:
 first_time = False
 if event.key == pygame.K_a:
 if x_change != 10:
 x_change = -10
 y_change = 0
 elif event.key == pygame.K_d:
 if x_change != -10:
 x_change = 10
 y_change = 0
 elif event.key == pygame.K_w:
 if y_change != 10:
 x_change = 0
 y_change = -10
 elif event.key == pygame.K_s:
 if y_change != -10:
 x_change = 0
 y_change = 10
 elif event.key == pygame.K_c:
 x_change = 0
 y_change = 0
 if not first_time:
 snake.update(score)
 if score % 10 == 0 and eat:
 snake.append(snake_body(
 snake[len(snake) - 1].x, snake[len(snake) - 1].y))
 print(len(snake))
 eat = False
 snake.move_head(x_change, y_change)
 if snake[0].x < food_x + 10 and snake[0].x > food_x - 10 and snake[0].y < food_y + 10 and snake[0].y > food_y - 10:
 score += 10
 food_x = random.randrange(5, display_width - 5)
 food_y = random.randrange(5, display_height - 5)
 eat = True
 if snake.check_death():
 pygame.quit()
 quit()
 # update game display
 game_display.fill(white)
 pygame.draw.rect(game_display, black, (food_x, food_y, factor, factor))
 snake.draw()
 pygame.display.flip()
 time.sleep(0.035)
 clock.tick(60)
if __name__ == "__main__":
 main()
lang-py

AltStyle によって変換されたページ (->オリジナル) /