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()