import json import networkx import matplotlib.pyplot as plt import math import requests raw_skill_tree = requests.get('https://raw.githubusercontent.com/poe-tool-dev/passive-skill-tree-json/master/3.21.0-atlas/SkillTree.json').text atlas_data = json.loads(raw_skill_tree) atlas_node_data = atlas_data['nodes'] atlas_graph = networkx.Graph() for node in atlas_node_data: node_1 = 0 if node == 'root' else int(node) for i in atlas_node_data[node]['in']: node_2 = 0 if i == 'root' else int(i) atlas_graph.add_edge(node_1, node_2) for i in atlas_node_data[node]['out']: node_2 = 0 if i == 'root' else int(i) atlas_graph.add_edge(node_1, node_2) mandated_nodes = [ 39896, 65464, 62028, 64740, 10530, 32784, 25301, # blocking 6530, 8171, 57512, 39180, # core + keystone 39276, 53175, 54874, 57163, # harvest 51834, 44249, 57784, 27002, 40700, 7382, # metamorph 33361, 55438, 55885, 45869, # betrayal ] # start() # set_init() # step() # find_closest() # find_alternate_paths() # adjust_and_compute_shortest() # if multiple_skip() # allocate() # remove_from_list() def find_closest(curr_node): global mandated_nodes, atlas_graph shortest = -1 next_node = None for node in mandated_nodes: path_len = networkx.shortest_path_length(atlas_graph, curr_node, node) if shortest == -1 or shortest > path_len: shortest = path_len next_node = node #elif shortest == path_len: # return -1 return next_node def find_all_shortest(curr_node, next_node): global mandated_nodes, atlas_graph, node_set paths = networkx.all_shortest_paths(atlas_graph, curr_node, next_node) shortest = -1 next_path = None for path in paths: path_len = len(path) - sum([node in node_set for node in path]) if shortest == - 1 or shortest > path_len: shortest = path_len next_path = path #elif shortest == path_len: # return -1 return next_path curr_node = 0 node_set = [] node_jail = [] release = False while len(mandated_nodes) + len(node_jail) != 0: if release: mandated_nodes += node_jail node_jail = [] if not release: release = True next_node = find_closest(curr_node) next_path = find_all_shortest(curr_node, next_node) if next_path == -1: node_jail.append(next_node) del mandated_nodes[mandated_nodes.index(next_node)] release = False else: for node in next_path: if node not in node_set: node_set.append(node) curr_node = next_node del mandated_nodes[mandated_nodes.index(curr_node)] for node in node_set: if node == 0: continue print(f'{atlas_node_data[str(node)]["skill"]}\t{atlas_node_data[str(node)].get("name")}') def draw_atlas_graph(): global atlas_data, node_set pos = {} for node in atlas_node_data: if node != 'root': group = atlas_node_data[node]['group'] orbit = atlas_node_data[node]['orbit'] orb_idx = atlas_node_data[node]['orbitIndex'] base_pos = [atlas_data['groups'][str(group)]['x'], atlas_data['groups'][str(group)]['y']] orbit_r = atlas_data['constants']['orbitRadii'][orbit] orbit_n = atlas_data['constants']['skillsPerOrbit'][orbit] angle = orb_idx / orbit_n * 2 * math.pi full_pos = [base_pos[0] + orbit_r * math.sin(angle), -1*(base_pos[1] - orbit_r * math.cos(angle))] pos[int(node)] = full_pos pos[0] = [0, -100] nodes = atlas_graph.nodes() color = [('#0000a0' if node in node_set else '#000000') for node in nodes] sizes = [(40 if node in node_set else 20) for node in nodes] networkx.draw(atlas_graph, pos=pos, node_color=color, node_size = sizes) plt.show() draw_atlas_graph() print(len(node_set) - 2)