First Python program: Snake












3












$begingroup$


I've started learning Python yesterday with the intention of studying machine learning. Before this, my experience with programming was exclusive to my first semester where I had a C course.



I decided to work towards a final objective: have an AI learn how to win the snake game. For that goal, I had to make the actual game. I didn't want to copy an already made game as I'm still learning. So with that in mind, I spent an entire night building my little snake game.



I would like the game to be as good as possible before I started the machine learning part, which is why I'm posting it here. My biggest problem right now is controlling the speed of the game. I achieved this by limiting the FPS number based on the current score but it seems like a cheap way to do it.



I divided the game in two files: vars.py where I define most variables and functions and snake.py with the actual game and a few other things. This is the way I was taught to program so if it's wrong or not done please feel free to point that out.



vars.py



import random
import math

width = 800
height = 600
BG = 255, 255, 255
FOOD_C = 128, 0, 0
BODY_C = 0, 0, 0
sqr_size = 10
SPEED = sqr_size

def dist(a, b):
return math.sqrt((b.pos[0] - a.pos[0])**2 + (b.pos[1] - a.pos[1])**2)

def check_food(snake, food): #Check if food is eaten
if dist(snake, food) > sqr_size:
return False
else:
return True

def loser(snake, food): #Check if lost the game
if snake.pos[0]<sqr_size or snake.pos[0]>width-sqr_size:
return True
if snake.pos[1]<sqr_size or snake.pos[1]>height-sqr_size:
return True
for i in snake.body[1:]:
if i == snake.pos:
return True

