Compare commits

..

13 Commits
1 ... main

Author SHA1 Message Date
Plaza521 bf638e711e
fix creating Player object 2023-03-16 23:14:44 +03:00
Plaza521 a89e41cd68
fix bug with turn 2023-03-06 01:30:06 +03:00
Plaza521 aff3036a0d
fix issue #1 and fix pause 2022-11-06 22:18:02 +03:00
Plaza521 a77fe7840d
add color 2022-10-29 04:25:09 +03:00
Plaza521 4840b016db
refactor 2022-10-27 19:59:23 +03:00
Plaza521 b6a097bbb3
refactor food and rename pause_game function 2022-10-27 17:41:10 +03:00
Plaza521 a96f8fcc71
delete unused var 2022-10-27 17:29:22 +03:00
Plaza521 9e82c9478a
refactor 2022-10-27 17:03:11 +03:00
Plaza521 95e1653b1a
Update README.md 2022-10-27 15:30:05 +03:00
Plaza521 996eebe470
add pause and refactor 2022-10-27 15:29:28 +03:00
Plaza521 ffc75251f1
small refactor 2022-10-27 00:29:36 +03:00
Plaza521 3982e7ab40
add score 2022-10-26 23:43:49 +03:00
Plaza521 713504a3d5
add reqirements 2022-10-26 23:17:12 +03:00
9 changed files with 141 additions and 70 deletions

View File

@ -4,4 +4,5 @@ Snake, but in console
Default keys: Default keys:
-- --
W A S D - move W A S D - move
Q - quit Q - quit
P - pause

View File

@ -4,9 +4,8 @@ from settings import *
class Food(Point): class Food(Point):
def __init__(self, x, y, pl): def __init__(self, x, y):
Point.__init__(self, x, y) Point.__init__(self, x, y)
self.pl = pl
def generate_new(self) -> None: def generate_new(self) -> None:
self.x = randint(0, WIDTH - 1) self.x = randint(0, WIDTH - 1)

View File

@ -9,10 +9,10 @@ if platform == "win32":
class COORDSET(Structure): class COORDSET(Structure):
_fields_ = [("X", c_long), ("Y", c_long)] _fields_ = [("X", c_long), ("Y", c_long)]
def _set_cursor_position(x: int, y: int) -> None: def set_cursor_position(x: int, y: int) -> None:
windll.kernel32.SetConsoleCursorPosition(STDHANDLE, COORDSET(x, y)) windll.kernel32.SetConsoleCursorPosition(STDHANDLE, COORDSET(x, y))
else: else:
def _set_cursor_position(x: int, y: int) -> None: def set_cursor_position(x: int, y: int) -> None:
print(f"\033[{x};{y}H") print(f"\033[{x};{y}H")
@ -23,14 +23,20 @@ class Frame:
self.matrix = [[SPACE] * width for line in range(height)] self.matrix = [[SPACE] * width for line in range(height)]
def __str__(self) -> str: def __str__(self) -> str:
out_string = f"Width:\n {self.width}\n" return (
out_string += f"Height:\n {self.height}\n" f"Width:\n {self.width}\n"
return out_string f"Height:\n {self.height}"
)
def draw( def draw(
self, x: int, y: int, self,
x: int,
y: int,
value: int = WALL, value: int = WALL,
width: int = 1, height: int = 1 width: int = 1,
height: int = 1
) -> None: ) -> None:
if not isinstance(value, int): if not isinstance(value, int):
raise TypeError("Value must be int") raise TypeError("Value must be int")
@ -40,27 +46,29 @@ class Frame:
self.matrix[y + line][x + column] = value self.matrix[y + line][x + column] = value
def show(self) -> None: def show(self) -> None:
_set_cursor_position(0, 0) set_cursor_position(0, 0)
out_string = f"{'' * (self.width * 2)}\n" out_string = f"{WALL_COLOR}{'' * (self.width * 2)}{RESET_COLOR}\n"
for line in self.matrix: for line in self.matrix:
to_str = '' to_str = ''
to_str += '' to_str += f'{WALL_COLOR}{RESET_COLOR}'
for elem in line: for elem in line:
if elem == SPACE: if elem == SPACE:
to_str += " " to_str += TT_SPACE
elif elem == WALL: elif elem == WALL:
to_str += "██" to_str += TT_WALL
elif elem == FOOD: elif elem == FOOD:
to_str += "@@" to_str += TT_FOOD
elif elem == WALL_FOOD: elif elem == WALL_FOOD:
to_str += "@█" to_str += TT_WALL_FOOD
to_str += '\n' elif elem == HEAD:
to_str += TT_HEAD
to_str += f'{WALL_COLOR}{RESET_COLOR}\n'
out_string += to_str out_string += to_str
out_string += f"{'' * (self.width * 2)}" out_string += f"{WALL_COLOR}{'' * (self.width * 2)}{RESET_COLOR}"
print(out_string) print(out_string)

