From ab9035e76d098c988090695cbecc1e7b6307e118 Mon Sep 17 00:00:00 2001 From: csd4ni3l Date: Tue, 14 Oct 2025 18:23:41 +0200 Subject: [PATCH] Add more levels and introduce NOT gate with single input --- game/play.py | 18 ++++-- menus/level_selector.py | 10 ++-- utils/constants.py | 119 +++++++++++++++++++++++++++++++++++----- 3 files changed, 123 insertions(+), 24 deletions(-) diff --git a/game/play.py b/game/play.py index 697f822..1403f64 100644 --- a/game/play.py +++ b/game/play.py @@ -1,11 +1,11 @@ import arcade, arcade.gui, random, datetime, os, json -from utils.utils import cubic_bezier_points, get_gate_port_position, generate_task_text -from utils.constants import button_style, dropdown_style, LOGICAL_GATES, LEVELS -from utils.preload import button_texture, button_hovered_texture - from datetime import datetime +from utils.utils import cubic_bezier_points, get_gate_port_position, generate_task_text +from utils.constants import button_style, dropdown_style, LOGICAL_GATES, LEVELS, SINGLE_INPUT_LOGICAL_GATES +from utils.preload import button_texture, button_hovered_texture + class LogicalGate(arcade.gui.UIBoxLayout): def __init__(self, id, x, y, gate_type, value): super().__init__(x=x, y=y, space_between=2, vertical=False) @@ -34,6 +34,8 @@ class LogicalGate(arcade.gui.UIBoxLayout): self.value = self.input[0].calculate_value() elif self.gate_type == "INPUT": # dont set INPUT to None pass + elif self.gate_type in SINGLE_INPUT_LOGICAL_GATES and len(self.input) == 1: + self.value = int(LOGICAL_GATES[self.gate_type](self.input[0].calculate_value())) elif len(self.input) == 2: self.value = int(LOGICAL_GATES[self.gate_type](self.input[0].calculate_value(), self.input[1].calculate_value())) # have to convert to int cause it might return boolean else: @@ -179,7 +181,9 @@ class Game(arcade.gui.UIView): else: process_nodes.remove(requirement[1]) - self.data["completed_levels"].append(self.level_num) + if not self.level_num in self.data["completed_levels"]: + self.data["completed_levels"].append(self.level_num) + self.task_label.text = f"You Successfully Completed Level {self.level_num + 1}!" with open("data.json", "w") as file: @@ -193,7 +197,9 @@ class Game(arcade.gui.UIView): self.selected_input = None def select_input(self, gate_id): - if len(self.gates[gate_id].input) == 2: + if self.gates[gate_id].gate_type not in SINGLE_INPUT_LOGICAL_GATES and len(self.gates[gate_id].input) == 2: + return + elif self.gates[gate_id].gate_type in SINGLE_INPUT_LOGICAL_GATES and len(self.gates[gate_id].input) == 1: return if self.selected_output is not None: diff --git a/menus/level_selector.py b/menus/level_selector.py index 8569a7f..f7c5a3a 100644 --- a/menus/level_selector.py +++ b/menus/level_selector.py @@ -36,23 +36,23 @@ class LevelSelector(arcade.gui.UIView): for n in range(len(LEVELS)): row, col = n // 5, n % 5 - if n < 5: + if n < 8: difficulty = "Easy" - elif n < 15: + elif n < 21: difficulty = "Intermediate" - elif n < 20: + elif n < 30: difficulty = "Hard" else: difficulty = "Extra Hard" completed_notice = '\n(Completed)' if n in self.data['completed_levels'] else '' - level_button = self.grid.add(arcade.gui.UITextureButton(width=self.window.width / 8, height=self.window.height / 8, text=f"{difficulty} Level {n + 1}{completed_notice}", texture=button_texture, texture_hovered=button_hovered_texture, style=button_style, multiline=True), row=row, column=col) + level_button = self.grid.add(arcade.gui.UITextureButton(width=self.window.width / 8, height=self.window.height / 12, text=f"{difficulty} Level {n + 1}{completed_notice}", texture=button_texture, texture_hovered=button_hovered_texture, style=button_style, multiline=True), row=row, column=col) level_button.on_click = lambda event, n=n: self.play(n) row, col = (n + 1) // 5, (n + 1) % 5 - diy_button = self.anchor.add(arcade.gui.UITextureButton(width=self.window.width / 2, height=self.window.height / 8, text=f"DIY", texture=button_texture, texture_hovered=button_hovered_texture, style=button_style), anchor_x="center", anchor_y="bottom", align_y=20) + diy_button = self.anchor.add(arcade.gui.UITextureButton(width=self.window.width / 2, height=self.window.height / 10, text=f"DIY", texture=button_texture, texture_hovered=button_hovered_texture, style=button_style), anchor_x="center", anchor_y="bottom", align_y=10) diy_button.on_click = lambda event: self.play(-1) self.grid._trigger_size_hint_update() diff --git a/utils/constants.py b/utils/constants.py index 5968f9a..e4cd8ed 100644 --- a/utils/constants.py +++ b/utils/constants.py @@ -7,6 +7,8 @@ menu_background_color = (30, 30, 47) log_dir = 'logs' discord_presence_id = 1427213145667276840 +SINGLE_INPUT_LOGICAL_GATES = ["NOT"] + LOGICAL_GATES = { "AND": lambda a, b: a and b, "OR": lambda a, b: a or b, @@ -14,11 +16,11 @@ LOGICAL_GATES = { "NOR": lambda a, b: not (a or b), "XOR": lambda a, b: a != b, "XNOR": lambda a, b: a == b, + "NOT": lambda a: not a, } LEVELS = [ - # EASY - +# EASY [ [2, "INPUT", 1], [1, "AND"], @@ -30,6 +32,11 @@ LEVELS = [ [1, "OR"], [1, "OUTPUT", 1] ], + [ + [1, "INPUT", 1], + [1, "NOT"], + [1, "OUTPUT", 0] + ], [ [2, "INPUT", 1], [1, "NAND"], @@ -41,6 +48,13 @@ LEVELS = [ [1, "XOR"], [1, "OUTPUT", 1] ], + [ + [1, "INPUT", 0], + [1, "INPUT", 1], + [1, "NOT"], + [1, "AND"], + [1, "OUTPUT", 1] + ], [ [2, "INPUT", 1], [1, "INPUT", 0], @@ -48,9 +62,13 @@ LEVELS = [ [1, "OR"], [1, "OUTPUT", 1] ], - - # INTERMEDIATE - + [ + [2, "INPUT", 1], + [1, "NOT"], + [1, "NAND"], + [1, "OUTPUT", 1] + ], +# INTERMEDIATE [ [2, "INPUT", 0], [1, "INPUT", 1], @@ -65,6 +83,13 @@ LEVELS = [ [1, "OR"], [1, "OUTPUT", 1] ], + [ + [1, "INPUT", 1], + [1, "INPUT", 0], + [1, "NOT"], + [1, "XOR"], + [1, "OUTPUT", 0] + ], [ [2, "INPUT", 1], [2, "INPUT", 0], @@ -73,6 +98,14 @@ LEVELS = [ [1, "XOR"], [1, "OUTPUT", 0] ], + [ + [2, "INPUT", 0], + [1, "INPUT", 1], + [1, "NOT"], + [1, "NOR"], + [1, "OR"], + [1, "OUTPUT", 1] + ], [ [3, "INPUT", 1], [1, "INPUT", 0], @@ -86,6 +119,14 @@ LEVELS = [ [1, "AND"], [1, "OUTPUT", 1] ], + [ + [2, "INPUT", 1], + [1, "INPUT", 0], + [1, "NOT"], + [1, "AND"], + [1, "NAND"], + [1, "OUTPUT", 0] + ], [ [2, "INPUT", 1], [2, "INPUT", 0], @@ -110,8 +151,9 @@ LEVELS = [ [1, "OUTPUT", 1] ], [ - [4, "INPUT", 0], [1, "INPUT", 1], + [3, "INPUT", 0], + [1, "NOT"], [2, "OR"], [1, "NAND"], [1, "OUTPUT", 0] @@ -124,9 +166,16 @@ LEVELS = [ [1, "AND"], [1, "OUTPUT", 0] ], - - # HARD - +# HARD + [ + [3, "INPUT", 1], + [1, "INPUT", 0], + [1, "NOT"], + [1, "AND"], + [1, "OR"], + [1, "XOR"], + [1, "OUTPUT", 0] + ], [ [3, "INPUT", 1], [2, "INPUT", 0], @@ -136,6 +185,14 @@ LEVELS = [ [1, "XOR"], [1, "OUTPUT", 1] ], + [ + [2, "INPUT", 1], + [2, "INPUT", 0], + [2, "NOT"], + [1, "NAND"], + [1, "OR"], + [1, "OUTPUT", 1] + ], [ [2, "INPUT", 1], [2, "INPUT", 0], @@ -143,6 +200,15 @@ LEVELS = [ [1, "OR"], [1, "OUTPUT", 0] ], + [ + [3, "INPUT", 0], + [1, "INPUT", 1], + [1, "NOT"], + [2, "NOR"], + [1, "XOR"], + [1, "XNOR"], + [1, "OUTPUT", 1] + ], [ [4, "INPUT", 0], [2, "INPUT", 1], @@ -160,6 +226,15 @@ LEVELS = [ [1, "XOR"], [1, "OUTPUT", 0] ], + [ + [2, "INPUT", 1], + [3, "INPUT", 0], + [1, "NOT"], + [2, "XOR"], + [1, "NAND"], + [1, "NOR"], + [1, "OUTPUT", 0] + ], [ [4, "INPUT", 1], [2, "INPUT", 0], @@ -169,9 +244,7 @@ LEVELS = [ [1, "XNOR"], [1, "OUTPUT", 1] ], - - # Extra Hard - +# EXTRA HARD [ [2, "INPUT", 1], [2, "INPUT", 0], @@ -182,6 +255,16 @@ LEVELS = [ [1, "OUTPUT", 0], [1, "OUTPUT", 1] ], + [ + [2, "INPUT", 1], + [1, "INPUT", 0], + [1, "NOT"], + [1, "AND"], + [1, "OR"], + [1, "XOR"], + [1, "OUTPUT", 0], + [1, "OUTPUT", 1] + ], [ [3, "INPUT", 1], [3, "INPUT", 0], @@ -192,6 +275,16 @@ LEVELS = [ [1, "OUTPUT", 1], [1, "OUTPUT", 0] ], + [ + [2, "INPUT", 1], + [2, "INPUT", 0], + [2, "NOT"], + [1, "NAND"], + [1, "NOR"], + [1, "XOR"], + [1, "OUTPUT", 1], + [1, "OUTPUT", 0] + ], [ [4, "INPUT", 1], [2, "INPUT", 0], @@ -199,7 +292,7 @@ LEVELS = [ [2, "XNOR"], [1, "AND"], [1, "OR"], - [2, "OUTPUT", 1], + [2, "OUTPUT", 1] ], [ [3, "INPUT", 1],