From 787fa1c785c1e9011917a0c3362e65a86cea228c Mon Sep 17 00:00:00 2001 From: Kristofers Solo Date: Sat, 16 Apr 2022 13:50:20 +0300 Subject: [PATCH] restructured code --- pygame/snake/source/assets/scripts/classes.py | 161 +++++++++++++ pygame/snake/source/assets/scripts/menu.py | 21 ++ pygame/snake/source/assets/scripts/score.py | 31 +++ pygame/snake/source/globals.py | 32 +++ pygame/snake/source/snake.py | 227 ++---------------- 5 files changed, 265 insertions(+), 207 deletions(-) create mode 100644 pygame/snake/source/assets/scripts/classes.py create mode 100644 pygame/snake/source/assets/scripts/menu.py create mode 100644 pygame/snake/source/assets/scripts/score.py create mode 100644 pygame/snake/source/globals.py diff --git a/pygame/snake/source/assets/scripts/classes.py b/pygame/snake/source/assets/scripts/classes.py new file mode 100644 index 00000000..24267473 --- /dev/null +++ b/pygame/snake/source/assets/scripts/classes.py @@ -0,0 +1,161 @@ +import pygame +from globals import * +from random import randrange + + +def end_screen() -> None: + quit() + + +class Cube: + + def __init__(self, position, color=PURPLE) -> None: + self.pos = position + self.direction = (1, 0) + self.color = color + + def move(self, direction: tuple) -> None: + self.direction = direction + self.pos = (self.pos[0] + self.direction[0], self.pos[1] + self.direction[1]) + + def draw(self, eyes=False) -> None: + distance = WIDTH // ROWS + i, j = self.pos + + pygame.draw.rect(WINDOW, self.color, (i * distance + 1, j * distance + 1, distance - 2, distance - 2)) + if eyes: + center = distance // 2 + radius = 3 + circle_middle = (i * distance + center - radius, j * distance + 8) + circle_middle_2 = (i * distance + distance - radius * 2, j * distance + 8) + pygame.draw.circle(WINDOW, BLACK, circle_middle, radius) + pygame.draw.circle(WINDOW, BLACK, circle_middle_2, radius) + + +class Snake: + + def __init__(self, pos: tuple, color: tuple, name: str, player_number: int = 1) -> None: + self.color = color + self.head = Cube(pos, self.color) + self.body = [] + self.body.append(self.head) + self.turns = {} + self.direction = (1, 0) + self.number = player_number + self.name = name + + def move(self) -> None: + keys = pygame.key.get_pressed() + if multiplayer: + num_1, num_2 = 1, 2 + else: + num_1, num_2 = 1, 1 + + if self.number == num_1: + if keys[pygame.K_LEFT] and self.direction != (1, 0): # turn left + self.direction = -1, 0 + self.turns[self.head.pos[:]] = self.direction + + if keys[pygame.K_RIGHT] and self.direction != (-1, 0): # turn right + self.direction = 1, 0 + self.turns[self.head.pos[:]] = self.direction + + if keys[pygame.K_UP] and self.direction != (0, 1): # turn up + self.direction = 0, -1 + self.turns[self.head.pos[:]] = self.direction + + if keys[pygame.K_DOWN] and self.direction != (0, -1): # turn down + self.direction = 0, 1 + self.turns[self.head.pos[:]] = self.direction + + if self.number == num_2: + if keys[pygame.K_a] and self.direction != (1, 0): # turn left + self.direction = -1, 0 + self.turns[self.head.pos[:]] = self.direction + + if keys[pygame.K_d] and self.direction != (-1, 0): # turn right + self.direction = 1, 0 + self.turns[self.head.pos[:]] = self.direction + + if keys[pygame.K_w] and self.direction != (0, 1): # turn up + self.direction = 0, -1 + self.turns[self.head.pos[:]] = self.direction + + if keys[pygame.K_s] and self.direction != (0, -1): # turn down + self.direction = 0, 1 + self.turns[self.head.pos[:]] = self.direction + + for index, head in enumerate(self.body): + head_pos = head.pos[:] + if head_pos in self.turns: + turn = self.turns[head_pos] + head.move((turn[0], turn[1])) + if index == len(self.body) - 1: + self.turns.pop(head_pos) + else: + if walls: # end game if goes into the wall + head.move(head.direction) + if head.direction[0] == -1 and head.pos[0] < 0: # left to right + end_screen() + + if head.direction[0] == 1 and head.pos[0] >= ROWS: # right to left + end_screen() + + if head.direction[1] == 1 and head.pos[1] >= COLUMNS: # bottom to top + end_screen() + + if head.direction[1] == -1 and head.pos[1] < 0: # top to bottom + end_screen() + + else: # move player to other screen size + if head.direction[0] == -1 and head.pos[0] <= 0: # left to right + head.pos = (ROWS - 1, head.pos[1]) + + elif head.direction[0] == 1 and head.pos[0] >= ROWS - 1: # right to left + head.pos = (0, head.pos[1]) + + elif head.direction[1] == 1 and head.pos[1] >= COLUMNS - 1: # bottom to top + head.pos = (head.pos[0], 0) + + elif head.direction[1] == -1 and head.pos[1] <= 0: # top to bottom + head.pos = (head.pos[0], COLUMNS - 1) + + else: + head.move(head.direction) + + def add_cube(self) -> None: + tail = self.body[-1] + if tail.direction == (1, 0): + self.body.append(Cube((tail.pos[0] - 1, tail.pos[1]), self.color)) + elif tail.direction == (-1, 0): + self.body.append(Cube((tail.pos[0] + 1, tail.pos[1]), self.color)) + elif tail.direction == (0, 1): + self.body.append(Cube((tail.pos[0], tail.pos[1] - 1), self.color)) + elif tail.direction == (0, -1): + self.body.append(Cube((tail.pos[0], tail.pos[1] + 1), self.color)) + + self.body[-1].direction = tail.direction + + def remove_cube(self) -> None: + self.body.pop(-1) + + def draw(self) -> None: + for index, head in enumerate(self.body): + if index == 0: + head.draw(eyes=True) + else: + head.draw() + + +class Snack: + + def __init__(self, texture) -> None: + self.texture = texture + self.randomize() + + def draw_snack(self) -> None: + snack_rect = pygame.Rect(self.pos[0] * CELL_SIZE, self.pos[1] * CELL_SIZE, CELL_SIZE, CELL_SIZE) + WINDOW.blit(self.texture, snack_rect) + + def randomize(self) -> None: + self.pos = (randrange(ROWS), randrange(COLUMNS)) \ No newline at end of file diff --git a/pygame/snake/source/assets/scripts/menu.py b/pygame/snake/source/assets/scripts/menu.py new file mode 100644 index 00000000..b28af370 --- /dev/null +++ b/pygame/snake/source/assets/scripts/menu.py @@ -0,0 +1,21 @@ +import pygame +from globals import * +from assets.scripts.score import read_score, sort + + +def main_menu() -> None: + text = set_font(20).render("QUIT", 1, GRAY) + while True: + WINDOW.fill(BLACK) + title_label = set_font(50).render("Press any key to start...", 1, WHITE) + WINDOW.blit(title_label, (WIDTH / 2 - title_label.get_width() / 2, WINDOW_HEIGHT / 2 - title_label.get_height() / 2)) + for event in pygame.event.get(): + if event.type == pygame.QUIT: + csv_file = read_score(BASE_PATH) + for line in sort(csv_file, reverse=True): + print(line) + quit() + if event.type == pygame.KEYDOWN: + from snake import main + main() + pygame.display.update() diff --git a/pygame/snake/source/assets/scripts/score.py b/pygame/snake/source/assets/scripts/score.py new file mode 100644 index 00000000..a0710eef --- /dev/null +++ b/pygame/snake/source/assets/scripts/score.py @@ -0,0 +1,31 @@ +import csv +import operator +from os.path import join, exists + +fields = ["Name", "Score"] + + +def write_score(name: str, score: int, base_path: str) -> None: + create_header = False + path = join(base_path, "score.csv") + if not exists(path): + create_header = True + with open(path, 'a', encoding='UTF-8', newline='') as file: + write = csv.writer(file) + if create_header: + write.writerow(fields) + write.writerows([[name, score]]) + + +def read_score(path: str): + lines = [] + path = join(path, "score.csv") + with open(path, 'r', encoding='UTF-8') as file: + for line in csv.reader(file): + lines.append(line) + return lines + + +def sort(data, reverse: bool = False): + data = sorted(data, key=operator.itemgetter(1), reverse=reverse) + return data \ No newline at end of file diff --git a/pygame/snake/source/globals.py b/pygame/snake/source/globals.py new file mode 100644 index 00000000..3c4fe5e2 --- /dev/null +++ b/pygame/snake/source/globals.py @@ -0,0 +1,32 @@ +import pygame +from os.path import join, abspath, dirname + +CELL_SIZE = 30 +ROWS, COLUMNS = 30, 20 +WIDTH, HEIGHT = ROWS * CELL_SIZE, COLUMNS * CELL_SIZE +WINDOW_HEIGHT = HEIGHT + 100 +WINDOW = pygame.display.set_mode((WIDTH, WINDOW_HEIGHT)) +pygame.font.init() +pygame.display.set_caption("Snake") + +BASE_PATH = abspath(dirname(__file__)) +SPRITE_PATH = join(BASE_PATH, "assets", "sprites") +apple_texture = pygame.transform.scale(pygame.image.load(join(SPRITE_PATH, "golden_apple.png")), (CELL_SIZE, CELL_SIZE)) +poison_texture = pygame.transform.scale(pygame.image.load(join(SPRITE_PATH, "poison.png")), (CELL_SIZE, CELL_SIZE)) +cobblestone_texture = pygame.transform.scale(pygame.image.load(join(SPRITE_PATH, "cobblestone.jpeg")), (CELL_SIZE, CELL_SIZE)) +FONT = join(BASE_PATH, "fonts", "roboto.ttf") + +RED = (255, 0, 0) +WHITE = (242, 242, 242) +GRAY = (204, 204, 204) +DARK_GRAY = (51, 51, 51) +BLACK = (0, 0, 0) +GREEN = (0, 128, 30) +PURPLE = (170, 0, 255) +BLUE = (85, 85, 255) + +set_font = lambda size: pygame.font.Font(FONT, size) # sets font size + +FPS = 10 # speed +multiplayer = False +walls = False diff --git a/pygame/snake/source/snake.py b/pygame/snake/source/snake.py index 39213129..472709c8 100755 --- a/pygame/snake/source/snake.py +++ b/pygame/snake/source/snake.py @@ -1,192 +1,17 @@ # Author - Kristiāns Francis Cagulis -# Date - 10.04.2022 +# Date - 16.04.2022 # Title - Snake import pygame -from random import randrange, randint -from os.path import abspath, dirname, join +from random import randint +from os.path import abspath, dirname -CELL_SIZE = 30 -ROWS, COLUMNS = 30, 20 -WIDTH, HEIGHT = ROWS * CELL_SIZE, COLUMNS * CELL_SIZE -WINDOW_HEIGHT = HEIGHT + 100 -WINDOW = pygame.display.set_mode((WIDTH, WINDOW_HEIGHT)) -pygame.font.init() -pygame.display.set_caption("Snake") +from globals import * +from assets.scripts.score import * +from assets.scripts.menu import main_menu +from assets.scripts.classes import * BASE_PATH = abspath(dirname(__file__)) -SPRITE_PATH = join(BASE_PATH, "assets", "sprites") -FONT = join(BASE_PATH, "fonts", "roboto.ttf") - -apple_texture = pygame.transform.scale(pygame.image.load(join(SPRITE_PATH, "golden_apple.png")), (CELL_SIZE, CELL_SIZE)) -poison_texture = pygame.transform.scale(pygame.image.load(join(SPRITE_PATH, "poison.png")), (CELL_SIZE, CELL_SIZE)) -cobblestone_texture = pygame.transform.scale(pygame.image.load(join(SPRITE_PATH, "cobblestone.jpeg")), (CELL_SIZE, CELL_SIZE)) - -RED = (255, 0, 0) -WHITE = (242, 242, 242) -GRAY = (204, 204, 204) -DARK_GRAY = (51, 51, 51) -BLACK = (0, 0, 0) -GREEN = (0, 128, 30) -PURPLE = (170, 0, 255) -BLUE = (85, 85, 255) -RANDOM_COLOR = (randint(0, 255), randint(0, 255), randint(0, 255)) - -multiplayer = False -walls = False - - -class Cube: - - def __init__(self, position, color=RANDOM_COLOR) -> None: - self.pos = position - self.direction = (1, 0) - self.color = color - - def move(self, direction: tuple) -> None: - self.direction = direction - self.pos = (self.pos[0] + self.direction[0], self.pos[1] + self.direction[1]) - - def draw(self, eyes=False) -> None: - distance = WIDTH // ROWS - i, j = self.pos - - pygame.draw.rect(WINDOW, self.color, (i * distance + 1, j * distance + 1, distance - 2, distance - 2)) - if eyes: - center = distance // 2 - radius = 3 - circle_middle = (i * distance + center - radius, j * distance + 8) - circle_middle_2 = (i * distance + distance - radius * 2, j * distance + 8) - pygame.draw.circle(WINDOW, BLACK, circle_middle, radius) - pygame.draw.circle(WINDOW, BLACK, circle_middle_2, radius) - - -class Snake: - - def __init__(self, pos: tuple, color: tuple, player_number: int = 1) -> None: - self.color = color - self.head = Cube(pos, self.color) - self.body = [] - self.body.append(self.head) - self.turns = {} - self.direction = (1, 0) - self.number = player_number - - def move(self) -> None: - keys = pygame.key.get_pressed() - if multiplayer: - num_1, num_2 = 1, 2 - else: - num_1, num_2 = 1, 1 - - if self.number == num_1: - if keys[pygame.K_LEFT] and self.direction != (1, 0): # turn left - self.direction = -1, 0 - self.turns[self.head.pos[:]] = self.direction - - if keys[pygame.K_RIGHT] and self.direction != (-1, 0): # turn right - self.direction = 1, 0 - self.turns[self.head.pos[:]] = self.direction - - if keys[pygame.K_UP] and self.direction != (0, 1): # turn up - self.direction = 0, -1 - self.turns[self.head.pos[:]] = self.direction - - if keys[pygame.K_DOWN] and self.direction != (0, -1): # turn down - self.direction = 0, 1 - self.turns[self.head.pos[:]] = self.direction - - if self.number == num_2: - if keys[pygame.K_a] and self.direction != (1, 0): # turn left - self.direction = -1, 0 - self.turns[self.head.pos[:]] = self.direction - - if keys[pygame.K_d] and self.direction != (-1, 0): # turn right - self.direction = 1, 0 - self.turns[self.head.pos[:]] = self.direction - - if keys[pygame.K_w] and self.direction != (0, 1): # turn up - self.direction = 0, -1 - self.turns[self.head.pos[:]] = self.direction - - if keys[pygame.K_s] and self.direction != (0, -1): # turn down - self.direction = 0, 1 - self.turns[self.head.pos[:]] = self.direction - - for index, head in enumerate(self.body): - head_pos = head.pos[:] - if head_pos in self.turns: - turn = self.turns[head_pos] - head.move((turn[0], turn[1])) - if index == len(self.body) - 1: - self.turns.pop(head_pos) - else: - if walls: # end game if goes into the wall - head.move(head.direction) - if head.direction[0] == -1 and head.pos[0] < 0: # left to right - end_screen() - - if head.direction[0] == 1 and head.pos[0] >= ROWS: # right to left - end_screen() - - if head.direction[1] == 1 and head.pos[1] >= COLUMNS: # bottom to top - end_screen() - - if head.direction[1] == -1 and head.pos[1] < 0: # top to bottom - end_screen() - - else: # move player to other screen size - if head.direction[0] == -1 and head.pos[0] <= 0: # left to right - head.pos = (ROWS - 1, head.pos[1]) - - elif head.direction[0] == 1 and head.pos[0] >= ROWS - 1: # right to left - head.pos = (0, head.pos[1]) - - elif head.direction[1] == 1 and head.pos[1] >= COLUMNS - 1: # bottom to top - head.pos = (head.pos[0], 0) - - elif head.direction[1] == -1 and head.pos[1] <= 0: # top to bottom - head.pos = (head.pos[0], COLUMNS - 1) - - else: - head.move(head.direction) - - def add_cube(self) -> None: - tail = self.body[-1] - if tail.direction == (1, 0): - self.body.append(Cube((tail.pos[0] - 1, tail.pos[1]), self.color)) - elif tail.direction == (-1, 0): - self.body.append(Cube((tail.pos[0] + 1, tail.pos[1]), self.color)) - elif tail.direction == (0, 1): - self.body.append(Cube((tail.pos[0], tail.pos[1] - 1), self.color)) - elif tail.direction == (0, -1): - self.body.append(Cube((tail.pos[0], tail.pos[1] + 1), self.color)) - - self.body[-1].direction = tail.direction - - def remove_cube(self) -> None: - self.body.pop(-1) - - def draw(self) -> None: - for index, head in enumerate(self.body): - if index == 0: - head.draw(eyes=True) - else: - head.draw() - - -class Snack: - - def __init__(self, texture) -> None: - self.texture = texture - self.randomize() - - def draw_snack(self) -> None: - snack_rect = pygame.Rect(self.pos[0] * CELL_SIZE, self.pos[1] * CELL_SIZE, CELL_SIZE, CELL_SIZE) - WINDOW.blit(self.texture, snack_rect) - - def randomize(self) -> None: - self.pos = (randrange(ROWS), randrange(COLUMNS)) def draw_grid() -> None: @@ -212,19 +37,15 @@ def collision_check(snakes, snack) -> None: snack.randomize() -def end_screen() -> None: - quit() - - def main() -> None: - FPS = 10 + run = True clock = pygame.time.Clock() - snake_one = Snake((randint(0, ROWS - 1), randint(0, COLUMNS - 1)), PURPLE) + snake_one = Snake((randint(0, ROWS - 1), randint(0, COLUMNS - 1)), PURPLE, "test1") snakes = [snake_one] if multiplayer: - snake_two = Snake((randint(0, ROWS - 1), randint(0, COLUMNS - 1)), BLUE, 2) + snake_two = Snake((randint(0, ROWS - 1), randint(0, COLUMNS - 1)), BLUE, "test2", 2) snakes.append(snake_two) apple = Snack(apple_texture) @@ -262,32 +83,24 @@ def main() -> None: collision_check(snakes, apple) if snake.body[0].pos == poison.pos: - snake.remove_cube() + if len(snake.body) > 1: + snake.remove_cube() poison = Snack(poison_texture) collision_check(snakes, poison) for i in range(len(snake.body)): if snake.body[i].pos in list(map(lambda z: z.pos, snake.body[i + 1:])): + for snake in snakes: + write_score(snake.name, len(snake.body), BASE_PATH) run = False redraw_window() -set_font = lambda size: pygame.font.Font(FONT, size) # sets font size - - -def main_menu() -> None: - text = set_font(20).render("QUIT", 1, GRAY) - while True: - WINDOW.fill(BLACK) - title_label = set_font(50).render("Press any key to start...", 1, WHITE) - WINDOW.blit(title_label, (WIDTH / 2 - title_label.get_width() / 2, WINDOW_HEIGHT / 2 - title_label.get_height() / 2)) - for event in pygame.event.get(): - if event.type == pygame.QUIT: - quit() - if event.type == pygame.KEYDOWN: - main() - pygame.display.update() - - if __name__ == '__main__': main_menu() + # for i in range(50, 100): + # write_score(f"test{i}", randint(1, 1_000_000), BASE_PATH) + # csv_file = read_score(BASE_PATH) + # # print(csv_file) + # for line in sort(csv_file, reverse=True): + # print(line)