From f4054fafa85316b6e8a4d8f7c2e293e44a9f2dfd Mon Sep 17 00:00:00 2001 From: csd4ni3l Date: Mon, 13 Oct 2025 21:24:30 +0200 Subject: [PATCH] Remove bloat, add level selector and some basic levels that just create input and outputs currently, no checking, make tool box invisible during screenshot --- game/play.py | 34 +++++++++++++++++++++++-------- menus/level_selector.py | 44 +++++++++++++++++++++++++++++++++++++++++ menus/main.py | 4 ++-- utils/constants.py | 22 +++++++++++++++++++-- utils/utils.py | 9 +++++++-- 5 files changed, 99 insertions(+), 14 deletions(-) create mode 100644 menus/level_selector.py diff --git a/game/play.py b/game/play.py index 49f3a0d..1045fe5 100644 --- a/game/play.py +++ b/game/play.py @@ -1,19 +1,19 @@ import arcade, arcade.gui, random, datetime -from utils.utils import cubic_bezier_points, get_gate_port_position -from utils.constants import dropdown_style, LOGICAL_GATES +from utils.utils import cubic_bezier_points, get_gate_port_position, generate_task_text +from utils.constants import dropdown_style, LOGICAL_GATES, LEVELS from datetime import datetime class LogicalGate(arcade.gui.UIBoxLayout): - def __init__(self, id, x, y, gate_type): + def __init__(self, id, x, y, gate_type, value): super().__init__(x=x, y=y, space_between=2, vertical=False) self.id = id self.gate_type = gate_type if gate_type == "INPUT": - self.value = 1 + self.value = value else: self.value = 0 @@ -41,12 +41,14 @@ class LogicalGate(arcade.gui.UIBoxLayout): return f"{self.gate_type}: {self.value}" class Game(arcade.gui.UIView): - def __init__(self, pypresence_client): + def __init__(self, pypresence_client, level_num): super().__init__() self.pypresence_client = pypresence_client self.pypresence_client.update(state="In game") + self.level_num = level_num + self.gates: list[LogicalGate] = [] self.connections = [] self.default_gate_type = "AND" @@ -60,9 +62,19 @@ class Game(arcade.gui.UIView): self.anchor = self.add_widget(arcade.gui.UIAnchorLayout(size_hint=(1, 1))) self.tools_box = self.anchor.add(arcade.gui.UIBoxLayout(space_between=5), anchor_x="right", anchor_y="bottom", align_x=-5, align_y=20) + self.task_label = self.anchor.add(arcade.gui.UILabel(text=generate_task_text(LEVELS[level_num]), font_size=24), anchor_x="center", anchor_y="top") + for gate in LOGICAL_GATES.keys(): button = self.tools_box.add(arcade.gui.UIFlatButton(width=self.window.width * 0.1, height=self.window.height * 0.075, text=f"Create {gate} gate", style=dropdown_style)) - button.on_click = lambda event, gate=gate: self.add_gate(random.randint(0, self.window.width - 100), random.randint(200, self.window.height - 100), gate) + button.on_click = lambda event, gate=gate: self.add_gate(random.randint(0, self.window.width - 300), random.randint(200, self.window.height - 100), gate) + + for requirement in LEVELS[level_num]: + if requirement[1] == "INPUT": + for _ in range(requirement[0]): + self.add_gate(random.randint(0, self.window.width - 300), random.randint(200, self.window.height - 100), "INPUT", requirement[2]) + elif requirement[1] == "OUTPUT": + for _ in range(requirement[0]): + self.add_gate(random.randint(0, self.window.width - 300), random.randint(200, self.window.height - 100), "OUTPUT") evaluate_button = self.tools_box.add(arcade.gui.UIFlatButton(width=self.window.width * 0.1, height=self.window.height * 0.075, text="Evaluate", style=dropdown_style)) evaluate_button.on_click = lambda event: self.run_logic() @@ -74,11 +86,17 @@ class Game(arcade.gui.UIView): hide_button.on_click = lambda event: self.hide_show_panel() def screenshot(self): + self.tools_box.visible = False + self.tools_box._requires_render = True + self.on_draw() + image = arcade.get_image() now = datetime.now() timestamp = now.strftime("%Y-%m-%d_%H-%M-%S") image.save(f"{timestamp}.png") + self.tools_box.visible = True + self.add_widget(arcade.gui.UIMessageBox( width=self.window.width / 2, height=self.window.height / 2, @@ -132,8 +150,8 @@ class Game(arcade.gui.UIView): self.selected_output = None self.selected_input = None - def add_gate(self, x, y, gate_type): - self.gates.append(self.add_widget(LogicalGate(len(self.gates), x, y, gate_type))) + def add_gate(self, x, y, gate_type, value=None): + self.gates.append(self.add_widget(LogicalGate(len(self.gates), x, y, gate_type, value))) self.gates[-1].input_add_button.on_click = lambda e, gate_id=len(self.gates) - 1: self.select_input(gate_id) self.gates[-1].output_add_button.on_click = lambda e, gate_id=len(self.gates) - 1: self.select_output(gate_id) diff --git a/menus/level_selector.py b/menus/level_selector.py new file mode 100644 index 0000000..8f9daf6 --- /dev/null +++ b/menus/level_selector.py @@ -0,0 +1,44 @@ +import arcade, arcade.gui + +from math import ceil + +from utils.constants import button_style, LEVELS +from utils.preload import button_texture, button_hovered_texture + +class LevelSelector(arcade.gui.UIView): + def __init__(self, pypresence_client): + super().__init__() + + self.pypresence_client = pypresence_client + self.pypresence_client.update(state="In Menus", details="Level Selector") + + self.anchor = self.add_widget(arcade.gui.UIAnchorLayout(size_hint=(1, 1))) + self.grid = self.anchor.add(arcade.gui.UIGridLayout(width=self.window.width / 2, height=self.window.height / 2, vertical_spacing=10, horizontal_spacing=10, column_count=5, row_count=ceil(len(LEVELS) / 5)), anchor_x="center", anchor_y="top", align_y=-self.window.height / 8) + + def on_show_view(self): + super().on_show_view() + + self.back_button = arcade.gui.UITextureButton(texture=button_texture, texture_hovered=button_hovered_texture, text='<--', style=button_style, width=100, height=50) + self.back_button.on_click = lambda event: self.main_exit() + self.anchor.add(self.back_button, anchor_x="left", anchor_y="top", align_x=5, align_y=-5) + + self.anchor.add(arcade.gui.UILabel(text="Level Selector", font_size=40), anchor_x="center", anchor_y="top") + + for n in range(len(LEVELS)): + row, col = n // 5, n % 5 + level_button = self.grid.add(arcade.gui.UITextureButton(width=self.window.width / 8, height=self.window.height / 8, text=f"Level {n + 1}", texture=button_texture, texture_hovered=button_hovered_texture, style=button_style), row=row, column=col) + level_button.on_click = lambda event, n=n: self.play(n) + + self.grid._trigger_size_hint_update() + + def main_exit(self): + from menus.main import Main + self.window.show_view(Main(self.pypresence_client)) + + def play(self, n): + from game.play import Game + self.window.show_view(Game(self.pypresence_client, n)) + + def on_key_press(self, symbol, modifiers): + if symbol == arcade.key.ESCAPE: + self.main_exit() diff --git a/menus/main.py b/menus/main.py index 12383e7..785bdaa 100644 --- a/menus/main.py +++ b/menus/main.py @@ -59,8 +59,8 @@ class Main(arcade.gui.UIView): self.settings_button.on_click = lambda event: self.settings() def play(self): - from game.play import Game - self.window.show_view(Game(self.pypresence_client)) + from menus.level_selector import LevelSelector + self.window.show_view(LevelSelector(self.pypresence_client)) def settings(self): from menus.settings import Settings diff --git a/utils/constants.py b/utils/constants.py index 49f3de9..c690517 100644 --- a/utils/constants.py +++ b/utils/constants.py @@ -8,16 +8,34 @@ log_dir = 'logs' discord_presence_id = 1427213145667276840 LOGICAL_GATES = { - "INPUT": lambda a: a, "AND": lambda a, b: a and b, "OR": lambda a, b: a or b, "NAND": lambda a, b: not (a and b), "NOR": lambda a, b: not (a or b), "XOR": lambda a, b: a != b, "XNOR": lambda a, b: a == b, - "OUTPUT": lambda a: a } +LEVELS = [ + [ + [2, "INPUT", 1], + [1, "AND"], + [1, "OUTPUT", 1] + ], + [ + [1, "INPUT", 1], + [1, "INPUT", 0], + [1, "AND"], + [1, "OUTPUT", 0] + ], + [ + [1, "INPUT", 0], + [1, "INPUT", 1], + [1, "OR"], + [1, "OUTPUT", 1] + ] +] + button_style = {'normal': UITextureButtonStyle(font_name="Roboto", font_color=arcade.color.BLACK), 'hover': UITextureButtonStyle(font_name="Roboto", font_color=arcade.color.BLACK), 'press': UITextureButtonStyle(font_name="Roboto", font_color=arcade.color.BLACK), 'disabled': UITextureButtonStyle(font_name="Roboto", font_color=arcade.color.BLACK)} big_button_style = {'normal': UITextureButtonStyle(font_name="Roboto", font_color=arcade.color.BLACK, font_size=26), 'hover': UITextureButtonStyle(font_name="Roboto", font_color=arcade.color.BLACK, font_size=26), diff --git a/utils/utils.py b/utils/utils.py index 9a1bc51..c1d9a24 100644 --- a/utils/utils.py +++ b/utils/utils.py @@ -4,8 +4,13 @@ from utils.constants import menu_background_color import pyglet.display -def lerp(a, b, t): - return a + (b - a) * t +def generate_task_text(level): + text = "Task: You need to use " + + text += f"{', '.join([f'{requirement[0]} {requirement[1]} gate(s)' for requirement in level if not requirement[1] in ['INPUT', 'OUTPUT']])}" + text += f" to result in {', '.join([f'{requirement[0]} OUTPUT gate(s) with value {requirement[2]}' for requirement in level if requirement[1] == 'OUTPUT'])}" + + return text def cubic_bezier_point(p0, p1, p2, p3, t): u = 1 - t