diff --git a/assets/graphics/powered_lines/cross/cross.png b/assets/graphics/powered_lines/cross/cross.png new file mode 100644 index 0000000..86ef4f9 Binary files /dev/null and b/assets/graphics/powered_lines/cross/cross.png differ diff --git a/assets/graphics/powered_lines/t_junction/left_right_bottom.png b/assets/graphics/powered_lines/t_junction/left_right_bottom.png new file mode 100644 index 0000000..5c12728 Binary files /dev/null and b/assets/graphics/powered_lines/t_junction/left_right_bottom.png differ diff --git a/assets/graphics/powered_lines/t_junction/left_right_top.png b/assets/graphics/powered_lines/t_junction/left_right_top.png new file mode 100644 index 0000000..92d3600 Binary files /dev/null and b/assets/graphics/powered_lines/t_junction/left_right_top.png differ diff --git a/assets/graphics/powered_lines/t_junction/top_bottom_left.png b/assets/graphics/powered_lines/t_junction/top_bottom_left.png new file mode 100644 index 0000000..a007c34 Binary files /dev/null and b/assets/graphics/powered_lines/t_junction/top_bottom_left.png differ diff --git a/assets/graphics/powered_lines/t_junction/top_bottom_right.png b/assets/graphics/powered_lines/t_junction/top_bottom_right.png new file mode 100644 index 0000000..7d80db8 Binary files /dev/null and b/assets/graphics/powered_lines/t_junction/top_bottom_right.png differ diff --git a/assets/graphics/unpowered_lines/cross/cross.png b/assets/graphics/unpowered_lines/cross/cross.png new file mode 100644 index 0000000..65e48bf Binary files /dev/null and b/assets/graphics/unpowered_lines/cross/cross.png differ diff --git a/assets/graphics/unpowered_lines/t_junction/left_right_bottom.png b/assets/graphics/unpowered_lines/t_junction/left_right_bottom.png new file mode 100644 index 0000000..8ae8e27 Binary files /dev/null and b/assets/graphics/unpowered_lines/t_junction/left_right_bottom.png differ diff --git a/assets/graphics/unpowered_lines/t_junction/left_right_top.png b/assets/graphics/unpowered_lines/t_junction/left_right_top.png new file mode 100644 index 0000000..a28e652 Binary files /dev/null and b/assets/graphics/unpowered_lines/t_junction/left_right_top.png differ diff --git a/assets/graphics/unpowered_lines/t_junction/top_bottom_left.png b/assets/graphics/unpowered_lines/t_junction/top_bottom_left.png new file mode 100644 index 0000000..12d1b2a Binary files /dev/null and b/assets/graphics/unpowered_lines/t_junction/top_bottom_left.png differ diff --git a/assets/graphics/unpowered_lines/t_junction/top_bottom_right.png b/assets/graphics/unpowered_lines/t_junction/top_bottom_right.png new file mode 100644 index 0000000..504f136 Binary files /dev/null and b/assets/graphics/unpowered_lines/t_junction/top_bottom_right.png differ diff --git a/game/cell.py b/game/cell.py new file mode 100644 index 0000000..45183bc --- /dev/null +++ b/game/cell.py @@ -0,0 +1,62 @@ +import arcade, arcade.gui + +from utils.constants import ROTATIONS, NEIGHBOURS +from utils.preload import TEXTURE_MAP + +def get_opposite(direction): + if direction == "l": + return "r" + elif direction == "r": + return "l" + elif direction == "t": + return "b" + elif direction == "b": + return "t" + +class Cell(arcade.gui.UITextureButton): + def __init__(self, cell_type, left_neighbour, top_neighbour): + super().__init__(texture=TEXTURE_MAP[cell_type, ROTATIONS[cell_type][0], cell_type == "power_source"]) + + self.rotation = ROTATIONS[cell_type][0] + self.cell_type = cell_type + self.powered = False + self.left_neighbour, self.top_neighbour = left_neighbour, top_neighbour + self.right_neighbour, self.bottom_neighbour = None, None + + def get_neighbour(self, name): + if name == "l": + return self.left_neighbour + elif name == "r": + return self.right_neighbour + elif name == "b": + return self.bottom_neighbour + elif name == "t": + return self.top_neighbour + + def get_connected_neighbours(self): + return [ + self.get_neighbour(neighbour_direction) for neighbour_direction in NEIGHBOURS[self.rotation] + if ( + self.get_neighbour(neighbour_direction) and + get_opposite(neighbour_direction) in NEIGHBOURS[self.get_neighbour(neighbour_direction).rotation] + ) + ] + + def update_value(self): + self.powered = any([neighbour.powered for neighbour in self.get_connected_neighbours()]) + + def update_visual(self): + self.texture = TEXTURE_MAP[(self.cell_type, self.rotation, self.powered)] + self.texture_hovered = TEXTURE_MAP[(self.cell_type, self.rotation, self.powered)] + self.texture_pressed = TEXTURE_MAP[(self.cell_type, self.rotation, self.powered)] + self._requires_render = True + + def next_rotation(self): + current_index = ROTATIONS[self.cell_type].index(self.rotation) + + if current_index + 1 == len(ROTATIONS[self.cell_type]): + self.rotation = ROTATIONS[self.cell_type][0] + else: + self.rotation = ROTATIONS[self.cell_type][current_index + 1] + + self.update_visual() \ No newline at end of file diff --git a/game/cells.py b/game/cells.py new file mode 100644 index 0000000..08f2495 --- /dev/null +++ b/game/cells.py @@ -0,0 +1,17 @@ +from game.cell import Cell + +class House(Cell): + def __init__(self, left_neighbour, top_neighbour): + super().__init__("house", left_neighbour, top_neighbour) + +class PowerSource(Cell): + def __init__(self, left_neighbour, top_neighbour): + super().__init__("power_source", left_neighbour, top_neighbour) + self.on_click = lambda e: self.next_rotation() + +class PowerLine(Cell): + def __init__(self, cell_type, left_neighbour, top_neighbour): + super().__init__(cell_type, left_neighbour, top_neighbour) + + if not cell_type == "cross": + self.on_click = lambda e: self.next_rotation() \ No newline at end of file diff --git a/game/play.py b/game/play.py index 5543ca3..b2cdaac 100644 --- a/game/play.py +++ b/game/play.py @@ -5,7 +5,7 @@ from utils.preload import button_texture, button_hovered_texture from collections import deque -from game.power_line import PowerLine +from game.cells import * class Game(arcade.gui.UIView): def __init__(self, pypresence_client, difficulty): @@ -15,8 +15,9 @@ class Game(arcade.gui.UIView): self.pypresence_client.update(state='In Game', start=self.pypresence_client.start_time) self.difficulty = difficulty - self.power_lines = [] + self.cells = [] self.power_sources = [] + self.houses = [] self.anchor = self.add_widget(arcade.gui.UIAnchorLayout(size_hint=(1, 1))) self.grid_size = list(map(int, difficulty.split("x"))) @@ -30,31 +31,36 @@ class Game(arcade.gui.UIView): self.anchor.add(self.back_button, anchor_x="left", anchor_y="top", align_x=5, align_y=-5) for row in range(self.grid_size[0]): - self.power_lines.append([]) + self.cells.append([]) for col in range(self.grid_size[1]): - left_neighbour = self.power_lines[row][col - 1] if col > 0 else None - top_neighbour = self.power_lines[row - 1][col] if row > 0 else None + left_neighbour = self.cells[row][col - 1] if col > 0 else None + top_neighbour = self.cells[row - 1][col] if row > 0 else None - line_type = random.choice(["line", "corner", "power_source"]) - power_line = PowerLine(line_type, left_neighbour, top_neighbour) + cell_type = random.choice(["line", "corner", "t_junction", "cross", "power_source", "house"]) - if line_type == "power_source": - self.power_sources.append(power_line) + if cell_type in ["line", "corner", "t_junction", "cross"]: + cell = PowerLine(cell_type, left_neighbour, top_neighbour) + elif cell_type == "power_source": + cell = PowerSource(left_neighbour, top_neighbour) + self.power_sources.append(cell) + elif cell_type == "house": + cell = House(left_neighbour, top_neighbour) + self.houses.append(cell) - self.power_grid.add(power_line, row=row, column=col) - self.power_lines[row].append(power_line) + self.power_grid.add(cell, row=row, column=col) + self.cells[row].append(cell) if left_neighbour: - left_neighbour.right_neighbour = power_line + left_neighbour.right_neighbour = cell if top_neighbour: - top_neighbour.bottom_neighbour = power_line + top_neighbour.bottom_neighbour = cell - arcade.schedule(self.update_grid, 1 / 10) + arcade.schedule(self.update_grid, 1 / 8) def update_grid(self, _): - for row in self.power_lines: + for row in self.cells: for power_line in row: - if power_line.line_type != "power_source": + if power_line.cell_type != "power_source": power_line.powered = False queue = deque(self.power_sources) @@ -74,7 +80,7 @@ class Game(arcade.gui.UIView): if id(connected_neighbour) not in visited: queue.append(connected_neighbour) - for row in self.power_lines: + for row in self.cells: for power_line in row: power_line.update_visual() diff --git a/game/power_line.py b/game/power_line.py deleted file mode 100644 index f648694..0000000 --- a/game/power_line.py +++ /dev/null @@ -1,104 +0,0 @@ -import arcade, arcade.gui - -from utils.preload import * - -TEXTURE_MAP = { - ("line", "vertical", True): vertical_powered, - ("line", "vertical", False): vertical_unpowered, - - ("line", "horizontal", True): horizontal_powered, - ("line", "horizontal", False): horizontal_unpowered, - - ("corner", "left_bottom", True): left_bottom_powered, - ("corner", "left_bottom", False): left_bottom_unpowered, - - ("corner", "left_top", True): left_top_powered, - ("corner", "left_top", False): left_top_unpowered, - - ("corner", "right_bottom", True): right_bottom_powered, - ("corner", "right_bottom", False): right_bottom_unpowered, - - ("corner", "right_top", True): right_top_powered, - ("corner", "right_top", False): right_top_unpowered, - - ("power_source", "all", True): power_source, -} - -ROTATIONS = { - "line": ["vertical", "horizontal"], - "corner": ["right_bottom", "left_bottom", "left_top", "right_top"], - "power_source": ["all"] -} - -NEIGHBOURS = { - "vertical": ["b", "t"], - "horizontal": ["l", "r"], - "left_bottom": ["l", "b"], - "right_bottom": ["r", "b"], - "left_top": ["l", "t"], - "right_top": ["r", "t"], - "all": ["l", "r", "t", "b"] -} - -def get_opposite(direction): - if direction == "l": - return "r" - elif direction == "r": - return "l" - - elif direction == "t": - return "b" - elif direction == "b": - return "t" - -class PowerLine(arcade.gui.UITextureButton): - def __init__(self, line_type, left_neighbour, top_neighbour): - super().__init__(texture=TEXTURE_MAP[line_type, ROTATIONS[line_type][0], line_type == "power_source"]) - - self.line_type = line_type - self.rotation = ROTATIONS[line_type][0] - self.powered = self.line_type == "power_source" - - self.left_neighbour, self.top_neighbour = left_neighbour, top_neighbour - self.right_neighbour, self.bottom_neighbour = None, None - - self.on_click = lambda e: self.next_rotation() - - self.update_visual() - - def next_rotation(self): - current_index = ROTATIONS[self.line_type].index(self.rotation) - - if current_index + 1 == len(ROTATIONS[self.line_type]): - self.rotation = ROTATIONS[self.line_type][0] - else: - self.rotation = ROTATIONS[self.line_type][current_index + 1] - - self.update_visual() - - def get_neighbour(self, name): - if name == "l": - return self.left_neighbour - elif name == "r": - return self.right_neighbour - elif name == "b": - return self.bottom_neighbour - elif name == "t": - return self.top_neighbour - - def get_connected_neighbours(self): - return [ - self.get_neighbour(neighbour_direction) for neighbour_direction in NEIGHBOURS[self.rotation] - if ( - self.get_neighbour(neighbour_direction) and - get_opposite(neighbour_direction) in NEIGHBOURS[self.get_neighbour(neighbour_direction).rotation] - ) - ] - - def update_value(self): - self.powered = any([neighbour.powered for neighbour in self.get_connected_neighbours()]) - - def update_visual(self): - self.texture = TEXTURE_MAP[(self.line_type, self.rotation, self.powered)] - self.texture_hovered = TEXTURE_MAP[(self.line_type, self.rotation, self.powered)] - self._requires_render = True \ No newline at end of file diff --git a/utils/constants.py b/utils/constants.py index 41c9ae0..d60fed6 100644 --- a/utils/constants.py +++ b/utils/constants.py @@ -3,6 +3,30 @@ from arcade.types import Color from arcade.gui.widgets.buttons import UITextureButtonStyle, UIFlatButtonStyle from arcade.gui.widgets.slider import UISliderStyle +ROTATIONS = { + "line": ["vertical", "horizontal"], + "corner": ["right_bottom", "left_bottom", "left_top", "right_top"], + "t_junction": ["top_bottom_right", "left_right_bottom", "top_bottom_left", "left_right_top"], + "cross": ["cross"], + "power_source": ["cross"], + "house": ["cross"] +} + +NEIGHBOURS = { + "vertical": ["b", "t"], + "horizontal": ["l", "r"], + "left_bottom": ["l", "b"], + "right_bottom": ["r", "b"], + "left_top": ["l", "t"], + "right_top": ["r", "t"], + "top_bottom_right": ["t", "b", "r"], + "top_bottom_left": ["t", "b", "l"], + "left_right_bottom": ["l", "r", "b"], + "left_right_top": ["l", "r", "t"], + "cross": ["l", "r", "t", "b"] +} + + menu_background_color = (30, 30, 47) log_dir = 'logs' discord_presence_id = 1435687634960777266 diff --git a/utils/preload.py b/utils/preload.py index 43fe057..84721a6 100644 --- a/utils/preload.py +++ b/utils/preload.py @@ -3,18 +3,42 @@ import arcade.gui, arcade button_texture = arcade.gui.NinePatchTexture(64 // 4, 64 // 4, 64 // 4, 64 // 4, arcade.load_texture("assets/graphics/button.png")) button_hovered_texture = arcade.gui.NinePatchTexture(64 // 4, 64 // 4, 64 // 4, 64 // 4, arcade.load_texture("assets/graphics/button_hovered.png")) -vertical_powered = arcade.load_texture("assets/graphics/powered_lines/line/vertical.png") -horizontal_powered = arcade.load_texture("assets/graphics/powered_lines/line/horizontal.png") -left_bottom_powered = arcade.load_texture("assets/graphics/powered_lines/corner/left_bottom.png") -left_top_powered = arcade.load_texture("assets/graphics/powered_lines/corner/left_top.png") -right_bottom_powered = arcade.load_texture("assets/graphics/powered_lines/corner/right_bottom.png") -right_top_powered = arcade.load_texture("assets/graphics/powered_lines/corner/right_top.png") +TEXTURE_MAP = { + ("line", "vertical", True): arcade.load_texture("assets/graphics/powered_lines/line/vertical.png"), + ("line", "vertical", False): arcade.load_texture("assets/graphics/unpowered_lines/line/vertical.png"), + + ("line", "horizontal", True): arcade.load_texture("assets/graphics/powered_lines/line/horizontal.png"), + ("line", "horizontal", False): arcade.load_texture("assets/graphics/unpowered_lines/line/horizontal.png"), -vertical_unpowered = arcade.load_texture("assets/graphics/unpowered_lines/line/vertical.png") -horizontal_unpowered = arcade.load_texture("assets/graphics/unpowered_lines/line/horizontal.png") -left_bottom_unpowered = arcade.load_texture("assets/graphics/unpowered_lines/corner/left_bottom.png") -left_top_unpowered = arcade.load_texture("assets/graphics/unpowered_lines/corner/left_top.png") -right_bottom_unpowered = arcade.load_texture("assets/graphics/unpowered_lines/corner/right_bottom.png") -right_top_unpowered = arcade.load_texture("assets/graphics/unpowered_lines/corner/right_top.png") + ("corner", "left_bottom", True): arcade.load_texture("assets/graphics/powered_lines/corner/left_bottom.png"), + ("corner", "left_bottom", False): arcade.load_texture("assets/graphics/unpowered_lines/corner/left_bottom.png"), + + ("corner", "left_top", True): arcade.load_texture("assets/graphics/powered_lines/corner/left_top.png"), + ("corner", "left_top", False): arcade.load_texture("assets/graphics/unpowered_lines/corner/left_top.png"), + + ("corner", "right_bottom", True): arcade.load_texture("assets/graphics/powered_lines/corner/right_bottom.png"), + ("corner", "right_bottom", False): arcade.load_texture("assets/graphics/unpowered_lines/corner/right_bottom.png"), + + ("corner", "right_top", True): arcade.load_texture("assets/graphics/powered_lines/corner/right_top.png"), + ("corner", "right_top", False): arcade.load_texture("assets/graphics/unpowered_lines/corner/right_top.png"), -power_source = arcade.load_texture("assets/graphics/power_source.png") + ("t_junction", "left_right_bottom", True): arcade.load_texture("assets/graphics/powered_lines/t_junction/left_right_bottom.png"), + ("t_junction", "left_right_bottom", False): arcade.load_texture("assets/graphics/unpowered_lines/t_junction/left_right_bottom.png"), + + ("t_junction", "left_right_top", True): arcade.load_texture("assets/graphics/powered_lines/t_junction/left_right_top.png"), + ("t_junction", "left_right_top", False): arcade.load_texture("assets/graphics/unpowered_lines/t_junction/left_right_top.png"), + + ("t_junction", "top_bottom_left", True): arcade.load_texture("assets/graphics/powered_lines/t_junction/top_bottom_left.png"), + ("t_junction", "top_bottom_left", False): arcade.load_texture("assets/graphics/unpowered_lines/t_junction/top_bottom_left.png"), + + ("t_junction", "top_bottom_right", True): arcade.load_texture("assets/graphics/powered_lines/t_junction/top_bottom_right.png"), + ("t_junction", "top_bottom_right", False): arcade.load_texture("assets/graphics/unpowered_lines/t_junction/top_bottom_right.png"), + + ("cross", "cross", True): arcade.load_texture("assets/graphics/powered_lines/cross/cross.png"), + ("cross", "cross", False): arcade.load_texture("assets/graphics/unpowered_lines/cross/cross.png"), + + ("power_source", "cross", True): arcade.load_texture("assets/graphics/power_source.png"), + + ("house", "cross", False): button_texture, + ("house", "cross", True): button_texture, +}