mirror of
https://github.com/csd4ni3l/chaos-protocol.git
synced 2026-01-01 04:23:43 +01:00
Fix connected component giving a single edge, add backtracking for rulesets, add previous property, add a better default ruleset, fix trash only working on hover and not intersection, fix dragging, update play.py a bit to be more compatible
This commit is contained in:
64
game/play.py
64
game/play.py
@@ -176,13 +176,13 @@ class Game(arcade.gui.UIView):
|
|||||||
|
|
||||||
self.triggered_events.append(["game_launch", {}])
|
self.triggered_events.append(["game_launch", {}])
|
||||||
|
|
||||||
def get_rule_values(self, ruleset_num, rule_num, rule_dict, event_args):
|
def get_rule_values(self, rule_num, rule_dict, rule_values, event_args):
|
||||||
args = [self.rule_values[f"{ruleset_num}_{rule_num}_{user_var}_{n}"] for n, user_var in enumerate(rule_dict["user_vars"])]
|
args = [rule_values[f"{rule_num}_{user_var}_{n}"] for n, user_var in enumerate(rule_dict["user_vars"])]
|
||||||
|
|
||||||
return args + [event_args[var] for var in rule_dict.get("vars", []) if not var in rule_dict["user_vars"]]
|
return args + [event_args[var] for var in rule_dict.get("vars", []) if not var in rule_dict["user_vars"]]
|
||||||
|
|
||||||
def check_rule(self, ruleset_num, rule_num, rule_dict, event_args):
|
def check_rule(self, rule_num, rule_dict, rule_values, event_args):
|
||||||
return rule_dict["func"](*self.get_rule_values(ruleset_num, rule_num, rule_dict, event_args))
|
return rule_dict["func"](*self.get_rule_values(rule_num, rule_dict, rule_values, event_args))
|
||||||
|
|
||||||
def get_action_function(self, action_dict):
|
def get_action_function(self, action_dict):
|
||||||
ACTION_FUNCTION_DICT = {
|
ACTION_FUNCTION_DICT = {
|
||||||
@@ -207,8 +207,8 @@ class Game(arcade.gui.UIView):
|
|||||||
|
|
||||||
return ACTION_FUNCTION_DICT[action_dict["type"]][action_dict["name"]]
|
return ACTION_FUNCTION_DICT[action_dict["type"]][action_dict["name"]]
|
||||||
|
|
||||||
def run_do_rule(self, ruleset_num, rule_num, rule_dict, event_args):
|
def run_do_rule(self, rule_num, rule_dict, rule_values, event_args):
|
||||||
self.get_action_function(rule_dict["action"])(*self.get_rule_values(ruleset_num, rule_num, rule_dict, event_args))
|
self.get_action_function(rule_dict["action"])(*self.get_rule_values(rule_num, rule_dict, rule_values, event_args))
|
||||||
|
|
||||||
def on_update(self, delta_time):
|
def on_update(self, delta_time):
|
||||||
if self.mode == "import" and self.file_manager.submitted_content:
|
if self.mode == "import" and self.file_manager.submitted_content:
|
||||||
@@ -238,57 +238,9 @@ class Game(arcade.gui.UIView):
|
|||||||
|
|
||||||
while len(self.triggered_events) > 0:
|
while len(self.triggered_events) > 0:
|
||||||
trigger, trigger_args = self.triggered_events.pop(0)
|
trigger, trigger_args = self.triggered_events.pop(0)
|
||||||
for key, ruleset in self.rulesets.items():
|
|
||||||
if len(ruleset) == 2:
|
|
||||||
if_rule_dict = IF_RULES[ruleset[0]]
|
|
||||||
do_rule_dict = DO_RULES[ruleset[1]]
|
|
||||||
|
|
||||||
if not if_rule_dict["trigger"] == trigger:
|
for rule in self.rulesets:
|
||||||
continue
|
...
|
||||||
|
|
||||||
if do_rule_dict["action"]["type"] == "shape_action" or "shape_type" in if_rule_dict["user_vars"]:
|
|
||||||
for shape in self.shapes:
|
|
||||||
event_args = trigger_args.copy()
|
|
||||||
if not "event_shape_type" in trigger_args:
|
|
||||||
event_args.update({"event_shape_type": shape.shape_type, "shape_size": shape.shape_size, "shape_x": shape.x, "shape_y": shape.y, "shape": shape, "shape_color": shape.shape_color})
|
|
||||||
|
|
||||||
if self.check_rule(key, 1, if_rule_dict, event_args):
|
|
||||||
self.run_do_rule(key, 2, do_rule_dict, event_args)
|
|
||||||
else:
|
|
||||||
event_args = trigger_args.copy()
|
|
||||||
if self.check_rule(key, 1, if_rule_dict, event_args):
|
|
||||||
self.run_do_rule(key, 2, do_rule_dict, event_args)
|
|
||||||
|
|
||||||
else:
|
|
||||||
if_rule_dicts = IF_RULES[ruleset[0]], IF_RULES[ruleset[2]]
|
|
||||||
do_rule_dict = DO_RULES[ruleset[3]]
|
|
||||||
|
|
||||||
if not (if_rule_dicts[0]["trigger"] == trigger and if_rule_dicts[0]["trigger"] == trigger):
|
|
||||||
continue
|
|
||||||
|
|
||||||
if do_rule_dict["action"]["type"] == "shape_action":
|
|
||||||
for shape in self.shapes:
|
|
||||||
event_args = trigger_args
|
|
||||||
|
|
||||||
if not "event_shape_type" in trigger_args:
|
|
||||||
event_args.update({"event_shape_type": shape.shape_type, "shape_size": shape.shape_size, "shape_x": shape.x, "shape_y": shape.y, "shape": shape, "shape_color": shape.shape_color})
|
|
||||||
|
|
||||||
if ruleset[1] == "and":
|
|
||||||
if self.check_rule(key, 1, if_rule_dicts[0], event_args) and self.check_rule(key, 2, if_rule_dicts[1], event_args):
|
|
||||||
self.run_do_rule(key, 3, do_rule_dict, event_args)
|
|
||||||
|
|
||||||
elif ruleset[1] == "or":
|
|
||||||
if self.check_rule(key, 1, if_rule_dicts[0], event_args) or self.check_rule(key, 2, if_rule_dicts[1], event_args):
|
|
||||||
self.run_do_rule(key, 3, do_rule_dict, event_args)
|
|
||||||
else:
|
|
||||||
event_args = trigger_args
|
|
||||||
if ruleset[1] == "and":
|
|
||||||
if self.check_rule(key, 1, if_rule_dicts[0], event_args) and self.check_rule(key, 2, if_rule_dicts[1], event_args):
|
|
||||||
self.run_do_rule(key, 3, do_rule_dict, event_args)
|
|
||||||
|
|
||||||
elif ruleset[1] == "or":
|
|
||||||
if self.check_rule(key, 1, if_rule_dicts[0], event_args) or self.check_rule(key, 2, if_rule_dicts[1], event_args):
|
|
||||||
self.run_do_rule(key, 3, do_rule_dict, event_args)
|
|
||||||
|
|
||||||
for shape in self.shapes:
|
for shape in self.shapes:
|
||||||
for shape_b in self.shapes:
|
for shape_b in self.shapes:
|
||||||
|
|||||||
113
game/rules.py
113
game/rules.py
@@ -50,12 +50,13 @@ def connection_between(p0, p3, start_dir_y, end_dir_y):
|
|||||||
|
|
||||||
def connected_component(edges, start):
|
def connected_component(edges, start):
|
||||||
graph = defaultdict(set)
|
graph = defaultdict(set)
|
||||||
for u, v in edges:
|
for u, v, _, __ in edges:
|
||||||
graph[u].add(v)
|
graph[u].add(v)
|
||||||
graph[v].add(u)
|
graph[v].add(u)
|
||||||
|
|
||||||
seen = set([start])
|
seen = set([start])
|
||||||
queue = deque([start])
|
queue = deque([start])
|
||||||
|
connected_edges = []
|
||||||
|
|
||||||
while queue:
|
while queue:
|
||||||
node = queue.popleft()
|
node = queue.popleft()
|
||||||
@@ -63,8 +64,11 @@ def connected_component(edges, start):
|
|||||||
if neighbor not in seen:
|
if neighbor not in seen:
|
||||||
seen.add(neighbor)
|
seen.add(neighbor)
|
||||||
queue.append(neighbor)
|
queue.append(neighbor)
|
||||||
|
connected_edges.append((node, neighbor))
|
||||||
|
elif (neighbor, node) not in connected_edges and (node, neighbor) not in connected_edges:
|
||||||
|
connected_edges.append((node, neighbor))
|
||||||
|
|
||||||
return list(seen)
|
return connected_edges
|
||||||
|
|
||||||
def get_rule_defaults(rule_type):
|
def get_rule_defaults(rule_type):
|
||||||
if rule_type == "if":
|
if rule_type == "if":
|
||||||
@@ -101,6 +105,26 @@ def get_rule_defaults(rule_type):
|
|||||||
for rule_key, rule_dict in DO_RULES.items()
|
for rule_key, rule_dict in DO_RULES.items()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def backtrace(node: dict):
|
||||||
|
dependencies = []
|
||||||
|
|
||||||
|
for prev_node_list in node.previous.values():
|
||||||
|
for prev_node in prev_node_list:
|
||||||
|
if prev_node.rule_type == "comparison":
|
||||||
|
comparison_children = backtrace(prev_node)
|
||||||
|
dependencies.append([
|
||||||
|
prev_node.rule_type,
|
||||||
|
prev_node.rule,
|
||||||
|
comparison_children,
|
||||||
|
prev_node.rule_num
|
||||||
|
])
|
||||||
|
elif prev_node.rule_type == "if":
|
||||||
|
dependencies.append([prev_node.rule_type, prev_node.rule, prev_node.rule_values, prev_node.rule_num])
|
||||||
|
elif prev_node.rule_type == "do":
|
||||||
|
dependencies.append([prev_node.rule_type, prev_node.rule, prev_node.rule_values, prev_node.rule_num])
|
||||||
|
|
||||||
|
return dependencies
|
||||||
|
|
||||||
class RuleBox(arcade.gui.UIBoxLayout):
|
class RuleBox(arcade.gui.UIBoxLayout):
|
||||||
def __init__(self, x, y, width, height, rule_num, rule_type, rule):
|
def __init__(self, x, y, width, height, rule_num, rule_type, rule):
|
||||||
super().__init__(space_between=5, x=x, y=y, width=width, height=height)
|
super().__init__(space_between=5, x=x, y=y, width=width, height=height)
|
||||||
@@ -110,6 +134,8 @@ class RuleBox(arcade.gui.UIBoxLayout):
|
|||||||
self.rule_type = rule_type
|
self.rule_type = rule_type
|
||||||
self.initialize_rule()
|
self.initialize_rule()
|
||||||
|
|
||||||
|
self.previous = {}
|
||||||
|
|
||||||
def initialize_rule(self):
|
def initialize_rule(self):
|
||||||
if not self.rule_type == "comparison":
|
if not self.rule_type == "comparison":
|
||||||
self.rule_dict = (
|
self.rule_dict = (
|
||||||
@@ -281,17 +307,20 @@ class RuleBox(arcade.gui.UIBoxLayout):
|
|||||||
self.clear()
|
self.clear()
|
||||||
self.initialize_rule()
|
self.initialize_rule()
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return f"<{self.rule_type} ({self.rule}, {self.rule_num})>"
|
||||||
|
|
||||||
def get_connection_pos(rule_ui: RuleBox, idx):
|
def get_connection_pos(rule_ui: RuleBox, idx):
|
||||||
if rule_ui.rule_type == "comparison":
|
if rule_ui.rule_type == "comparison":
|
||||||
if idx == 1:
|
if idx == 0:
|
||||||
button = rule_ui.previous_button_1
|
button = rule_ui.previous_button_1
|
||||||
y = button.top
|
y = button.top
|
||||||
direction = 1
|
direction = 1
|
||||||
elif idx == 2:
|
elif idx == 1:
|
||||||
button = rule_ui.previous_button_2
|
button = rule_ui.previous_button_2
|
||||||
y = button.top
|
y = button.top
|
||||||
direction = 1
|
direction = 1
|
||||||
else:
|
elif idx == 2:
|
||||||
button = rule_ui.next_button
|
button = rule_ui.next_button
|
||||||
y = button.bottom
|
y = button.bottom
|
||||||
direction = -1
|
direction = -1
|
||||||
@@ -374,16 +403,49 @@ class RuleUI(arcade.gui.UIAnchorLayout):
|
|||||||
|
|
||||||
self.rule_space = self.add(arcade.gui.UIWidget(size_hint=(1, 1)))
|
self.rule_space = self.add(arcade.gui.UIWidget(size_hint=(1, 1)))
|
||||||
|
|
||||||
# self.create_connected_ruleset([("if", "x_position_compare"), ("do", "move_x")])
|
self.create_connected_ruleset([
|
||||||
|
("if", "x_position_compare"),
|
||||||
|
("if", "y_position_compare"),
|
||||||
|
("comparison", "and"),
|
||||||
|
("comparison", "and"),
|
||||||
|
("do", "move_x")],
|
||||||
|
[
|
||||||
|
[0, 2, 0, 0], # x_position_compare 0 -> first comparison 0
|
||||||
|
[1, 2, 0, 1], # y_position_compare 0 -> first comparison 1
|
||||||
|
[2, 3, 2, 0], # first comparison 2 (output) -> second comparison 0
|
||||||
|
[1, 3, 0, 1], # y_position_compare 0 -> -> second comparison 1
|
||||||
|
[3, 4, 2, 0] # second comparison 2 (output) -> do
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
self.trash_spritelist = arcade.SpriteList()
|
self.trash_spritelist = arcade.SpriteList()
|
||||||
self.trash_sprite = trash_bin
|
self.trash_sprite = trash_bin
|
||||||
self.trash_sprite.position = (self.window.width * 0.9, self.window.height * 0.2)
|
self.trash_sprite.position = (self.window.width * 0.9, self.window.height * 0.2)
|
||||||
self.trash_spritelist.append(self.trash_sprite)
|
self.trash_spritelist.append(self.trash_sprite)
|
||||||
|
|
||||||
|
def set_previous(self, rule_ui_a, rule_ui_b, to_connect_idx, idx):
|
||||||
|
if rule_ui_a.rule_type == "if" and to_connect_idx == 0:
|
||||||
|
if idx not in rule_ui_b.previous:
|
||||||
|
rule_ui_b.previous[idx] = []
|
||||||
|
rule_ui_b.previous[idx].append(rule_ui_a)
|
||||||
|
elif rule_ui_a.rule_type == "comparison":
|
||||||
|
if to_connect_idx == 2:
|
||||||
|
if idx not in rule_ui_b.previous:
|
||||||
|
rule_ui_b.previous[idx] = []
|
||||||
|
rule_ui_b.previous[idx].append(rule_ui_a)
|
||||||
|
else:
|
||||||
|
if to_connect_idx not in rule_ui_a.previous:
|
||||||
|
rule_ui_a.previous[to_connect_idx] = []
|
||||||
|
rule_ui_a.previous[to_connect_idx].append(rule_ui_b)
|
||||||
|
elif rule_ui_a.rule_type == "do" and idx == 0:
|
||||||
|
if idx not in rule_ui_a.previous:
|
||||||
|
rule_ui_a.previous[0] = []
|
||||||
|
rule_ui_a.previous[0].append(rule_ui_b)
|
||||||
|
|
||||||
def connection(self, rule_ui, allowed_next_connection, idx):
|
def connection(self, rule_ui, allowed_next_connection, idx):
|
||||||
if self.to_connect is not None:
|
if self.to_connect is not None:
|
||||||
old_rule_type = self.rule_ui[self.to_connect].rule_type
|
old_rule_ui = self.rule_ui[self.to_connect]
|
||||||
|
old_rule_type = old_rule_ui.rule_type
|
||||||
if (
|
if (
|
||||||
rule_ui.rule_type not in self.allowed_next_connection or
|
rule_ui.rule_type not in self.allowed_next_connection or
|
||||||
old_rule_type not in allowed_next_connection or
|
old_rule_type not in allowed_next_connection or
|
||||||
@@ -395,6 +457,9 @@ class RuleUI(arcade.gui.UIAnchorLayout):
|
|||||||
return
|
return
|
||||||
|
|
||||||
self.connections.append([self.to_connect, rule_ui.rule_num, self.to_connect_idx, idx])
|
self.connections.append([self.to_connect, rule_ui.rule_num, self.to_connect_idx, idx])
|
||||||
|
|
||||||
|
self.set_previous(old_rule_ui, rule_ui, self.to_connect_idx, idx)
|
||||||
|
|
||||||
self.allowed_next_connection = None
|
self.allowed_next_connection = None
|
||||||
self.to_connect = None
|
self.to_connect = None
|
||||||
self.to_connect_idx = None
|
self.to_connect_idx = None
|
||||||
@@ -412,7 +477,7 @@ class RuleUI(arcade.gui.UIAnchorLayout):
|
|||||||
self.to_connect = None
|
self.to_connect = None
|
||||||
|
|
||||||
for connection in self.connections:
|
for connection in self.connections:
|
||||||
if self.dragged_rule_ui.rule_num in connection:
|
if self.dragged_rule_ui.rule_num in connection[:2]:
|
||||||
self.connections.remove(connection)
|
self.connections.remove(connection)
|
||||||
|
|
||||||
self.rule_space.remove(self.dragged_rule_ui)
|
self.rule_space.remove(self.dragged_rule_ui)
|
||||||
@@ -424,12 +489,10 @@ class RuleUI(arcade.gui.UIAnchorLayout):
|
|||||||
else:
|
else:
|
||||||
self.dragged_rule_ui = rule_ui
|
self.dragged_rule_ui = rule_ui
|
||||||
|
|
||||||
def get_rulesets(self):
|
def get_rulesets(self): # return actions that can happen and the dependencies needed
|
||||||
if self.connections:
|
do_blocks = [rule_ui for rule_ui in self.rule_ui.values() if rule_ui.rule_type == "do"]
|
||||||
components = connected_component(self.connections, 0)
|
|
||||||
print(components)
|
|
||||||
|
|
||||||
return {}
|
return [backtrace(do_block) for do_block in do_blocks]
|
||||||
|
|
||||||
def generate_pos(self):
|
def generate_pos(self):
|
||||||
return random.randint(
|
return random.randint(
|
||||||
@@ -446,13 +509,13 @@ class RuleUI(arcade.gui.UIAnchorLayout):
|
|||||||
force or generate_rule(rule_type),
|
force or generate_rule(rule_type),
|
||||||
)
|
)
|
||||||
if rule_type == "if":
|
if rule_type == "if":
|
||||||
rule_box.next_button.on_click = lambda event, rule_box=rule_box: self.connection(rule_box, ["do", "comparison"], 1)
|
rule_box.next_button.on_click = lambda event, rule_box=rule_box: self.connection(rule_box, ["do", "comparison"], 0)
|
||||||
elif rule_type == "comparison":
|
elif rule_type == "comparison":
|
||||||
rule_box.previous_button_1.on_click = lambda event, rule_box=rule_box: self.connection(rule_box, ["if", "comparison"], 1)
|
rule_box.previous_button_1.on_click = lambda event, rule_box=rule_box: self.connection(rule_box, ["if", "comparison"], 0)
|
||||||
rule_box.previous_button_2.on_click = lambda event, rule_box=rule_box: self.connection(rule_box, ["if", "comparison"], 2)
|
rule_box.previous_button_2.on_click = lambda event, rule_box=rule_box: self.connection(rule_box, ["if", "comparison"], 1)
|
||||||
rule_box.next_button.on_click = lambda event, rule_box=rule_box: self.connection(rule_box, ["do", "comparison"], 3)
|
rule_box.next_button.on_click = lambda event, rule_box=rule_box: self.connection(rule_box, ["do", "comparison"], 2)
|
||||||
elif rule_type == "do":
|
elif rule_type == "do":
|
||||||
rule_box.previous_button.on_click = lambda event, rule_box=rule_box: self.connection(rule_box, ["if", "comparison"], 1)
|
rule_box.previous_button.on_click = lambda event, rule_box=rule_box: self.connection(rule_box, ["if", "comparison"], 0)
|
||||||
|
|
||||||
rule_box.drag_button.on_click = lambda event, rule_box=rule_box: self.drag(rule_box)
|
rule_box.drag_button.on_click = lambda event, rule_box=rule_box: self.drag(rule_box)
|
||||||
|
|
||||||
@@ -464,16 +527,14 @@ class RuleUI(arcade.gui.UIAnchorLayout):
|
|||||||
|
|
||||||
return rule_box
|
return rule_box
|
||||||
|
|
||||||
def create_connected_ruleset(self, rules):
|
def create_connected_ruleset(self, rules, connections):
|
||||||
previous = None
|
|
||||||
|
|
||||||
for rule_type, rule in rules:
|
for rule_type, rule in rules:
|
||||||
rule_box = self.add_rule(rule_type, rule)
|
self.add_rule(rule_type, rule)
|
||||||
|
|
||||||
if previous:
|
for connection in connections:
|
||||||
self.connections.append((previous.rule_num, rule_box.rule_num))
|
self.set_previous(self.rule_ui[connection[0]], self.rule_ui[connection[1]], connection[2], connection[3])
|
||||||
|
|
||||||
previous = rule_box
|
self.connections.extend(connections)
|
||||||
|
|
||||||
def draw(self):
|
def draw(self):
|
||||||
self.bezier_points = []
|
self.bezier_points = []
|
||||||
@@ -509,7 +570,7 @@ class RuleUI(arcade.gui.UIAnchorLayout):
|
|||||||
self.dragged_rule_ui.center_y += event.dy
|
self.dragged_rule_ui.center_y += event.dy
|
||||||
|
|
||||||
def on_update(self, dt):
|
def on_update(self, dt):
|
||||||
if self.dragged_rule_ui and self.trash_sprite.rect.point_in_rect((self.window.mouse.data["x"], self.window.mouse.data["y"])):
|
if self.dragged_rule_ui and self.trash_sprite.rect.intersection(self.dragged_rule_ui.rect):
|
||||||
if not self.trash_sprite._current_keyframe_index == self.trash_sprite.animation.num_frames - 1:
|
if not self.trash_sprite._current_keyframe_index == self.trash_sprite.animation.num_frames - 1:
|
||||||
self.trash_sprite.update_animation()
|
self.trash_sprite.update_animation()
|
||||||
else:
|
else:
|
||||||
|
|||||||
Reference in New Issue
Block a user