Loading main.py +2 −1 Original line number Diff line number Diff line from pythonsnake import controller from pythonsnake.controller import Controller if __name__ == "__main__": controller = Controller() controller.game_menu() pythonsnake/candy.py 0 → 100644 +55 −0 Original line number Diff line number Diff line from random import choice from pythonsnake.snake import Snake class Candy: def __init__(self, grid_width: int, grid_height: int, snake: Snake) -> None: self.X = 0 self.Y = 0 self.random_coord(grid_width, grid_height, snake) def random_coord( self, grid_width: int, grid_height: int, snake: Snake ) -> None: found = False x = 0 y = 0 while not found: correct = True x = self.random_coord_X(grid_width, snake) y = self.random_coord_Y(grid_height, snake) # candy can be on the same line or on the same column but not at # the exact same place as the snake for snake_part in snake.coord: if snake_part["x"] == x and snake_part["y"] == y: correct = False break if correct: found = True self.X = x self.Y = y def random_coord_X(self, grid_width: int, snake: Snake) -> int: coord_to_exclude = [] for snake_part in snake.coord: coord_to_exclude.append(snake_part["x"]) return choice( [i for i in range(0, grid_width) if i not in coord_to_exclude] ) def random_coord_Y(self, grid_height: int, snake: Snake) -> int: coord_to_exclude = [] for snake_part in snake.coord: coord_to_exclude.append(snake_part["y"]) return choice( [i for i in range(0, grid_height) if i not in coord_to_exclude] ) def new_coord( self, grid_width: int, grid_height: int, snake: Snake ) -> None: self.random_coord(grid_width, grid_height, snake) pythonsnake/controller.py +45 −50 Original line number Diff line number Diff line from pythonsnake import model, view from pythonsnake.model import Game from pythonsnake.terminalview import TerminalView import keyboard import time def game_menu(): class Controller: def __init__(self) -> None: self.view = TerminalView() self.game = None def game_menu(self) -> None: while True: start_game(choose_mode()) self.start_game(self.choose_mode()) def choose_mode(): view.menu() def choose_mode(self) -> int: self.view.menu() choice = None while choice != "1" and choice != "2" and choice != "3": while choice != "1" and choice != "2": choice = input("=>") if choice != "1" and choice != "2" and choice != "3": view.menu_choice_incorrect() if choice != "1" and choice != "2": self.view.menu_choice_incorrect() if choice == "3": if choice == "2": exit() return int(choice) def start_game(mode): gameState = model.Game(29) def start_game(self, mode: int) -> None: self.game = Game(50, 25) if mode == 1: start_game_terminal(gameState) elif mode == 2: start_game_UI(gameState) self.start_game_terminal() def start_game_terminal(gameState): def start_game_terminal(self) -> None: keyboard.unhook_all() listen_escape_game(gameState) self.listen_escape_game() while not gameState.lost: # gameState.step() view.refresh_grid(gameState.move(gameState.current_direction + " arrow")) listen_move(gameState) while not self.game.lost: self.view.display_grid( self.game.move(self.game.current_direction + " arrow") ) self.listen_move() continue time.sleep(1) keyboard.unhook_all() def listen_escape_game(self) -> None: keyboard.on_press_key("esc", lambda _: self.game.exit_game()) def start_game_UI(game): pass def listen_escape_game(gameState): keyboard.on_press_key("esc", lambda _: gameState.exit_game()) def listen_move(gameState): def listen_move(self) -> None: if keyboard.is_pressed("left arrow"): view.refresh_grid(gameState.move("left arrow")) self.view.display_grid(self.game.move("left arrow")) if keyboard.is_pressed("right arrow"): view.refresh_grid(gameState.move("right arrow")) self.view.display_grid(self.game.move("right arrow")) if keyboard.is_pressed("up arrow"): view.refresh_grid(gameState.move("up arrow")) self.view.display_grid(self.game.move("up arrow")) if keyboard.is_pressed("down arrow"): view.refresh_grid(gameState.move("down arrow")) self.view.display_grid(self.game.move("down arrow")) pythonsnake/model.py +108 −55 Original line number Diff line number Diff line from copy import copy import random from pythonsnake.snake import Snake from pythonsnake.candy import Candy class Game: def __init__(self, grid_size) -> None: self.grid_size = grid_size self.grid = [[i for i in range(grid_size)] for j in range(grid_size)] self.player_coord = [0, 0] self.player_length = 1 def __init__(self, grid_width: int, grid_height: int) -> None: self.grid_width = grid_width self.grid_height = grid_height self.snake = Snake() self.lost = False self.current_direction = "right" self.candy = self.new_candy() self.candy = Candy(grid_width, grid_height, self.snake) self.grid = self.init_grid(grid_width, grid_height) self.update_grid() def move(self, direction): def move(self, direction: str): # if the User is not trying to U turn, process the move if not self.is_U_turn(direction): # the snake can't make a U turn if(direction == "left arrow" and self.current_direction == "right" or direction == "right arrow" and self.current_direction == "left" or direction == "up arrow" and self.current_direction == "down" or direction == "down arrow" and self.current_direction == "up"): return self # if the move is allowed (not off grid or snake not biting itself) if self.is_move_allowed(direction): self.current_direction = direction.replace(" arrow", "") self.snake.move(direction) if self.check_candy(): self.snake.eat_candy() self.candy.new_coord( self.grid_width, self.grid_height, self.snake ) if direction == "left arrow" and self.check_move( self.player_coord[0] - 1, self.player_coord[1] ): self.player_coord[0] -= 1 self.current_direction = "left" elif direction == "right arrow" and self.check_move( self.player_coord[0] + 1, self.player_coord[1] ): self.player_coord[0] += 1 self.current_direction = "right" elif direction == "up arrow" and self.check_move( self.player_coord[0], self.player_coord[1] - 1 ): self.player_coord[1] -= 1 self.current_direction = "up" elif direction == "down arrow" and self.check_move( self.player_coord[0], self.player_coord[1] + 1 ): self.player_coord[1] += 1 self.current_direction = "down" self.update_grid() else: self.lost = True self.check_candy() return self def exit_game(self): self.lost = True """ check if the move is still in the grid check if the move is allowed in the grid """ def check_move(self, coordX, coordY): def is_move_allowed(self, direction: str): snake_head = copy(self.snake.coord[0]) if direction == "left arrow": snake_head["x"] -= 1 elif direction == "right arrow": snake_head["x"] += 1 elif direction == "up arrow": snake_head["y"] -= 1 elif direction == "down arrow": snake_head["y"] += 1 # check if next position of snake head is off grid if ( coordX >= 0 and coordX <= len(self.grid) - 1 and coordY >= 0 and coordY <= len(self.grid[0]) - 1 snake_head["x"] < 0 or snake_head["x"] >= self.grid_width or snake_head["y"] < 0 or snake_head["y"] >= self.grid_height ): return False # check if next position of snake haed is not another snake piece for snake_piece in self.snake.coord: if ( snake_piece["x"] == snake_head["x"] and snake_piece["y"] == snake_head["y"] ): return True else: return False return True def new_candy(self): return [random.randint(0, self.grid_size), random.randint(0, self.grid_size)] return [ random.randint(0, self.grid_size), random.randint(0, self.grid_size), ] def check_candy(self) -> bool: if ( self.snake.coord[0]["x"] == self.candy.X and self.snake.coord[0]["y"] == self.candy.Y ): return True return False def check_candy(self): def is_U_turn(self, direction: str) -> bool: # the User/snake can't make a U turn if ( self.player_coord[0] == self.candy[0] and self.player_coord[1] == self.candy[1] direction == "left arrow" and self.current_direction == "right" or direction == "right arrow" and self.current_direction == "left" or direction == "up arrow" and self.current_direction == "down" or direction == "down arrow" and self.current_direction == "up" ): self.eat_candy() return True def eat_candy(self): self.player_length += 1 self.candy = self.new_candy() return False """ _summary_ init the playing grid with format column = width height = Y1 = line = [ [X1],[X2],[X3],[X4] ] Y2 [X1],[X2],[X3],[X4] Y3 [X1],[X2],[X3],[X4] Y4 [X1],[X2],[X3],[X4] """ def init_grid(self, grid_width: int, grid_height: int) -> None: return [ [{"snake": False, "candy": False} for i in range(0, grid_width)] for j in range(0, grid_height) ] def update_grid(self) -> None: # reset grid for line in self.grid: for column in line: column["snake"] = False column["candy"] = False for snake_piece in self.snake.coord: self.grid[snake_piece["y"]][snake_piece["x"]]["snake"] = True self.grid[self.candy.Y][self.candy.X]["candy"] = True pythonsnake/snake.py 0 → 100644 +42 −0 Original line number Diff line number Diff line from copy import deepcopy class Snake: def __init__(self) -> None: self.coord = [] self.coord.append({"x": 0, "y": 0}) self.piece_pending = None def eat_candy(self) -> None: self.piece_pending = { "x": self.coord[-1]["x"], "y": self.coord[-1]["y"], } def move(self, direction) -> None: snake_to_shift = deepcopy(self.coord) # move the snake head if direction == "left arrow": self.coord[0]["x"] -= 1 elif direction == "right arrow": self.coord[0]["x"] += 1 elif direction == "up arrow": self.coord[0]["y"] -= 1 elif direction == "down arrow": self.coord[0]["y"] += 1 # move the body for i, piece in enumerate(snake_to_shift): # except the snake head if i != 0: self.coord[i] = { "x": snake_to_shift[i - 1]["x"], "y": snake_to_shift[i - 1]["y"], } if self.piece_pending != None: self.coord.append( {"x": self.piece_pending["x"], "y": self.piece_pending["y"]} ) self.piece_pending = None Loading
main.py +2 −1 Original line number Diff line number Diff line from pythonsnake import controller from pythonsnake.controller import Controller if __name__ == "__main__": controller = Controller() controller.game_menu()
pythonsnake/candy.py 0 → 100644 +55 −0 Original line number Diff line number Diff line from random import choice from pythonsnake.snake import Snake class Candy: def __init__(self, grid_width: int, grid_height: int, snake: Snake) -> None: self.X = 0 self.Y = 0 self.random_coord(grid_width, grid_height, snake) def random_coord( self, grid_width: int, grid_height: int, snake: Snake ) -> None: found = False x = 0 y = 0 while not found: correct = True x = self.random_coord_X(grid_width, snake) y = self.random_coord_Y(grid_height, snake) # candy can be on the same line or on the same column but not at # the exact same place as the snake for snake_part in snake.coord: if snake_part["x"] == x and snake_part["y"] == y: correct = False break if correct: found = True self.X = x self.Y = y def random_coord_X(self, grid_width: int, snake: Snake) -> int: coord_to_exclude = [] for snake_part in snake.coord: coord_to_exclude.append(snake_part["x"]) return choice( [i for i in range(0, grid_width) if i not in coord_to_exclude] ) def random_coord_Y(self, grid_height: int, snake: Snake) -> int: coord_to_exclude = [] for snake_part in snake.coord: coord_to_exclude.append(snake_part["y"]) return choice( [i for i in range(0, grid_height) if i not in coord_to_exclude] ) def new_coord( self, grid_width: int, grid_height: int, snake: Snake ) -> None: self.random_coord(grid_width, grid_height, snake)
pythonsnake/controller.py +45 −50 Original line number Diff line number Diff line from pythonsnake import model, view from pythonsnake.model import Game from pythonsnake.terminalview import TerminalView import keyboard import time def game_menu(): class Controller: def __init__(self) -> None: self.view = TerminalView() self.game = None def game_menu(self) -> None: while True: start_game(choose_mode()) self.start_game(self.choose_mode()) def choose_mode(): view.menu() def choose_mode(self) -> int: self.view.menu() choice = None while choice != "1" and choice != "2" and choice != "3": while choice != "1" and choice != "2": choice = input("=>") if choice != "1" and choice != "2" and choice != "3": view.menu_choice_incorrect() if choice != "1" and choice != "2": self.view.menu_choice_incorrect() if choice == "3": if choice == "2": exit() return int(choice) def start_game(mode): gameState = model.Game(29) def start_game(self, mode: int) -> None: self.game = Game(50, 25) if mode == 1: start_game_terminal(gameState) elif mode == 2: start_game_UI(gameState) self.start_game_terminal() def start_game_terminal(gameState): def start_game_terminal(self) -> None: keyboard.unhook_all() listen_escape_game(gameState) self.listen_escape_game() while not gameState.lost: # gameState.step() view.refresh_grid(gameState.move(gameState.current_direction + " arrow")) listen_move(gameState) while not self.game.lost: self.view.display_grid( self.game.move(self.game.current_direction + " arrow") ) self.listen_move() continue time.sleep(1) keyboard.unhook_all() def listen_escape_game(self) -> None: keyboard.on_press_key("esc", lambda _: self.game.exit_game()) def start_game_UI(game): pass def listen_escape_game(gameState): keyboard.on_press_key("esc", lambda _: gameState.exit_game()) def listen_move(gameState): def listen_move(self) -> None: if keyboard.is_pressed("left arrow"): view.refresh_grid(gameState.move("left arrow")) self.view.display_grid(self.game.move("left arrow")) if keyboard.is_pressed("right arrow"): view.refresh_grid(gameState.move("right arrow")) self.view.display_grid(self.game.move("right arrow")) if keyboard.is_pressed("up arrow"): view.refresh_grid(gameState.move("up arrow")) self.view.display_grid(self.game.move("up arrow")) if keyboard.is_pressed("down arrow"): view.refresh_grid(gameState.move("down arrow")) self.view.display_grid(self.game.move("down arrow"))
pythonsnake/model.py +108 −55 Original line number Diff line number Diff line from copy import copy import random from pythonsnake.snake import Snake from pythonsnake.candy import Candy class Game: def __init__(self, grid_size) -> None: self.grid_size = grid_size self.grid = [[i for i in range(grid_size)] for j in range(grid_size)] self.player_coord = [0, 0] self.player_length = 1 def __init__(self, grid_width: int, grid_height: int) -> None: self.grid_width = grid_width self.grid_height = grid_height self.snake = Snake() self.lost = False self.current_direction = "right" self.candy = self.new_candy() self.candy = Candy(grid_width, grid_height, self.snake) self.grid = self.init_grid(grid_width, grid_height) self.update_grid() def move(self, direction): def move(self, direction: str): # if the User is not trying to U turn, process the move if not self.is_U_turn(direction): # the snake can't make a U turn if(direction == "left arrow" and self.current_direction == "right" or direction == "right arrow" and self.current_direction == "left" or direction == "up arrow" and self.current_direction == "down" or direction == "down arrow" and self.current_direction == "up"): return self # if the move is allowed (not off grid or snake not biting itself) if self.is_move_allowed(direction): self.current_direction = direction.replace(" arrow", "") self.snake.move(direction) if self.check_candy(): self.snake.eat_candy() self.candy.new_coord( self.grid_width, self.grid_height, self.snake ) if direction == "left arrow" and self.check_move( self.player_coord[0] - 1, self.player_coord[1] ): self.player_coord[0] -= 1 self.current_direction = "left" elif direction == "right arrow" and self.check_move( self.player_coord[0] + 1, self.player_coord[1] ): self.player_coord[0] += 1 self.current_direction = "right" elif direction == "up arrow" and self.check_move( self.player_coord[0], self.player_coord[1] - 1 ): self.player_coord[1] -= 1 self.current_direction = "up" elif direction == "down arrow" and self.check_move( self.player_coord[0], self.player_coord[1] + 1 ): self.player_coord[1] += 1 self.current_direction = "down" self.update_grid() else: self.lost = True self.check_candy() return self def exit_game(self): self.lost = True """ check if the move is still in the grid check if the move is allowed in the grid """ def check_move(self, coordX, coordY): def is_move_allowed(self, direction: str): snake_head = copy(self.snake.coord[0]) if direction == "left arrow": snake_head["x"] -= 1 elif direction == "right arrow": snake_head["x"] += 1 elif direction == "up arrow": snake_head["y"] -= 1 elif direction == "down arrow": snake_head["y"] += 1 # check if next position of snake head is off grid if ( coordX >= 0 and coordX <= len(self.grid) - 1 and coordY >= 0 and coordY <= len(self.grid[0]) - 1 snake_head["x"] < 0 or snake_head["x"] >= self.grid_width or snake_head["y"] < 0 or snake_head["y"] >= self.grid_height ): return False # check if next position of snake haed is not another snake piece for snake_piece in self.snake.coord: if ( snake_piece["x"] == snake_head["x"] and snake_piece["y"] == snake_head["y"] ): return True else: return False return True def new_candy(self): return [random.randint(0, self.grid_size), random.randint(0, self.grid_size)] return [ random.randint(0, self.grid_size), random.randint(0, self.grid_size), ] def check_candy(self) -> bool: if ( self.snake.coord[0]["x"] == self.candy.X and self.snake.coord[0]["y"] == self.candy.Y ): return True return False def check_candy(self): def is_U_turn(self, direction: str) -> bool: # the User/snake can't make a U turn if ( self.player_coord[0] == self.candy[0] and self.player_coord[1] == self.candy[1] direction == "left arrow" and self.current_direction == "right" or direction == "right arrow" and self.current_direction == "left" or direction == "up arrow" and self.current_direction == "down" or direction == "down arrow" and self.current_direction == "up" ): self.eat_candy() return True def eat_candy(self): self.player_length += 1 self.candy = self.new_candy() return False """ _summary_ init the playing grid with format column = width height = Y1 = line = [ [X1],[X2],[X3],[X4] ] Y2 [X1],[X2],[X3],[X4] Y3 [X1],[X2],[X3],[X4] Y4 [X1],[X2],[X3],[X4] """ def init_grid(self, grid_width: int, grid_height: int) -> None: return [ [{"snake": False, "candy": False} for i in range(0, grid_width)] for j in range(0, grid_height) ] def update_grid(self) -> None: # reset grid for line in self.grid: for column in line: column["snake"] = False column["candy"] = False for snake_piece in self.snake.coord: self.grid[snake_piece["y"]][snake_piece["x"]]["snake"] = True self.grid[self.candy.Y][self.candy.X]["candy"] = True
pythonsnake/snake.py 0 → 100644 +42 −0 Original line number Diff line number Diff line from copy import deepcopy class Snake: def __init__(self) -> None: self.coord = [] self.coord.append({"x": 0, "y": 0}) self.piece_pending = None def eat_candy(self) -> None: self.piece_pending = { "x": self.coord[-1]["x"], "y": self.coord[-1]["y"], } def move(self, direction) -> None: snake_to_shift = deepcopy(self.coord) # move the snake head if direction == "left arrow": self.coord[0]["x"] -= 1 elif direction == "right arrow": self.coord[0]["x"] += 1 elif direction == "up arrow": self.coord[0]["y"] -= 1 elif direction == "down arrow": self.coord[0]["y"] += 1 # move the body for i, piece in enumerate(snake_to_shift): # except the snake head if i != 0: self.coord[i] = { "x": snake_to_shift[i - 1]["x"], "y": snake_to_shift[i - 1]["y"], } if self.piece_pending != None: self.coord.append( {"x": self.piece_pending["x"], "y": self.piece_pending["y"]} ) self.piece_pending = None