# Snake Game using python and tkinter

I have written a Snake game using Python's Tkinter library.

I am a beginner to programming. I learned some python alone and in school. However, most of what we did in school is algorithms/data structures and problem-solving (school program geared towards mathematics). Not much coding.

Lately, I picked up Python again. I was introduced to OOP in Python and used Tkinter before deciding to give Snake a try. Anyway, here is a link to my code in github. This is my first quasi-real application.

from tkinter import*
from random import randint

# constants that go in the making of the grid used for the snake's movment
PIXEL = 10
STEP = 2 * PIXEL
# constants that go into specifying the shapes' sizes
OB_SIZE_FACTOR = 1
SN_SIZE_FACTOR = 0.9
OB_SIZE = PIXEL * OB_SIZE_FACTOR
SN_SIZE = PIXEL * SN_SIZE_FACTOR
# color constants
BG_COLOR = 'black'
OB_COLOR = 'red'
SN_COLOR = 'white'
# a dictionary to ease access to a shape's type in the Shape class
SN = 'snake'
OB = 'obstacle'
SIZE = {SN: SN_SIZE, OB: OB_SIZE}
# constants for keyboard input
UP = 'Up'
DOWN = 'Down'
RIGHT = 'Right'
LEFT = 'Left'
DIRECTIONS = {UP: [0, -1], DOWN: [0, 1], RIGHT: [1, 0], LEFT: [-1, 0]}
AXES = {UP: 'Vertical', DOWN: 'Vertical', RIGHT: 'Horizontal', LEFT: 'Horizontal'}
# refresh time for the perpetual motion
REFRESH_TIME = 100

class Master(Canvas):
"""create the game canvas, the snake, the obstacle, keep track of the score"""
def __init__(self, boss=None):
super().__init__(boss)
self.configure(width=WD, height=HT, bg=BG_COLOR)
self.running = 0
self.snake = None
self.obstacle = None
self.direction = None
self.current = None
self.score = Scores(boss)

def start(self):
"""start snake game"""
if self.running == 0:
self.snake = Snake(self)
self.obstacle = Obstacle(self)
self.direction = RIGHT
self.current = Movement(self, RIGHT)
self.current.begin()
self.running = 1

def clean(self):
"""restarting the game"""
if self.running == 1:
self.score.reset()
self.current.stop()
self.running = 0
self.obstacle.delete()
for block in self.snake.blocks:
block.delete()

def redirect(self, event):
"""taking keyboard inputs and moving the snake accordingly"""
if 1 == self.running and \
event.keysym in AXES.keys() and\
AXES[event.keysym] != AXES[self.direction]:
self.current.flag = 0
self.direction = event.keysym
self.current = Movement(self, event.keysym)  # a new instance at each turn to avoid confusion/tricking
self.current.begin()  # program gets tricked if the user presses two arrow keys really quickly

class Scores:
"""Objects that keep track of the score and high score"""
def __init__(self, boss=None):
self.counter = StringVar(boss, '0')
self.maximum = StringVar(boss, '0')

def increment(self):
score = int(self.counter.get()) + 1
maximum = max(score, int(self.maximum.get()))
self.counter.set(str(score))
self.maximum.set(str(maximum))

def reset(self):
self.counter.set('0')

class Shape:
"""This is a template to make obstacles and snake body parts"""
def __init__(self, can, a, b, kind):
self.can = can
self.x, self.y = a, b
self.kind = kind
if kind == SN:
self.ref = Canvas.create_rectangle(self.can,
a - SN_SIZE, b - SN_SIZE,
a + SN_SIZE, b + SN_SIZE,
fill=SN_COLOR,
width=2)
elif kind == OB:
self.ref = Canvas.create_oval(self.can,
a - OB_SIZE, b - OB_SIZE,
a + SN_SIZE, b + SN_SIZE,
fill=OB_COLOR,
width=2)

def modify(self, a, b):
self.x, self.y = a, b
self.can.coords(self.ref,
a - SIZE[self.kind], b - SIZE[self.kind],
a + SIZE[self.kind], b + SIZE[self.kind])

def delete(self):
self.can.delete(self.ref)

class Obstacle(Shape):
"""snake food"""
def __init__(self, can):
"""only create the obstacles where there is no snake body part"""
self.can = can
n, m = randint(0, p), randint(0, p)
a, b = PIXEL * (2 * n + 1), PIXEL * (2 * m + 1)
while [a, b] in [[block.x, block.y] for block in self.can.snake.blocks]:
n, m = randint(0, p), randint(0, p)
a, b = PIXEL * (2 * n + 1), PIXEL * (2 * m + 1)
super().__init__(can, a, b, OB)

class Block(Shape):
"""snake body part"""
def __init__(self, can, a, y):
super().__init__(can, a, y, SN)

class Snake:
"""a snake keeps track of its body parts"""
def __init__(self, can):
"""initial position chosen by me"""
self.can = can
a = PIXEL + 2 * int(GRADUATION/4) * PIXEL
self.blocks = [Block(can, a, a), Block(can, a, a + STEP)]

def move(self, path):
"""an elementary step consisting of putting the tail of the snake in the first position"""
a = (self.blocks[-1].x + STEP * path) % WD
b = (self.blocks[-1].y + STEP * path) % HT
if a == self.can.obstacle.x and b == self.can.obstacle.y:  # check if we find food
self.can.score.increment()
self.can.obstacle.delete()
self.blocks.append(Block(self.can, a, b))
self.can.obstacle = Obstacle(self.can)
elif [a, b] in [[block.x, block.y] for block in self.blocks]:  # check if we hit a body part
self.can.clean()
else:
self.blocks.modify(a, b)
self.blocks = self.blocks[1:] + [self.blocks]

class Movement:
"""object that enters the snake into a perpetual state of motion in a predefined direction"""
def __init__(self, can, direction):
self.flag = 1
self.can = can
self.direction = direction

def begin(self):
"""start the perpetual motion"""
if self.flag > 0:
self.can.snake.move(DIRECTIONS[self.direction])
self.can.after(REFRESH_TIME, self.begin)

def stop(self):
"""stop the perpetual movement"""
self.flag = 0

if __name__ == "__main__":
root = Tk()
root.title("Snake Game")
game = Master(root)
game.grid(column=1, row=0, rowspan=3)
root.bind("<Key>", game.redirect)
buttons = Frame(root, width=35)
Button(buttons, text='Start', command=game.start).grid()
Button(buttons, text='Stop', command=game.clean).grid()
Button(buttons, text='Quit', command=root.destroy).grid()
buttons.grid(column=0, row=0)
scoreboard = Frame(root, width=35, height=2 * HT / 5)
Label(scoreboard, text='Game Score').grid()
Label(scoreboard, textvariable=game.score.counter).grid()
Label(scoreboard, text='High Score').grid()
Label(scoreboard, textvariable=game.score.maximum).grid()
scoreboard.grid(column=0, row=2)
root.mainloop() • You might be interested in this question and its answer. Jan 25, 2018 at 23:06