Loading main.py +2 −1 Changes for main.py: 2 added lines, 1 removed line. 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 Changes for pythonsnake/candy.py: 55 added lines, 0 removed lines. 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 +31 −36 Changes for pythonsnake/controller.py: 31 added lines, 36 removed lines. 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 +104 −51 Changes for pythonsnake/model.py: 104 added lines, 51 removed lines. 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 Changes for pythonsnake/snake.py: 42 added lines, 0 removed lines. 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 Changes for main.py: 2 added lines, 1 removed line. 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 Changes for pythonsnake/candy.py: 55 added lines, 0 removed lines. 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 +31 −36 Changes for pythonsnake/controller.py: 31 added lines, 36 removed lines. 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 +104 −51 Changes for pythonsnake/model.py: 104 added lines, 51 removed lines. 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 Changes for pythonsnake/snake.py: 42 added lines, 0 removed lines. 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