snake.py/snake.py

288 lines
8.6 KiB
Python

#!/usr/bin/env python3
import sys
import os
import tty
import termios
from select import select, error
from getopt import getopt, GetoptError
from math import floor
from random import randint, choice
from time import sleep
STDIN_FILENO = sys.stdin.fileno()
body=[]
cherries=[]
paused=False
snake_col=(255, 255, 255)
cherry_col=(255, 0, 0)
bg_col=(0, 0, 0)
arg_cherry=1
interval=0.1
rainbow_snake=False
rainbow_cherry=False
rainbow_bg=False
length=1
grow=1
growths=0
should_grow = False
die_to_self=True
die_to_wall=True
score = 0
terminal_settings = termios.tcgetattr(STDIN_FILENO)
def __select(iwtd, owtd, ewtd):
while True:
try:
return select(iwtd, owtd, ewtd, 0)
except error:
err = sys.exc_info()[1]
if err.args[0] == errno.EINTR:
return([], [], [])
else:
raise
def hex_to_rgb(hexa):
try:
return tuple(int(hexa.lstrip('#')[i:i+2], 16) for i in (0, 2, 4))
except:
_help()
def get_args():
global arg_cherry
global snake_col
global bg_col
global cherry_col
global interval
global rainbow_snake
global rainbow_cherry
global rainbow_bg
global length
global grow
global die_to_self
global die_to_wall
try:
opts, args = getopt(sys.argv[1:], 'hnwc:b:s:r:i:l:g:', ['cherries=', 'background=', 'background-color=', 'cherry-color=', 'snake=', 'snake-color=', 'interval=', 'length=', 'grow=', 'no-self-collision', 'no-wall-collision', 'help'])
except GetoptError:
_help()
for opt, arg in opts:
try:
if opt in ("-c", "--cherries"):
arg_cherry = int(arg)
elif opt in ("-b", "--background", "--background-color"):
if int(arg) == -1:
rainbow_bg=True
else:
bg_col = hex_to_rgb(arg)
elif opt in ("-r", "--cherry-color"):
if int(arg) == -1:
rainbow_cherry=True
else:
cherry_col = hex_to_rgb(arg)
elif opt in ("-s", "--snake", "--snake-color"):
if int(arg) == -1:
rainbow_snake=True
else:
snake_col = hex_to_rgb(arg)
elif opt in ("-i", "--interval"):
interval = float(arg)
elif opt in ("-l", "--length"):
length = int(arg)
elif opt in ("-g", "--grow"):
grow = int(arg)
elif opt in ("-n", "--no-self-collision"):
die_to_self=False
elif opt in ("-w", "--no-wall-collision"):
die_to_wall=False
elif opt in ('-h', '--help'):
big_help()
except ValueError:
_help()
def cherry():
global body
global cherries
used_spaces = body.copy()
used_spaces.extend(cherries)
lst = list(set(all_tuples)-set(used_spaces))
if len(lst) > 0:
return choice(lst)
else:
return (-1, -1)
def _help():
print("snake [OPTIONS...]", end='\r\n')
exit()
def big_help():
print(
"""python snake.py [OPTIONS...]
OPTIONS:
-c INTEGER How many cherries will exist at once
--cherries=
-b HEX Color of the background
--background= --background-color=
-s HEX Color of the snake (-1 for random)
--snake= --snake-color=
-r HEX Color of the cherry
--cherry-color=
-i INTEGER How many seconds between movements
--interval=
-l INTEGER Initial length of snake
--length=
-g INTEGER How much to grow from cherries
--grow=
-n Turn off collision with the snake's body
--no-self-collision
-w Turn off collision with the walls
--no-wall-collision
-h --help Show this page and quit
""", end='\r\n')
exit()
def stop():
print('\033[0m\033[?25h\033[?1049h', end='')
termios.tcsetattr(STDIN_FILENO, termios.TCSADRAIN, terminal_settings)
print(f'Score: {score}', end='\r\n')
exit()
def win():
print('\033[0m\033[?25h\033[?1049h', end='')
termios.tcsetattr(STDIN_FILENO, termios.TCSADRAIN, terminal_settings)
print('You win!', end='\r\n')
exit()
try:
sx, sy = os.get_terminal_size()
all_tuples = []
for i in range(sx):
for j in range(sy):
all_tuples.append((i, j))
direction = 0
tty.setcbreak(STDIN_FILENO)
print('\033[?25l\033[?1049h', end='')
get_args()
for i in range(length):
x,y = floor(sx/2), floor(sy/2)+i
body.append((x,y))
for i in range(arg_cherry):
cherries.append((-1,-1))
for i in range(len(cherries)):
cherries[i] = cherry()
while True:
if STDIN_FILENO in __select([STDIN_FILENO], [], [])[0]:
data=os.read(STDIN_FILENO, 1)
if len(data) == 0:
stop()
if data[0] == 27:
data=os.read(STDIN_FILENO, 1)
if len(data) == 0:
stop()
if data[0] == 91:
data=os.read(STDIN_FILENO, 1)
if len(data) == 0:
stop()
if data[0] == 65 and (direction != 1 or len(body) == 1):
direction = 0
elif data[0] == 66 and (direction != 0 or len(body) == 1):
direction = 1
elif data[0] == 67 and (direction != 3 or len(body) == 1):
direction = 2
elif data[0] == 68 and (direction != 2 or len(body) == 1):
direction = 3
elif data[0] == 70:
if paused:
stop()
elif data[0] == 72:
paused = not paused
elif data[0] in (119, 87):
direction = 0
elif data[0] in (115, 83):
direction = 1
elif data[0] in (100, 68):
direction = 2
elif data[0] in (97, 65):
direction = 3
elif data[0] in (101, 69):
if paused:
stop()
elif data[0] in (112, 80):
paused = not paused
if not paused:
last = body[0]
if direction == 0:
body[0] = (body[0][0], body[0][1]-1)
elif direction == 1:
body[0] = (body[0][0], body[0][1]+1)
elif direction == 2:
body[0] = (body[0][0]+1, body[0][1])
elif direction == 3:
body[0] = (body[0][0]-1, body[0][1])
for i in range(len(body)-1):
temp = body[i+1]
body[i+1] = last
last = temp
if body[0] in cherries:
cherries[cherries.index(body[0])] = cherry()
should_grow = True
score += 1
if growths == grow:
growths = 0
should_grow = False
elif should_grow:
new = (body[-1][0], body[-1][1])
body.append(new)
growths += 1
if body.count(body[0]) > 1 and len(body) > 2 and die_to_self:
stop()
if body[0][0] >= sx or body[0][0] < 0 or body[0][1] >= sy-1 or body[0][1] < 0:
if die_to_wall:
stop()
else:
body[0] = (body[0][0] % sx, body[0][1] % sy)
for j in range(sy-1):
print(f'\033[{j+1};0H', end='')
for i in range(sx):
if (i, j) in body:
if rainbow_snake:
snake_col = (randint(0,256), randint(0,256), randint(0,256))
print(f'\033[48;2;{snake_col[0]};{snake_col[1]};{snake_col[2]}m ', end='')
elif (i, j) in cherries:
if rainbow_cherry:
cherry_col = (randint(0,256), randint(0,256), randint(0,256))
print(f'\033[48;2;{cherry_col[0]};{cherry_col[1]};{cherry_col[2]}m ', end='')
else:
if rainbow_bg:
bg_col = (randint(0,256), randint(0,256), randint(0,256))
print(f'\033[48;2;{bg_col[0]};{bg_col[1]};{bg_col[2]}m ', end='')
print(f'\033[0mScore: {score}', end='')
if not paused:
print(f'\033[{sy+1};{sx-5}H ', end='')
else:
print(f'\033[{sy+1};{sx-5}HPaused', end='')
if list(set(all_tuples)-set(body)) == []:
win()
if interval > 0:
sleep(interval)
except KeyboardInterrupt:
stop()