#!/usr/bin/env python3
import sys
import random
import time
import contextlib
import termios
import timeout_decorator
import os
import argparse
import json
import info
from blessings import Terminal
class QuitGameError ( BaseException ) :
pass
class RanIntoSomethingError ( QuitGameError ) :
pass
class IsFullScreen ( BaseException ) :
pass
def draw_worm ( ) :
for location in worm_locations :
print ( do_move ( * reversed ( location ) ) + term . bright_blue ( ' o ' ) , end = ' ' )
print ( do_move ( * reversed ( worm_head ) ) + ' @ ' + do_move ( * reversed ( worm_head ) ) , end = ' ' )
def draw_frame ( ) :
print ( term . clear , end = ' ' )
print ( do_move ( 0 , 0 ) + term . on_red ( ' worm ' ) + term . bright_cyan_on_red ( ' .py ' ) + ' Press ' + term . bold_green ( ' I ' ) + ' for info, ' + term . bold_red ( ' Ctrl-C ' ) + ' to quit ' , end = ' ' )
if score > - 1 :
print ( do_move ( 0 , width - 12 ) + f ' Score: { " " * ( 4 - len ( str ( score ) ) ) } { term . bright_green ( str ( score ) ) } ' , end = ' ' )
print ( do_move ( 1 , 0 ) + term . white_on_red ( ' ┌ ' + ( ' ─ ' * ( width - 3 ) ) + ' ┐ ' ) , end = ' ' )
for y in range ( 2 , height - 1 ) :
print ( do_move ( y , 0 ) + term . white_on_red ( ' │ ' + do_move ( y , width - 2 ) + ' │ ' ) , end = ' ' )
print (
do_move ( height - 1 , 0 )
+ term . white_on_red ( ' └ ' )
+ term . white_on_red ( ' ─ ' * ( width - 3 ) )
+ term . white_on_red ( ' ┘ ' )
, end = ' ' )
print ( do_move ( * reversed ( bonus_location ) ) + term . black_on_green ( term . on_bright_green ( str ( bonus_points ) ) ) , end = ' ' )
draw_worm ( )
sys . stdout . flush ( )
def move_head ( direction , distance ) :
global size , worm_head , last_dir , worm_locations , bonus_location , bonus_points , score
if direction not in ' hjklHJKLABCDwasdx ' :
raise ValueError ( ' argument to move_head() must be one of `hjklHJKLABCDwasdx` ' )
if direction == ' x ' :
return
worm_locations . append ( worm_head . copy ( ) )
worm_head = worm_head . copy ( )
if direction in ' kKAw ' : #up
worm_head [ 1 ] - = 1
last_dir = ' A '
elif direction in ' jJBs ' : #down
worm_head [ 1 ] + = 1
last_dir = ' B '
elif direction in ' hHDa ' : #left
worm_head [ 0 ] - = 1
last_dir = ' D '
elif direction in ' lLCd ' : #right
worm_head [ 0 ] + = 1
last_dir = ' C '
while len ( worm_locations ) > size :
worm_locations . pop ( 0 )
if worm_head in worm_locations \
or worm_head [ 1 ] < = 1 \
or worm_head [ 1 ] > = height - 1 \
or worm_head [ 0 ] < = 0 \
or worm_head [ 0 ] > = width - 2 :
raise RanIntoSomethingError ( )
if worm_head == bonus_location :
size + = bonus_points
score + = bonus_points
new_bonus ( )
if distance > 1 :
move_head ( direction , distance - 1 )
@contextlib . contextmanager
def decanonize ( fd ) :
old_settings = termios . tcgetattr ( fd )
new_settings = old_settings [ : ]
new_settings [ 3 ] & = ~ termios . ICANON
termios . tcsetattr ( fd , termios . TCSAFLUSH , new_settings )
yield
termios . tcsetattr ( fd , termios . TCSAFLUSH , old_settings )
@timeout_decorator . timeout ( 1 )
def run ( * _ ) :
global do_automove , do_help
if do_automove :
move_head ( last_dir , 1 )
draw_frame ( )
do_automove = True
save_game ( )
k = await_keys ( ' hjklHJKLABCDwasdiI ' )
if k in ' hjklHJKLABCDwasd ' :
move_head ( k , 10 if k in ' HJKL ' else 1 )
draw_frame ( )
do_automove = False
return
elif k in ' ' :
save_game ( )
sys . exit ( 0 )
elif k in ' iI ' :
do_help = True
return
def await_keys ( keys ) :
while True :
k = sys . stdin . read ( 1 )
if k in keys :
return k
def new_bonus ( ) :
global bonus_location , bonus_points
bonus_points = random . randint ( 1 , 9 )
bonus_location = worm_head
while worm_head == bonus_location or bonus_location in worm_locations :
bonus_location = [
random . randint ( 1 , width - 3 ) ,
random . randint ( 2 , height - 2 ) ,
]
def do_move ( y , x ) :
y + = ( term . height - height ) / / 2
x + = ( term . width - width ) / / 2
return term . move ( y , x )
def save_game ( ) :
if not args . full_screen :
with open ( gamesave_path , ' w+ ' ) as f :
json . dump ( [ worm_locations , worm_head , last_dir , score , size , bonus_location , bonus_points , do_automove , do_help ] , f )
term = Terminal ( )
gamesave_path = os . path . join ( os . getenv ( ' HOME ' ) , ' .worm.py-gamesave ' )
parser = argparse . ArgumentParser ( )
parser . add_argument ( " --full-screen " , ' -f ' , help = " use entire screen (disables game saving) " , action = ' store_true ' )
parser . add_argument ( " --delete-save " , help = " delete saved game and exit " , action = ' store_true ' )
args = parser . parse_args ( )
if args . delete_save :
try :
os . unlink ( gamesave_path )
print ( " Saved game deleted. " )
except FileNotFoundError :
print ( " No saved game found. " )
except Exception as e :
print ( " An error occurred. " )
print ( str ( type ( e ) ) . split ( " ' " ) [ 1 ] + ' : ' + str ( e ) )
sys . exit ( 1 )
sys . exit ( 0 )
if not args . full_screen :
height = 24
width = 80
else :
height = term . height
width = term . width
worm_y = height / / 2
x_offset = ( term . width - width ) / / 2
info_1 , info_2 = info . get_infos ( term , do_move , height , width , x_offset )
try :
if args . full_screen :
raise IsFullScreen ( )
with open ( gamesave_path ) as f :
save = json . load ( f )
worm_locations , worm_head , last_dir , score , size , bonus_location , bonus_points , do_automove , do_help = save
except ( FileNotFoundError , IsFullScreen ) :
size = 7
worm_locations = [ [ i + 10 , worm_y ] for i in range ( size ) ]
worm_head = [ size + 10 , worm_y ]
last_dir = ' x '
score = 0
new_bonus ( )
do_automove = True
do_help = False
try :
with term . fullscreen ( ) :
os . system ( ' stty raw -echo ' )
draw_frame ( )
while True :
if do_help :
for info in ( info_1 , info_2 ) :
os . system ( ' stty -raw ' )
print ( info , end = ' ' )
sys . stdout . flush ( )
os . system ( ' stty raw ' )
k = await_keys ( ' cC ' )
if k in ' ' :
save_game ( )
sys . exit ( 0 )
do_help = False
else :
try :
run ( )
except timeout_decorator . timeout_decorator . TimeoutError :
pass
except KeyboardInterrupt :
save_game ( )
sys . exit ( 0 )
except RanIntoSomethingError :
try :
if not args . full_screen :
os . unlink ( gamesave_path )
except FileNotFoundError :
pass
os . system ( ' stty -raw echo ' )
print ( ' ' , end = ' \r \n ' )
if size + 1 > = ( height - 3 ) * ( width - 1 ) :
print ( ' You won! ' , end = ' \r \n ' )
else :
print ( ' Well, you ran into something and the game is over. ' , end = ' \r \n ' )
print ( f ' Your final score was { score } ' , end = ' \r \n ' )
print ( ' ' , end = ' \r \n ' )
finally :
os . system ( ' stty -raw echo ' )