def game_speed(snake):
if (10 + snake.score()//2) < 30:
return 10 + snake.score()//2
else:
return 30

class Snake(object):
def __init__(self):
self.pos = [random.randint(1, (width-sqr_size)/10)*10,
random.randint(1, (height-sqr_size)/10)*10]
self.mov = "UP"
self.body = [self.pos[:]]

def change_mov(self, key): #Decide where to move
if key == "UP" and self.mov != "DOWN":
self.mov = key
if key == "DOWN" and self.mov != "UP":
self.mov = key
if key == "RIGHT" and self.mov != "LEFT":
self.mov = key
if key == "LEFT" and self.mov != "RIGHT":
self.mov = key

def score(self):
return len(self.body)

def move(self, eat): #Snake movement
if self.mov == "UP": self.pos[1] = self.pos[1] - SPEED
if self.mov == "DOWN": self.pos[1] = self.pos[1] + SPEED
if self.mov == "LEFT": self.pos[0] = self.pos[0] - SPEED
if self.mov == "RIGHT": self.pos[0] = self.pos[0] + SPEED
self.body.insert(0, self.pos[:])
if not eat:
self.body.pop()


class Food(object):
def __init__(self):
self.pos = [random.randint(1, (width-sqr_size)/10)*10,
random.randint(1, (height-sqr_size)/10)*10]


snake.py



import pygame, sys
import vars

#Initialising pygame
pygame.init()
pygame.font.init()
myfont = pygame.font.SysFont('Times New Roman', 30)
clock = pygame.time.Clock()
screen = pygame.display.set_mode((vars.width,vars.height))
pygame.display.update()

#Initialising variables
lost = False
eat = False
snake = vars.Snake()
food = vars.Food()
screen.fill(vars.BG)
key1 = "0"

def whatkey(event):
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
return "LEFT"
if event.key == pygame.K_RIGHT:
return "RIGHT"
if event.key == pygame.K_UP:
return "UP"
if event.key == pygame.K_DOWN:
return "DOWN"

while not lost:
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
key1 = whatkey(event)

#How the game works
snake.change_mov(key1)
eat = vars.check_food(snake, food)
snake.move(eat)
if eat:
food = vars.Food()
lost = vars.loser(snake, food)

#Screen drawings
screen.fill(vars.BG)
for i in snake.body:
pygame.draw.circle(screen, vars.BODY_C, (i[0], i[1]), vars.sqr_size, 0)
pygame.draw.circle(screen, vars.FOOD_C, (food.pos[0], food.pos[1]), vars.sqr_size, 0)
pygame.display.set_caption("Snake. Your score is: {}".format(snake.score()))
pygame.display.update()

#Control of the game speed via fps
#Not related to the SPEED variable. That is for movement
msElapsed = clock.tick(vars.game_speed(snake))

#Lose screen
pygame.display.update()
screen.fill(vars.BG)
textsurface1 = myfont.render('You lost. Your score is:', False, (0, 0, 0))
textsurface2 = myfont.render("{}".format(snake.score()), False, (0, 0, 0))
screen.blit(textsurface1,(250, 200))
screen.blit(textsurface2,(380,280))
pygame.display.update()
while 1:
for event in pygame.event.get():
if event.type == pygame.QUIT: sys.exit()









share|improve this question









New contributor




André Rocha is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.







$endgroup$












  • $begingroup$
    Please do not update the code in your question to incorporate feedback from answers, doing so goes against the Question + Answer style of Code Review. This is not a forum where you should keep the most updated version in your question. Please see what you may and may not do after receiving answers.
    $endgroup$
    – Mast
    8 hours ago










  • $begingroup$
    @Mast I'm sorry, I didn't know. However, the edits I made weren't to incorporate the answers. I changed circles to squares, for example and colours I believe but didn't know I shouldn't. I won't do it again.
    $endgroup$
    – André Rocha
    7 hours ago










  • $begingroup$
    Feel free to post a follow-up question with improved code if your code has changed significantly enough in the meantime. You can save such edits for then. No problem.
    $endgroup$
    – Mast
    5 hours ago
















3












$begingroup$


I've started learning Python yesterday with the intention of studying machine learning. Before this, my experience with programming was exclusive to my first semester where I had a C course.



I decided to work towards a final objective: have an AI learn how to win the snake game. For that goal, I had to make the actual game. I didn't want to copy an already made game as I'm still learning. So with that in mind, I spent an entire night building my little snake game.



I would like the game to be as good as possible before I started the machine learning part, which is why I'm posting it here. My biggest problem right now is controlling the speed of the game. I achieved this by limiting the FPS number based on the current score but it seems like a cheap way to do it.



I divided the game in two files: vars.py where I define most variables and functions and snake.py with the actual game and a few other things. This is the way I was taught to program so if it's wrong or not done please feel free to point that out.



vars.py



import random
import math

width = 800
height = 600
BG = 255, 255, 255
FOOD_C = 128, 0, 0
BODY_C = 0, 0, 0
sqr_size = 10
SPEED = sqr_size

def dist(a, b):
return math.sqrt((b.pos[0] - a.pos[0])**2 + (b.pos[1] - a.pos[1])**2)

def check_food(snake, food): #Check if food is eaten
if dist(snake, food) > sqr_size:
return False
else:
return True

def loser(snake, food): #Check if lost the game
if snake.pos[0]<sqr_size or snake.pos[0]>width-sqr_size:
return True
if snake.pos[1]<sqr_size or snake.pos[1]>height-sqr_size:
return True
for i in snake.body[1:]:
if i == snake.pos:
return True

def game_speed(snake):
if (10 + snake.score()//2) < 30:
return 10 + snake.score()//2
else:
return 30

class Snake(object):
def __init__(self):
self.pos = [random.randint(1, (width-sqr_size)/10)*10,
random.randint(1, (height-sqr_size)/10)*10]
self.mov = "UP"
self.body = [self.pos[:]]

def change_mov(self, key): #Decide where to move
if key == "UP" and self.mov != "DOWN":
self.mov = key
if key == "DOWN" and self.mov != "UP":
self.mov = key
if key == "RIGHT" and self.mov != "LEFT":
self.mov = key
if key == "LEFT" and self.mov != "RIGHT":
self.mov = key

def score(self):
return len(self.body)

def move(self, eat): #Snake movement
if self.mov == "UP": self.pos[1] = self.pos[1] - SPEED
if self.mov == "DOWN": self.pos[1] = self.pos[1] + SPEED
if self.mov == "LEFT": self.pos[0] = self.pos[0] - SPEED
if self.mov == "RIGHT": self.pos[0] = self.pos[0] + SPEED
self.body.insert(0, self.pos[:])
if not eat:
self.body.pop()


class Food(object):
def __init__(self):
self.pos = [random.randint(1, (width-sqr_size)/10)*10,
random.randint(1, (height-sqr_size)/10)*10]


snake.py



import pygame, sys
import vars

#Initialising pygame
pygame.init()
pygame.font.init()
myfont = pygame.font.SysFont('Times New Roman', 30)
clock = pygame.time.Clock()
screen = pygame.display.set_mode((vars.width,vars.height))
pygame.display.update()

#Initialising variables
lost = False
eat = False
snake = vars.Snake()
food = vars.Food()
screen.fill(vars.BG)
key1 = "0"

def whatkey(event):
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
return "LEFT"
if event.key == pygame.K_RIGHT:
return "RIGHT"
if event.key == pygame.K_UP:
return "UP"
if event.key == pygame.K_DOWN:
return "DOWN"

while not lost:
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
key1 = whatkey(event)

#How the game works
snake.change_mov(key1)
eat = vars.check_food(snake, food)
snake.move(eat)
if eat:
food = vars.Food()
lost = vars.loser(snake, food)

#Screen drawings
screen.fill(vars.BG)
for i in snake.body:
pygame.draw.circle(screen, vars.BODY_C, (i[0], i[1]), vars.sqr_size, 0)
pygame.draw.circle(screen, vars.FOOD_C, (food.pos[0], food.pos[1]), vars.sqr_size, 0)
pygame.display.set_caption("Snake. Your score is: {}".format(snake.score()))
pygame.display.update()

#Control of the game speed via fps
#Not related to the SPEED variable. That is for movement
msElapsed = clock.tick(vars.game_speed(snake))

#Lose screen
pygame.display.update()
screen.fill(vars.BG)
textsurface1 = myfont.render('You lost. Your score is:', False, (0, 0, 0))
textsurface2 = myfont.render("{}".format(snake.score()), False, (0, 0, 0))
screen.blit(textsurface1,(250, 200))
screen.blit(textsurface2,(380,280))
pygame.display.update()
while 1:
for event in pygame.event.get():
if event.type == pygame.QUIT: sys.exit()









share|improve this question









New contributor




André Rocha is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.







$endgroup$












  • $begingroup$
    Please do not update the code in your question to incorporate feedback from answers, doing so goes against the Question + Answer style of Code Review. This is not a forum where you should keep the most updated version in your question. Please see what you may and may not do after receiving answers.
    $endgroup$
    – Mast
    8 hours ago










  • $begingroup$
    @Mast I'm sorry, I didn't know. However, the edits I made weren't to incorporate the answers. I changed circles to squares, for example and colours I believe but didn't know I shouldn't. I won't do it again.
    $endgroup$
    – André Rocha
    7 hours ago










  • $begingroup$
    Feel free to post a follow-up question with improved code if your code has changed significantly enough in the meantime. You can save such edits for then. No problem.
    $endgroup$
    – Mast
    5 hours ago














3












3








3





$begingroup$


I've started learning Python yesterday with the intention of studying machine learning. Before this, my experience with programming was exclusive to my first semester where I had a C course.



I decided to work towards a final objective: have an AI learn how to win the snake game. For that goal, I had to make the actual game. I didn't want to copy an already made game as I'm still learning. So with that in mind, I spent an entire night building my little snake game.



I would like the game to be as good as possible before I started the machine learning part, which is why I'm posting it here. My biggest problem right now is controlling the speed of the game. I achieved this by limiting the FPS number based on the current score but it seems like a cheap way to do it.



I divided the game in two files: vars.py where I define most variables and functions and snake.py with the actual game and a few other things. This is the way I was taught to program so if it's wrong or not done please feel free to point that out.



vars.py



import random
import math

width = 800
height = 600
BG = 255, 255, 255
FOOD_C = 128, 0, 0
BODY_C = 0, 0, 0
sqr_size = 10
SPEED = sqr_size

def dist(a, b):
return math.sqrt((b.pos[0] - a.pos[0])**2 + (b.pos[1] - a.pos[1])**2)

def check_food(snake, food): #Check if food is eaten
if dist(snake, food) > sqr_size:
return False
else:
return True

def loser(snake, food): #Check if lost the game
if snake.pos[0]<sqr_size or snake.pos[0]>width-sqr_size:
return True
if snake.pos[1]<sqr_size or snake.pos[1]>height-sqr_size:
return True
for i in snake.body[1:]:
if i == snake.pos:
return True

def game_speed(snake):
if (10 + snake.score()//2) < 30:
return 10 + snake.score()//2
else:
return 30

class Snake(object):
def __init__(self):
self.pos = [random.randint(1, (width-sqr_size)/10)*10,
random.randint(1, (height-sqr_size)/10)*10]
self.mov = "UP"
self.body = [self.pos[:]]

def change_mov(self, key): #Decide where to move
if key == "UP" and self.mov != "DOWN":
self.mov = key
if key == "DOWN" and self.mov != "UP":
self.mov = key
if key == "RIGHT" and self.mov != "LEFT":
self.mov = key
if key == "LEFT" and self.mov != "RIGHT":
self.mov = key

def score(self):
return len(self.body)

def move(self, eat): #Snake movement
if self.mov == "UP": self.pos[1] = self.pos[1] - SPEED
if self.mov == "DOWN": self.pos[1] = self.pos[1] + SPEED
if self.mov == "LEFT": self.pos[0] = self.pos[0] - SPEED
if self.mov == "RIGHT": self.pos[0] = self.pos[0] + SPEED
self.body.insert(0, self.pos[:])
if not eat:
self.body.pop()


class Food(object):
def __init__(self):
self.pos = [random.randint(1, (width-sqr_size)/10)*10,
random.randint(1, (height-sqr_size)/10)*10]


snake.py



import pygame, sys
import vars

#Initialising pygame
pygame.init()
pygame.font.init()
myfont = pygame.font.SysFont('Times New Roman', 30)
clock = pygame.time.Clock()
screen = pygame.display.set_mode((vars.width,vars.height))
pygame.display.update()

#Initialising variables
lost = False
eat = False
snake = vars.Snake()
food = vars.Food()
screen.fill(vars.BG)
key1 = "0"

def whatkey(event):
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
return "LEFT"
if event.key == pygame.K_RIGHT:
return "RIGHT"
if event.key == pygame.K_UP:
return "UP"
if event.key == pygame.K_DOWN:
return "DOWN"

while not lost:
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
key1 = whatkey(event)

#How the game works
snake.change_mov(key1)
eat = vars.check_food(snake, food)
snake.move(eat)
if eat:
food = vars.Food()
lost = vars.loser(snake, food)

#Screen drawings
screen.fill(vars.BG)
for i in snake.body:
pygame.draw.circle(screen, vars.BODY_C, (i[0], i[1]), vars.sqr_size, 0)
pygame.draw.circle(screen, vars.FOOD_C, (food.pos[0], food.pos[1]), vars.sqr_size, 0)
pygame.display.set_caption("Snake. Your score is: {}".format(snake.score()))
pygame.display.update()

#Control of the game speed via fps
#Not related to the SPEED variable. That is for movement
msElapsed = clock.tick(vars.game_speed(snake))

#Lose screen
pygame.display.update()
screen.fill(vars.BG)
textsurface1 = myfont.render('You lost. Your score is:', False, (0, 0, 0))
textsurface2 = myfont.render("{}".format(snake.score()), False, (0, 0, 0))
screen.blit(textsurface1,(250, 200))
screen.blit(textsurface2,(380,280))
pygame.display.update()
while 1:
for event in pygame.event.get():
if event.type == pygame.QUIT: sys.exit()









share|improve this question









New contributor




André Rocha is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.







$endgroup$




I've started learning Python yesterday with the intention of studying machine learning. Before this, my experience with programming was exclusive to my first semester where I had a C course.



I decided to work towards a final objective: have an AI learn how to win the snake game. For that goal, I had to make the actual game. I didn't want to copy an already made game as I'm still learning. So with that in mind, I spent an entire night building my little snake game.



I would like the game to be as good as possible before I started the machine learning part, which is why I'm posting it here. My biggest problem right now is controlling the speed of the game. I achieved this by limiting the FPS number based on the current score but it seems like a cheap way to do it.



I divided the game in two files: vars.py where I define most variables and functions and snake.py with the actual game and a few other things. This is the way I was taught to program so if it's wrong or not done please feel free to point that out.



vars.py



import random
import math

width = 800
height = 600
BG = 255, 255, 255
FOOD_C = 128, 0, 0
BODY_C = 0, 0, 0
sqr_size = 10
SPEED = sqr_size

def dist(a, b):
return math.sqrt((b.pos[0] - a.pos[0])**2 + (b.pos[1] - a.pos[1])**2)

def check_food(snake, food): #Check if food is eaten
if dist(snake, food) > sqr_size:
return False
else:
return True

def loser(snake, food): #Check if lost the game
if snake.pos[0]<sqr_size or snake.pos[0]>width-sqr_size:
return True
if snake.pos[1]<sqr_size or snake.pos[1]>height-sqr_size:
return True
for i in snake.body[1:]:
if i == snake.pos:
return True

def game_speed(snake):
if (10 + snake.score()//2) < 30:
return 10 + snake.score()//2
else:
return 30

class Snake(object):
def __init__(self):
self.pos = [random.randint(1, (width-sqr_size)/10)*10,
random.randint(1, (height-sqr_size)/10)*10]
self.mov = "UP"
self.body = [self.pos[:]]

def change_mov(self, key): #Decide where to move
if key == "UP" and self.mov != "DOWN":
self.mov = key
if key == "DOWN" and self.mov != "UP":
self.mov = key
if key == "RIGHT" and self.mov != "LEFT":
self.mov = key
if key == "LEFT" and self.mov != "RIGHT":
self.mov = key

def score(self):
return len(self.body)

def move(self, eat): #Snake movement
if self.mov == "UP": self.pos[1] = self.pos[1] - SPEED
if self.mov == "DOWN": self.pos[1] = self.pos[1] + SPEED
if self.mov == "LEFT": self.pos[0] = self.pos[0] - SPEED
if self.mov == "RIGHT": self.pos[0] = self.pos[0] + SPEED
self.body.insert(0, self.pos[:])
if not eat:
self.body.pop()


class Food(object):
def __init__(self):
self.pos = [random.randint(1, (width-sqr_size)/10)*10,
random.randint(1, (height-sqr_size)/10)*10]


snake.py



import pygame, sys
import vars

#Initialising pygame
pygame.init()
pygame.font.init()
myfont = pygame.font.SysFont('Times New Roman', 30)
clock = pygame.time.Clock()
screen = pygame.display.set_mode((vars.width,vars.height))
pygame.display.update()

#Initialising variables
lost = False
eat = False
snake = vars.Snake()
food = vars.Food()
screen.fill(vars.BG)
key1 = "0"

def whatkey(event):
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
return "LEFT"
if event.key == pygame.K_RIGHT:
return "RIGHT"
if event.key == pygame.K_UP:
return "UP"
if event.key == pygame.K_DOWN:
return "DOWN"

while not lost:
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
key1 = whatkey(event)

#How the game works
snake.change_mov(key1)
eat = vars.check_food(snake, food)
snake.move(eat)
if eat:
food = vars.Food()
lost = vars.loser(snake, food)

#Screen drawings
screen.fill(vars.BG)
for i in snake.body:
pygame.draw.circle(screen, vars.BODY_C, (i[0], i[1]), vars.sqr_size, 0)
pygame.draw.circle(screen, vars.FOOD_C, (food.pos[0], food.pos[1]), vars.sqr_size, 0)
pygame.display.set_caption("Snake. Your score is: {}".format(snake.score()))
pygame.display.update()

#Control of the game speed via fps
#Not related to the SPEED variable. That is for movement
msElapsed = clock.tick(vars.game_speed(snake))

#Lose screen
pygame.display.update()
screen.fill(vars.BG)
textsurface1 = myfont.render('You lost. Your score is:', False, (0, 0, 0))
textsurface2 = myfont.render("{}".format(snake.score()), False, (0, 0, 0))
screen.blit(textsurface1,(250, 200))
screen.blit(textsurface2,(380,280))
pygame.display.update()
while 1:
for event in pygame.event.get():
if event.type == pygame.QUIT: sys.exit()






python beginner pygame snake-game






share|improve this question









New contributor




André Rocha is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.











share|improve this question









New contributor




André Rocha is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.









share|improve this question




share|improve this question








edited 8 hours ago









Mast

7,49163788




7,49163788






New contributor




André Rocha is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.









asked 9 hours ago









André RochaAndré Rocha

163




163




New contributor




André Rocha is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.





New contributor





André Rocha is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.






André Rocha is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.












  • $begingroup$
    Please do not update the code in your question to incorporate feedback from answers, doing so goes against the Question + Answer style of Code Review. This is not a forum where you should keep the most updated version in your question. Please see what you may and may not do after receiving answers.
    $endgroup$
    – Mast
    8 hours ago










  • $begingroup$
    @Mast I'm sorry, I didn't know. However, the edits I made weren't to incorporate the answers. I changed circles to squares, for example and colours I believe but didn't know I shouldn't. I won't do it again.
    $endgroup$
    – André Rocha
    7 hours ago










  • $begingroup$
    Feel free to post a follow-up question with improved code if your code has changed significantly enough in the meantime. You can save such edits for then. No problem.
    $endgroup$
    – Mast
    5 hours ago


















  • $begingroup$
    Please do not update the code in your question to incorporate feedback from answers, doing so goes against the Question + Answer style of Code Review. This is not a forum where you should keep the most updated version in your question. Please see what you may and may not do after receiving answers.
    $endgroup$
    – Mast
    8 hours ago










  • $begingroup$
    @Mast I'm sorry, I didn't know. However, the edits I made weren't to incorporate the answers. I changed circles to squares, for example and colours I believe but didn't know I shouldn't. I won't do it again.
    $endgroup$
    – André Rocha
    7 hours ago










  • $begingroup$
    Feel free to post a follow-up question with improved code if your code has changed significantly enough in the meantime. You can save such edits for then. No problem.
    $endgroup$
    – Mast
    5 hours ago
















$begingroup$
Please do not update the code in your question to incorporate feedback from answers, doing so goes against the Question + Answer style of Code Review. This is not a forum where you should keep the most updated version in your question. Please see what you may and may not do after receiving answers.
$endgroup$
– Mast
8 hours ago




$begingroup$
Please do not update the code in your question to incorporate feedback from answers, doing so goes against the Question + Answer style of Code Review. This is not a forum where you should keep the most updated version in your question. Please see what you may and may not do after receiving answers.
$endgroup$
– Mast
8 hours ago












$begingroup$
@Mast I'm sorry, I didn't know. However, the edits I made weren't to incorporate the answers. I changed circles to squares, for example and colours I believe but didn't know I shouldn't. I won't do it again.
$endgroup$
– André Rocha
7 hours ago




$begingroup$
@Mast I'm sorry, I didn't know. However, the edits I made weren't to incorporate the answers. I changed circles to squares, for example and colours I believe but didn't know I shouldn't. I won't do it again.
$endgroup$
– André Rocha
7 hours ago












$begingroup$
Feel free to post a follow-up question with improved code if your code has changed significantly enough in the meantime. You can save such edits for then. No problem.
$endgroup$
– Mast
5 hours ago




$begingroup$
Feel free to post a follow-up question with improved code if your code has changed significantly enough in the meantime. You can save such edits for then. No problem.
$endgroup$
– Mast
5 hours ago










2 Answers
2






active

oldest

votes


















5












$begingroup$

For efficiency reasons, you should always do x1**2 + y1**2 < r**2 rather than sqrt(x1**2 + y1**2) < r, because sqrt is much much slower than pow. Because You don't need a square root to compare distances. This is the special case of x1**2 + y1**2 < x2**2 + y2**2.



Sometimes sqrt distances computing when you have a bunch of things on your screen becomes the slowest thing in your program. And there is absolutely no reason to do it.



My suggestion is to keep everything squared, until you really need to compute sqrt (which you don't)





Also, storing a direction in a string works ("DOWN"), but isn't very practical, it is a beginner pattern called 'stringly typed code'. You could instead make a constant called DOWN which corresponds to the vector pointing down ((0, -1) to make it simple or 0 - 1j if you like complex numbers (best imo) or a custom object if you like OOP). You can then replace:



if self.mov == "UP": 
self.pos[1] = self.pos[1] - SPEED
if self.mov == "DOWN":
self.pos[1] = self.pos[1] + SPEED
if self.mov == "LEFT":
self.pos[0] = self.pos[0] - SPEED
if self.mov == "RIGHT":
self.pos[0] = self.pos[0] + SPEED

# becomes

self.pos += self.mov


with constants, math becomes easier:



UP = 0 + 1j
DOWN = 0 - 1j
LEFT = -1 + 0j
RIGHT = 1 + 0j

2*DOWN + 5*LEFT # means move 2 cases down and 5 left how intuitive

if key == "UP" and self.mov != "DOWN":
self.mov = key
if key == "DOWN" and self.mov != "UP":
self.mov = key
if key == "RIGHT" and self.mov != "LEFT":
self.mov = key
if key == "LEFT" and self.mov != "RIGHT":
self.mov = key

# becomes

if key - self.mov:
self.mov = key


It takes time getting used to but it is worth it, you can always use tuples but they are the same except math doesn't work with them. The fact is Complex numbers are awesome it generalises nicely for arbitrary directions and distances. And if you assign to constants, you don't ever need to see them.






share|improve this answer










New contributor




Benoît Pilatte is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.






$endgroup$













  • $begingroup$
    I'll also suggest looking into numpy for direction vectors. It's not strictly necessary for 2D vectors (I actually really like that idea of using complex numbers, I might borrow that), but it'll certainly show up once you start looking into AI code, so you might as well get used to it now.
    $endgroup$
    – scnerd
    3 hours ago



















2












$begingroup$

I'm on my phone so I'll just mention something minor I noticed.



check_food's return is redundant. dist(snake, food) > sqr_size already evaluates to a boolean value. You just need to negate that:



def check_food(snake, food): #Check if food is eaten
return not dist(snake, food) > sqr_size


Or simply:



def check_food(snake, food): #Check if food is eaten
return dist(snake, food) <= sqr_size


And there's a similar situation in loser. The first two conditions are just returning True. They could be "connected" via or to be simplified.






share|improve this answer











$endgroup$













  • $begingroup$
    You are absolutely right. I deleted the check_food function altogether and just used eat = vars.dist(snake, food) < vars.sqr_size
    $endgroup$
    – André Rocha
    9 hours ago












  • $begingroup$
    @AndréRocha Unless you've double checked that logic, you may want to use <= instead, as that would be the opposite of >.
    $endgroup$
    – Carcigenicate
    9 hours ago










  • $begingroup$
    I did, it was eating the food while it was walking on an adjacent space. This way that won't happen
    $endgroup$
    – André Rocha
    9 hours ago











Your Answer





StackExchange.ifUsing("editor", function () {
return StackExchange.using("mathjaxEditing", function () {
StackExchange.MarkdownEditor.creationCallbacks.add(function (editor, postfix) {
StackExchange.mathjaxEditing.prepareWmdForMathJax(editor, postfix, [["\$", "\$"]]);
});
});
}, "mathjax-editing");

StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");

StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "196"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);

StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});

function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: false,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: null,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});


}
});






