ConsoleSnake
ConsoleSnake
Snake game in your windows, linux or macOS console
Source Code: main.py
# -*- coding: UTF-8 -*-
import time
import os
from random import randint
from getch import KBHit
class Snake:
def __init__(self, x, y):
self.parts = [[1, 1]]
self.length = 1
self.dir = 'd'
self.skins = ['O']
self.fruit = [randint(2, x), randint(2, y)]
self.size = [x, y]
self.print_in_coords()
def get_opposites(self):
return {"w": "s", "s": "w", "d": "a", "a":"d"}
def set_skins(self):
"""
This iterates each snake part, and based where the adjacent ones are,
it gives it a skin between the following: │ ─ └ ┐ ┌ ┘
"""
skins = ['O']
coords_subtraction = lambda a, b: [x1 - x2 for (x1, x2) in zip(a, b)]
for i in range(1, len(self.parts)):
if i == len(self.parts)-1:
a = self.parts[-2]
b = self.parts[-1]
else:
b = self.parts[i+1]
a = self.parts[i-1]
diff = coords_subtraction(a, b)
if diff[0] == 0:
skins.append('│')
elif diff[1] == 0:
skins.append('─')
else:
a = self.parts[i-1]
b = self.parts[i]
diff2 = coords_subtraction(a, b)
if sum(diff) == 0:
if sum(diff2) == 1:
skins.append('└')
else:
skins.append('┐')
else:
if diff2[1] == -1 or diff2[0] == 1:
skins.append('┌')
else:
skins.append('┘')
self.skins = skins
def print_in_coords(self):
"""
Prints the field of game with '·',
prints the snake body parts,
prints the fruit ('X')
"""
coords = self.parts
os.system('cls' if os.name == 'nt' else 'clear')
for i in range(self.size[1], 0, -1):
for j in range(1, self.size[0]+1):
if [j, i] in coords:
print(self.skins[coords.index([j, i])], end=' ')
elif [j, i] == self.fruit:
print('X', end=' ')
else:
print('·', end=' ')
print('')
def update_coors(self):
"""
Makes every part of the snake move to where the following was,
except the head, that moves to the direction the user input
"""
for i in range(len(self.parts)-1, 0, -1):
self.parts[i] = self.parts[i-1][:]
if self.dir == 'w':
self.parts[0][1] += 1
elif self.dir == 'd':
self.parts[0][0] += 1
elif self.dir == 's':
self.parts[0][1] -= 1
elif self.dir == 'a':
self.parts[0][0] -= 1
def check_fruit(self):
"""
Checks if the snake's head is in the same place as the fruit,
if so, the snake grows and another fruit is spawned
"""
if self.parts[0] == self.fruit:
self.grow()
self.generate_fruit()
def alive(self):
"""
Check if the head hit a body part or has crossed the limits
"""
head = self.parts[0]
if (head in self.parts[1:]) or (not(0 < head[0] <= self.size[0])) or (not(0 < head[1] <= self.size[1])):
return False
return True
def get_action(self, character):
if (character in 'wasd') and (self.get_opposites()[character] != self.dir or len(self.parts) == 1):
self.dir = character
self.update_coors()
self.check_fruit()
self.set_skins()
self.print_in_coords()
return self.alive()
def generate_fruit(self):
new_coords = [randint(1,self.size[0]), randint(1,self.size[1])]
if new_coords in self.parts:
self.generate_fruit()
else:
self.fruit = new_coords
def grow(self):
if len(self.parts) > 1:
last = self.parts[-1]
sec_last = self.parts[-2]
diff = [x1 - x2 for (x1, x2) in zip(sec_last, last)]
if diff[0] == 0:
if diff[1] > 0:
self.parts.append([last[0], last[1]-1])
else:
self.parts.append([last[0], last[1]+1])
elif diff[0] > 0:
self.parts.append([last[0]-1, last[1]])
else:
self.parts.append([last[0]+1, last[1]])
else:
head = self.parts[0]
if self.dir == 'w':
self.parts.append([head[0], head[1]-1])
elif self.dir == 'd':
self.parts.append([head[0]-1, head[1]])
elif self.dir == 's':
self.parts.append([head[0], head[1]+1])
elif self.dir == 'a':
self.parts.append([head[0]+1, head[1]])
self.length += 1
def main():
snake = Snake(15, 10) # This means the game field is 15x10
update_time = .125 # This is how much time there is between updates, 1/update_time = fps
keep_playing = True
kb = KBHit()
while keep_playing:
t = 0
key_stroke = ' '
while t < update_time:
start = time.time()
if kb.kbhit():
key_stroke = kb.getch()
end = time.time()
t += end - start
keep_playing = snake.get_action(key_stroke)
if snake.size[0] * snake.size[1] <= snake.length:
print('You win!')
break
kb.set_normal_term()
print('Score:', snake.length)
while True:
again = input('Keep playing? (y/n) ')
if again.lower() == 'y':
main()
break
elif again.lower() == 'n':
print('Bye')
break
else:
print('Input a valid answer')
if __name__ == "__main__":
main()