66
main.py
View File

@ -1,46 +1,80 @@
# from frame import Frame
from settings import * from settings import *
from player import Player from player import Player
import keyboard as kb import keyboard as kb
from out import Out from out import Out
from os import system from os import system
from time import sleep, time
class Game: class Game:
def __init__(self) -> None: def __init__(self) -> None:
self.running = True self.running = True
self.is_pause = False
self.pl = Player() self.pl = Player()
self.out = Out() self.out = Out(self.pl)
kb.add_hotkey(QUIT_BUTTON, self.stop_game) kb.add_hotkey(QUIT_BUTTON, self.stop_game)
kb.add_hotkey(LEFT_BUTTON, self.pl.left) kb.add_hotkey(PAUSE_BUTTON, self.switch_pause)
kb.add_hotkey(RIGHT_BUTTON, self.pl.right) kb.add_hotkey(
kb.add_hotkey(UP_BUTTON, self.pl.up) LEFT_BUTTON,
kb.add_hotkey(DOWN_BUTTON, self.pl.down) self.pl.left,
args=[self]
)
kb.add_hotkey(
RIGHT_BUTTON,
self.pl.right,
args=[self]
)
kb.add_hotkey(
UP_BUTTON,
self.pl.up,
args=[self]
)
kb.add_hotkey(
DOWN_BUTTON,
self.pl.down,
args=[self]
)
def switch_pause(self) -> None:
self.is_pause = not self.is_pause
def stop_game(self) -> None: def stop_game(self) -> None:
self.running = False if not self.is_pause:
self.running = False
def update(self) -> None:
pass
def output(self) -> None:
pass
def play(self) -> None: def play(self) -> None:
system("clear||cls") system("clear||cls")
print()
start_time = time()
different_between_time = 1 / FPS
while self.running: while self.running:
try: try:
self.pl.update() sleep(1 / FPS - different_between_time)
self.out.draw(self.pl) start_time = time()
if not self.is_pause:
self.pl.input()
self.pl.update()
self.out.draw()
end_time = time()
different_between_time = start_time - end_time
except IndexError as e: except IndexError as e:
self.running = False self.running = False
print(e) print(e)
except KeyboardInterrupt:
return
input("Press enter to leave from game.\n")
def main() -> None: def main() -> None:
Game().play() game = Game()
game.play()
if __name__ == '__main__': if __name__ == '__main__':

19
out.py
View File

@ -4,26 +4,28 @@ from frame import Frame
class Out: class Out:
def __init__(self) -> None: def __init__(self, pl: Player) -> None:
self.width = WIDTH self.width = WIDTH
self.height = HEIGHT self.height = HEIGHT
self.fps = FPS self.pl = pl
def draw(self, pl: Player) -> None: def draw(self) -> None:
frame = Frame(self.width, self.height) frame = Frame(self.width, self.height)
pl = self.pl
for point in pl.body: for point in pl.body:
if point.x < 0 or point.y < 0:
raise IndexError("Snake has collision with walls")
elif point.x >= WIDTH or point.y >= HEIGHT:
raise IndexError("Snake has collision with walls")
frame.draw( frame.draw(
x=point.x, y=point.y, x=point.x, y=point.y,
value=WALL, value=WALL,
width=1, height=1 width=1, height=1
) )
frame.draw(
x=pl.body[-1].x, y=pl.body[-1].y,
value=HEAD,
width=1, height=1
)
if frame.see(pl.food.x, pl.food.y) == WALL: if frame.see(pl.food.x, pl.food.y) == WALL:
frame.draw( frame.draw(
x=pl.food.x, y=pl.food.y, x=pl.food.x, y=pl.food.y,
@ -36,3 +38,4 @@ class Out:
) )
frame.show() frame.show()
print(f"Score: {pl.score}")

View File

