From 418b5ae28d82ff060f4e1cd61f6f65c4f28d027e Mon Sep 17 00:00:00 2001 From: gamerdonkey Date: Tue, 26 Aug 2025 23:17:20 -0500 Subject: [PATCH] Initial commit with a halfway working algorithm --- .gitignore | 1 + make_tree.py | 50 ++++++++++++++++++++++++++++ output_html.py | 73 +++++++++++++++++++++++++++++++++++++++++ test.py | 89 ++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 213 insertions(+) create mode 100644 .gitignore create mode 100644 make_tree.py create mode 100644 output_html.py create mode 100644 test.py diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..a6c57f5 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +*.json diff --git a/make_tree.py b/make_tree.py new file mode 100644 index 0000000..414f556 --- /dev/null +++ b/make_tree.py @@ -0,0 +1,50 @@ +from anytree import Node, RenderTree +from anytree.exporter import JsonExporter + + +def print_ingredients(): + for i, node in ingredients.items(): + print(f" {i}.) {node.name}") + + +ingredients = {} + +ingredient = "start" +i = 0 +while ingredient: + print_ingredients() + + ingredient = input("Add ingredient: ") + + if ingredient: + ingredients[i] = Node(ingredient) + i += 1 + +task = "start" +while task: + print_ingredients() + + task = input("Add task: ") + + if task: + needs = input("List needs (comma-separated): ") + + new_task = Node(task) + + ingredients[i] = new_task + i += 1 + + for e in [int(key.strip()) for key in needs.split(",")]: + ingredients.pop(e).parent = new_task + +for pre, _, node in RenderTree(new_task): + print(f"{pre}{node.name}") + +name = input("Recipe name: ") + +if name: + name = name.replace(" ", "_") + + with open(f"{name}.json", 'w') as f: + JsonExporter(indent=2).write(new_task, f) + diff --git a/output_html.py b/output_html.py new file mode 100644 index 0000000..0687ff3 --- /dev/null +++ b/output_html.py @@ -0,0 +1,73 @@ +from anytree import LevelOrderGroupIter +from anytree.importer import JsonImporter +from sys import argv + +if len(argv) < 2: + print(f"usage: {argv[0]} ") + exit() + +with open(argv[1], 'r') as f: + root = JsonImporter().read(f) + +rows = [] +leaves = [] + +for i in range(len(root.leaves)): + rows.append([]) + leaves.append({"name":"wrong"}) + +cur_row = 0 +for level in LevelOrderGroupIter(root): + cur_row = 0 + + for node in sorted(level, key=lambda x: x.size, reverse=True): + leaf_count = len(node.leaves) + if False: #node in root.leaves: + leaves[cur_row] = node + else: + rows[cur_row].append(f'{node.name}') + + cur_row += max(leaf_count, 1) + last_depth = node.depth + +print(leaves) + +for i, leaf in enumerate(leaves): + #rows[i].append(f"{leaf.name}") + rows[i].reverse() + + print("") + for cell in rows[i]: + print(f" {cell}") + print("") + + + +output_rows = [] +rows = [] + +for i in range(len(root.leaves)): + output_rows.append([]) + +def depth_first_search(node, rows, leaf_count): + + for child in sorted(node.children, key=lambda x: x.size, reverse=True): + leaf_count = depth_first_search(child, rows, leaf_count) + + if node.is_leaf: + cur_row = leaf_count + rows[cur_row].append(f'{node.name}') + leaf_count += 1 + else: + cur_row = leaf_count - len(node.leaves) + rows[cur_row].append(f'{node.name}') + + return leaf_count + +depth_first_search(root, output_rows, 0) + +for row in output_rows: + print("") + for cell in row: + print(f" {cell}") + print("") diff --git a/test.py b/test.py new file mode 100644 index 0000000..5181b02 --- /dev/null +++ b/test.py @@ -0,0 +1,89 @@ +from anytree import Node +from anytree import RenderTree +from anytree import LevelOrderIter, LevelOrderGroupIter +from anytree.search import find, findall + +cut = Node("cut") +cool = Node("cool", parent=cut) +press = Node("press into pan", parent=cool) +stir = Node("stir until coated", parent=press) +cereal = Node("crispy rice cereal (6 cups)", parent=stir) +melt_stir = Node("stir until melted", parent=stir) +marshmellows = Node("marshmellows (10 oz.)", parent=melt_stir) +melt = Node("melt", parent=melt_stir) +butter = Node("butter (3 tbsp)", parent=melt) + +output_lines = {} +leaves = [node for node in sorted(cut.leaves, key=lambda node: node.depth, reverse=True)] + +max_leaf_name_length = max([len(leaf.name) for leaf in leaves]) + +for leaf in leaves: + line = f"| {leaf.name.ljust(max_leaf_name_length)} |" + output_lines[leaf] = line + +max_depth = max([leaf.depth for leaf in leaves]) + +for cur_depth in range(max_depth-1, -1, -1): + max_name_length = max([len(node.name) for node in findall(cut, lambda node: node.depth == cur_depth and not node in cut.leaves)]) + max_name_length = max(max_name_length, 10) + for leaf in leaves: + task = find(cut, lambda node: node.depth == cur_depth and node in leaf.path) + if task and not task in cut.leaves: + output_lines[leaf] += f" {task.name.center(max_name_length)} |" + else: + output_lines[leaf] += f" {"".ljust(max_name_length)} " + +for key in output_lines.keys(): + print(output_lines[key]) + +print("") + +output_lines = [""] * len(cut.leaves) + +cur_line = 0 +last_depth = cut.depth +for node in LevelOrderIter(cut): + if node in cut.leaves: + continue + if last_depth != node.depth: + cur_line = 0 + + output_lines[cur_line] = f" {node.name} " + output_lines[cur_line] + cur_line += len(node.children) + 1 + last_depth = node.depth + +for line in output_lines: + print(line) + +rows = [] +leaves = [] + +for i in range(len(cut.leaves)): + rows.append([]) + leaves.append({"name":"wrong"}) + +cur_row = 0 +for level in LevelOrderGroupIter(cut): + cur_row = 0 + + for node in reversed(level): + leaf_count = len(node.leaves) + if node in cut.leaves: + leaves[cur_row] = node + else: + rows[cur_row].append(f'{node.name}') + + cur_row += max(leaf_count, 1) + last_depth = node.depth + +for i, leaf in enumerate(leaves): + rows[i].append(f"{leaf.name}") + rows[i].reverse() + + print("") + for cell in rows[i]: + print(cell) + print("") + +