André Rocha is a new contributor. Be nice, and check out our Code of Conduct.










draft saved

draft discarded


















StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f213665%2ffirst-python-program-snake%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown

























2 Answers
2






active

oldest

votes








2 Answers
2






active

oldest

votes









active

oldest

votes






active

oldest

votes









5












$begingroup$

For efficiency reasons, you should always do x1**2 + y1**2 < r**2 rather than sqrt(x1**2 + y1**2) < r, because sqrt is much much slower than pow. Because You don't need a square root to compare distances. This is the special case of x1**2 + y1**2 < x2**2 + y2**2.



Sometimes sqrt distances computing when you have a bunch of things on your screen becomes the slowest thing in your program. And there is absolutely no reason to do it.



My suggestion is to keep everything squared, until you really need to compute sqrt (which you don't)





Also, storing a direction in a string works ("DOWN"), but isn't very practical, it is a beginner pattern called 'stringly typed code'. You could instead make a constant called DOWN which corresponds to the vector pointing down ((0, -1) to make it simple or 0 - 1j if you like complex numbers (best imo) or a custom object if you like OOP). You can then replace:



if self.mov == "UP": 
self.pos[1] = self.pos[1] - SPEED
if self.mov == "DOWN":
self.pos[1] = self.pos[1] + SPEED
if self.mov == "LEFT":
self.pos[0] = self.pos[0] - SPEED
if self.mov == "RIGHT":
self.pos[0] = self.pos[0] + SPEED

# becomes

self.pos += self.mov


with constants, math becomes easier:



UP = 0 + 1j
DOWN = 0 - 1j
LEFT = -1 + 0j
RIGHT = 1 + 0j

2*DOWN + 5*LEFT # means move 2 cases down and 5 left how intuitive

if key == "UP" and self.mov != "DOWN":
self.mov = key
if key == "DOWN" and self.mov != "UP":
self.mov = key
if key == "RIGHT" and self.mov != "LEFT":
self.mov = key
if key == "LEFT" and self.mov != "RIGHT":
self.mov = key

# becomes

if key - self.mov:
self.mov = key


It takes time getting used to but it is worth it, you can always use tuples but they are the same except math doesn't work with them. The fact is Complex numbers are awesome it generalises nicely for arbitrary directions and distances. And if you assign to constants, you don't ever need to see them.






share|improve this answer










New contributor




Benoît Pilatte is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.






$endgroup$













  • $begingroup$
    I'll also suggest looking into numpy for direction vectors. It's not strictly necessary for 2D vectors (I actually really like that idea of using complex numbers, I might borrow that), but it'll certainly show up once you start looking into AI code, so you might as well get used to it now.
    $endgroup$
    – scnerd
    3 hours ago
















5












$begingroup$

For efficiency reasons, you should always do x1**2 + y1**2 < r**2 rather than sqrt(x1**2 + y1**2) < r, because sqrt is much much slower than pow. Because You don't need a square root to compare distances. This is the special case of x1**2 + y1**2 < x2**2 + y2**2.



Sometimes sqrt distances computing when you have a bunch of things on your screen becomes the slowest thing in your program. And there is absolutely no reason to do it.



My suggestion is to keep everything squared, until you really need to compute sqrt (which you don't)





Also, storing a direction in a string works ("DOWN"), but isn't very practical, it is a beginner pattern called 'stringly typed code'. You could instead make a constant called DOWN which corresponds to the vector pointing down ((0, -1) to make it simple or 0 - 1j if you like complex numbers (best imo) or a custom object if you like OOP). You can then replace:



if self.mov == "UP": 
self.pos[1] = self.pos[1] - SPEED
if self.mov == "DOWN":
self.pos[1] = self.pos[1] + SPEED
if self.mov == "LEFT":
self.pos[0] = self.pos[0] - SPEED
if self.mov == "RIGHT":
self.pos[0] = self.pos[0] + SPEED

# becomes

self.pos += self.mov


with constants, math becomes easier:



UP = 0 + 1j
DOWN = 0 - 1j
LEFT = -1 + 0j
RIGHT = 1 + 0j

2*DOWN + 5*LEFT # means move 2 cases down and 5 left how intuitive

if key == "UP" and self.mov != "DOWN":
self.mov = key
if key == "DOWN" and self.mov != "UP":
self.mov = key
if key == "RIGHT" and self.mov != "LEFT":
self.mov = key
if key == "LEFT" and self.mov != "RIGHT":
self.mov = key

# becomes

if key - self.mov:
self.mov = key


It takes time getting used to but it is worth it, you can always use tuples but they are the same except math doesn't work with them. The fact is Complex numbers are awesome it generalises nicely for arbitrary directions and distances. And if you assign to constants, you don't ever need to see them.






share|improve this answer










New contributor




Benoît Pilatte is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.






$endgroup$













  • $begingroup$
    I'll also suggest looking into numpy for direction vectors. It's not strictly necessary for 2D vectors (I actually really like that idea of using complex numbers, I might borrow that), but it'll certainly show up once you start looking into AI code, so you might as well get used to it now.
    $endgroup$
    – scnerd
    3 hours ago














5












5








5





$begingroup$

For efficiency reasons, you should always do x1**2 + y1**2 < r**2 rather than sqrt(x1**2 + y1**2) < r, because sqrt is much much slower than pow. Because You don't need a square root to compare distances. This is the special case of x1**2 + y1**2 < x2**2 + y2**2.



Sometimes sqrt distances computing when you have a bunch of things on your screen becomes the slowest thing in your program. And there is absolutely no reason to do it.



My suggestion is to keep everything squared, until you really need to compute sqrt (which you don't)





Also, storing a direction in a string works ("DOWN"), but isn't very practical, it is a beginner pattern called 'stringly typed code'. You could instead make a constant called DOWN which corresponds to the vector pointing down ((0, -1) to make it simple or 0 - 1j if you like complex numbers (best imo) or a custom object if you like OOP). You can then replace:



if self.mov == "UP": 
self.pos[1] = self.pos[1] - SPEED
if self.mov == "DOWN":
self.pos[1] = self.pos[1] + SPEED
if self.mov == "LEFT":
self.pos[0] = self.pos[0] - SPEED
if self.mov == "RIGHT":
self.pos[0] = self.pos[0] + SPEED

# becomes

self.pos += self.mov


with constants, math becomes easier:



UP = 0 + 1j
DOWN = 0 - 1j
LEFT = -1 + 0j
RIGHT = 1 + 0j

2*DOWN + 5*LEFT # means move 2 cases down and 5 left how intuitive

if key == "UP" and self.mov != "DOWN":
self.mov = key
if key == "DOWN" and self.mov != "UP":
self.mov = key
if key == "RIGHT" and self.mov != "LEFT":
self.mov = key
if key == "LEFT" and self.mov != "RIGHT":
self.mov = key

# becomes

if key - self.mov:
self.mov = key


It takes time getting used to but it is worth it, you can always use tuples but they are the same except math doesn't work with them. The fact is Complex numbers are awesome it generalises nicely for arbitrary directions and distances. And if you assign to constants, you don't ever need to see them.






share|improve this answer










New contributor




Benoît Pilatte is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.






$endgroup$



For efficiency reasons, you should always do x1**2 + y1**2 < r**2 rather than sqrt(x1**2 + y1**2) < r, because sqrt is much much slower than pow. Because You don't need a square root to compare distances. This is the special case of x1**2 + y1**2 < x2**2 + y2**2.



Sometimes sqrt distances computing when you have a bunch of things on your screen becomes the slowest thing in your program. And there is absolutely no reason to do it.



My suggestion is to keep everything squared, until you really need to compute sqrt (which you don't)





Also, storing a direction in a string works ("DOWN"), but isn't very practical, it is a beginner pattern called 'stringly typed code'. You could instead make a constant called DOWN which corresponds to the vector pointing down ((0, -1) to make it simple or 0 - 1j if you like complex numbers (best imo) or a custom object if you like OOP). You can then replace:



if self.mov == "UP": 
self.pos[1] = self.pos[1] - SPEED
if self.mov == "DOWN":
self.pos[1] = self.pos[1] + SPEED
if self.mov == "LEFT":
self.pos[0] = self.pos[0] - SPEED
if self.mov == "RIGHT":
self.pos[0] = self.pos[0] + SPEED

# becomes

self.pos += self.mov


with constants, math becomes easier:



UP = 0 + 1j
DOWN = 0 - 1j
LEFT = -1 + 0j
RIGHT = 1 + 0j

2*DOWN + 5*LEFT # means move 2 cases down and 5 left how intuitive

if key == "UP" and self.mov != "DOWN":
self.mov = key
if key == "DOWN" and self.mov != "UP":
self.mov = key
if key == "RIGHT" and self.mov != "LEFT":
self.mov = key
if key == "LEFT" and self.mov != "RIGHT":
self.mov = key

# becomes

if key - self.mov:
self.mov = key


It takes time getting used to but it is worth it, you can always use tuples but they are the same except math doesn't work with them. The fact is Complex numbers are awesome it generalises nicely for arbitrary directions and distances. And if you assign to constants, you don't ever need to see them.







share|improve this answer










New contributor




Benoît Pilatte is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.









share|improve this answer



share|improve this answer








edited 3 hours ago





















New contributor




Benoît Pilatte is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.









answered 6 hours ago









Benoît PilatteBenoît Pilatte

1615




1615




New contributor




Benoît Pilatte is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.





New contributor





Benoît Pilatte is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.






Benoît Pilatte is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.












  • $begingroup$
    I'll also suggest looking into numpy for direction vectors. It's not strictly necessary for 2D vectors (I actually really like that idea of using complex numbers, I might borrow that), but it'll certainly show up once you start looking into AI code, so you might as well get used to it now.
    $endgroup$
    – scnerd
    3 hours ago


















  • $begingroup$
    I'll also suggest looking into numpy for direction vectors. It's not strictly necessary for 2D vectors (I actually really like that idea of using complex numbers, I might borrow that), but it'll certainly show up once you start looking into AI code, so you might as well get used to it now.
    $endgroup$
    – scnerd
    3 hours ago
















$begingroup$
I'll also suggest looking into numpy for direction vectors. It's not strictly necessary for 2D vectors (I actually really like that idea of using complex numbers, I might borrow that), but it'll certainly show up once you start looking into AI code, so you might as well get used to it now.
$endgroup$
– scnerd
3 hours ago




$begingroup$
I'll also suggest looking into numpy for direction vectors. It's not strictly necessary for 2D vectors (I actually really like that idea of using complex numbers, I might borrow that), but it'll certainly show up once you start looking into AI code, so you might as well get used to it now.
$endgroup$
– scnerd
3 hours ago













2












$begingroup$

I'm on my phone so I'll just mention something minor I noticed.



check_food's return is redundant. dist(snake, food) > sqr_size already evaluates to a boolean value. You just need to negate that:



def check_food(snake, food): #Check if food is eaten
return not dist(snake, food) > sqr_size


Or simply:



def check_food(snake, food): #Check if food is eaten
return dist(snake, food) <= sqr_size


And there's a similar situation in loser. The first two conditions are just returning True. They could be "connected" via or to be simplified.






share|improve this answer











$endgroup$













  • $begingroup$
    You are absolutely right. I deleted the check_food function altogether and just used eat = vars.dist(snake, food) < vars.sqr_size
    $endgroup$
    – André Rocha
    9 hours ago












  • $begingroup$
    @AndréRocha Unless you've double checked that logic, you may want to use <= instead, as that would be the opposite of >.
    $endgroup$
    – Carcigenicate
    9 hours ago










  • $begingroup$
    I did, it was eating the food while it was walking on an adjacent space. This way that won't happen
    $endgroup$
    – André Rocha
    9 hours ago
















2












$begingroup$

I'm on my phone so I'll just mention something minor I noticed.



check_food's return is redundant. dist(snake, food) > sqr_size already evaluates to a boolean value. You just need to negate that:



def check_food(snake, food): #Check if food is eaten
return not dist(snake, food) > sqr_size


Or simply:



def check_food(snake, food): #Check if food is eaten
return dist(snake, food) <= sqr_size


And there's a similar situation in loser. The first two conditions are just returning True. They could be "connected" via or to be simplified.






share|improve this answer











$endgroup$













  • $begingroup$
    You are absolutely right. I deleted the check_food function altogether and just used eat = vars.dist(snake, food) < vars.sqr_size
    $endgroup$
    – André Rocha
    9 hours ago












  • $begingroup$
    @AndréRocha Unless you've double checked that logic, you may want to use <= instead, as that would be the opposite of >.
    $endgroup$
    – Carcigenicate
    9 hours ago










  • $begingroup$
    I did, it was eating the food while it was walking on an adjacent space. This way that won't happen
    $endgroup$
    – André Rocha
    9 hours ago














2












2








2





$begingroup$

I'm on my phone so I'll just mention something minor I noticed.



check_food's return is redundant. dist(snake, food) > sqr_size already evaluates to a boolean value. You just need to negate that:



def check_food(snake, food): #Check if food is eaten
return not dist(snake, food) > sqr_size


Or simply:



def check_food(snake, food): #Check if food is eaten
return dist(snake, food) <= sqr_size


And there's a similar situation in loser. The first two conditions are just returning True. They could be "connected" via or to be simplified.






share|improve this answer











$endgroup$



I'm on my phone so I'll just mention something minor I noticed.



check_food's return is redundant. dist(snake, food) > sqr_size already evaluates to a boolean value. You just need to negate that:



def check_food(snake, food): #Check if food is eaten
return not dist(snake, food) > sqr_size


Or simply:



def check_food(snake, food): #Check if food is eaten
return dist(snake, food) <= sqr_size


And there's a similar situation in loser. The first two conditions are just returning True. They could be "connected" via or to be simplified.







share|improve this answer














share|improve this answer



share|improve this answer








edited 9 hours ago

























answered 9 hours ago









CarcigenicateCarcigenicate

3,40911531




3,40911531












  • $begingroup$
    You are absolutely right. I deleted the check_food function altogether and just used eat = vars.dist(snake, food) < vars.sqr_size
    $endgroup$
    – André Rocha
    9 hours ago












  • $begingroup$
    @AndréRocha Unless you've double checked that logic, you may want to use <= instead, as that would be the opposite of >.
    $endgroup$
    – Carcigenicate
    9 hours ago










  • $begingroup$
    I did, it was eating the food while it was walking on an adjacent space. This way that won't happen
    $endgroup$
    – André Rocha
    9 hours ago


















  • $begingroup$
    You are absolutely right. I deleted the check_food function altogether and just used eat = vars.dist(snake, food) < vars.sqr_size
    $endgroup$
    – André Rocha
    9 hours ago












  • $begingroup$
    @AndréRocha Unless you've double checked that logic, you may want to use <= instead, as that would be the opposite of >.
    $endgroup$
    – Carcigenicate
    9 hours ago










  • $begingroup$
    I did, it was eating the food while it was walking on an adjacent space. This way that won't happen
    $endgroup$
    – André Rocha
    9 hours ago
















$begingroup$
You are absolutely right. I deleted the check_food function altogether and just used eat = vars.dist(snake, food) < vars.sqr_size
$endgroup$
– André Rocha
9 hours ago






$begingroup$
You are absolutely right. I deleted the check_food function altogether and just used eat = vars.dist(snake, food) < vars.sqr_size
$endgroup$
– André Rocha
9 hours ago














$begingroup$
@AndréRocha Unless you've double checked that logic, you may want to use <= instead, as that would be the opposite of >.
$endgroup$
– Carcigenicate
9 hours ago




$begingroup$
@AndréRocha Unless you've double checked that logic, you may want to use <= instead, as that would be the opposite of >.
$endgroup$
– Carcigenicate
9 hours ago












$begingroup$
I did, it was eating the food while it was walking on an adjacent space. This way that won't happen
$endgroup$
– André Rocha
9 hours ago




$begingroup$
I did, it was eating the food while it was walking on an adjacent space. This way that won't happen
$endgroup$
– André Rocha
9 hours ago










André Rocha is a new contributor. Be nice, and check out our Code of Conduct.










draft saved

draft discarded


















André Rocha is a new contributor. Be nice, and check out our Code of Conduct.













André Rocha is a new contributor. Be nice, and check out our Code of Conduct.












André Rocha is a new contributor. Be nice, and check out our Code of Conduct.
















Thanks for contributing an answer to Code Review Stack Exchange!


  • Please be sure to answer the question. Provide details and share your research!

But avoid



  • Asking for help, clarification, or responding to other answers.

  • Making statements based on opinion; back them up with references or personal experience.


Use MathJax to format equations. MathJax reference.


To learn more, see our tips on writing great answers.




draft saved


draft discarded














StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f213665%2ffirst-python-program-snake%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown





















































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown

































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown







Popular posts from this blog

Polycentropodidae

Magento 2 Error message: Invalid state change requested

Paulmy