@ -1,50 +1,62 @@
from settings import * from settings import *
from point import Point from point import Point
from food import Food from food import Food
from time import sleep
from itertools import permutations
class Player: class Player:
def __init__(self) -> None: def __init__(self) -> None:
self.start_direciton = MAIN_DIRECTION
self.direction = MAIN_DIRECTION self.direction = MAIN_DIRECTION
self.body = [Point(MAIN_X, MAIN_Y)] self.body = [Point(MAIN_X, MAIN_Y)]
self.food = Food(0, 0, self) self.food = Food(0, 0)
self.food.generate_new() self.food.generate_new()
def update(self) -> None: self.score = 1
sleep(1 / FPS)
def input(self) -> None:
if self.direction == D_UP: if self.direction == D_UP:
# self.body[0].y -= 1
self.body.append(Point(self.body[-1].x, self.body[-1].y - 1)) self.body.append(Point(self.body[-1].x, self.body[-1].y - 1))
elif self.direction == D_DOWN: elif self.direction == D_DOWN:
# self.body[0].y += 1
self.body.append(Point(self.body[-1].x, self.body[-1].y + 1)) self.body.append(Point(self.body[-1].x, self.body[-1].y + 1))
elif self.direction == D_LEFT: elif self.direction == D_LEFT:
# self.body[0].x -= 1
self.body.append(Point(self.body[-1].x - 1, self.body[-1].y)) self.body.append(Point(self.body[-1].x - 1, self.body[-1].y))
elif self.direction == D_RIGHT: elif self.direction == D_RIGHT:
# self.body[0].x += 1
self.body.append(Point(self.body[-1].x + 1, self.body[-1].y)) self.body.append(Point(self.body[-1].x + 1, self.body[-1].y))
def _check_collision(body: list[Point]) -> None:
for point in body:
if point.x < 0 or point.y < 0:
raise IndexError("Snake has collision with walls")
elif point.x >= WIDTH or point.y >= HEIGHT:
raise IndexError("Snake has collision with walls")
if len(set(body)) != len(body):
raise IndexError("Player has collision with self")
def update(self) -> None:
self.start_direction = self.direction
if self.body[-1] == self.food: if self.body[-1] == self.food:
self.food.generate_new() self.food.generate_new()
self.score += 1
else: else:
self.body.pop(0) self.body.pop(0)
if len(set(self.body)) != len(self.body): Player._check_collision(self.body)
raise IndexError("Player has collision with self")
def left(self) -> None: def left(self, game) -> None:
self.direction = D_LEFT if not game.is_pause and self.start_direction != D_RIGHT:
self.direction = D_LEFT
def right(self) -> None: def right(self, game) -> None:
self.direction = D_RIGHT if not game.is_pause and self.start_direction != D_LEFT:
self.direction = D_RIGHT
def up(self) -> None: def up(self, game) -> None:
self.direction = D_UP if not game.is_pause and self.start_direction != D_DOWN:
self.direction = D_UP
def down(self) -> None: def down(self, game) -> None:
self.direction = D_DOWN if not game.is_pause and self.start_direction != D_UP:
self.direction = D_DOWN

View File

@ -4,15 +4,15 @@ class Point:
self.y = y self.y = y
def __eq__(self, other) -> bool: def __eq__(self, other) -> bool:
if isinstance(other, Point): if not isinstance(other, Point):
if self.x == other.x and self.y == other.y: return False
return True
else:
return False
else:
raise TypeError("You can compare only Point with Point")
def __hash__(self) -> None: if self.x == other.x and self.y == other.y:
return True
else:
return False
def __hash__(self) -> int:
return int(f"{abs(self.x)}000{abs(self.y)}") return int(f"{abs(self.x)}000{abs(self.y)}")
def __str__(self) -> str: def __str__(self) -> str:

1
requirements.txt Normal file
View File

@ -0,0 +1 @@
keyboard==0.13.5

View File

@ -2,9 +2,12 @@
WIDTH = 20 WIDTH = 20
HEIGHT = 20 HEIGHT = 20
FPS = 5 FPS = 5
WALL_COLOR = "\u001b[31m"
RESET_COLOR = "\u001b[0m"
# Buttons # Buttons
QUIT_BUTTON = 'q' QUIT_BUTTON = 'q'
PAUSE_BUTTON = 'p'
LEFT_BUTTON = 'a' LEFT_BUTTON = 'a'
RIGHT_BUTTON = 'd' RIGHT_BUTTON = 'd'
UP_BUTTON = 'w' UP_BUTTON = 'w'
@ -24,3 +27,13 @@ SPACE = 0
WALL = 1 WALL = 1
FOOD = 2 FOOD = 2
WALL_FOOD = 3 WALL_FOOD = 3
HEAD = 4
TT_SPACE = " "
TT_WALL = "\u001b[34m{}\u001b[0m".format("██")
TT_FOOD = "\u001b[33m{}\u001b[0m".format("██")
TT_WALL_FOOD = "\u001b[32m{}\u001b[0m".format("██")
TT_HEAD = "\u001b[36m{}\u001b[0m".format("██")
# Globals
is_pause = False