import networkx as nx # the python package that allows you to get longest paths import numpy as np # needed for some of the basic caluclations def generated_board(num_layers): """create the points for a board with given number of layers""" start_point = [[500, 550]] height_increases = 75 width_increases = 120 board = [start_point] for i in range(num_layers): num_points_in_layer = i + 2 layer = [ [ start_point[0][0] - (i + 1) * (width_increases / 2) + pt * width_increases, start_point[0][1] - (i + 1) * height_increases ] for pt in range(num_points_in_layer) ] board.append(layer) return board def generate_board_weights(board, weight_choice, num_layers): """given a board for a given number of layers assign random weights. These are controlled using a random seed""" total_weights = sum([i * 2 for i in range(1, num_layers + 1)]) # gerenate weights to use for board rng = np.random.default_rng(weight_choice) random_edge_values = rng.integers(1, 20, total_weights) weight_pairs = [[random_edge_values[i], random_edge_values[i + 1]] for i in range(0, len(random_edge_values), 2)] start = 0 end = 0 edges = [] for diff in range(num_layers): start += diff end += diff + 1 edges.append(weight_pairs[start:end]) graph_edges = [] for rowIndex, points in enumerate(board): for pointIndex, point_cords in enumerate(points): if rowIndex != len(board) - 1: point_line_start = board[rowIndex][pointIndex] point_left_line_end = board[rowIndex + 1][pointIndex] point_right_line_end = board[rowIndex + 1][pointIndex + 1] edge_left = edges[rowIndex][pointIndex][0] edge_right = edges[rowIndex][pointIndex][1] graph_edges.append((str(point_line_start), str(point_left_line_end), edge_left)) graph_edges.append((str(point_line_start), str(point_right_line_end), edge_right)) return edges, graph_edges def _get_myopic_path(board, weights): myopic_path = [str(board[0][0])] point_moved_to = 0 for layer, weights_at_level in enumerate(weights): max_value = max(weights_at_level[point_moved_to]) max_index = weights_at_level[point_moved_to].index(max_value) point_moved_to = max_index + point_moved_to myopic_path.append(str(board[layer + 1][point_moved_to])) return myopic_path def get_longest_path(graph_edges, board): """ setting up the graph (i.e. maze) using networkx. Then using networkx inbuilt functionlity we can get the longest path """ # # create a blank graph using networkx graph = nx.DiGraph() # # adds the info on edges and nodes as in the format defined above i.e. a list of # # nodes that need to be connected and how much weight each connection should be # # assinged graph.add_weighted_edges_from(graph_edges) # will tell networkx to get all possible paths given the start point and ending at # one of the end points and then look at the scores. start_point = str(board[0][0]) # a list of the end points of the maze target = [str(b) for b in board[-1]] all_simple_paths = list(nx.all_simple_paths(graph, source=start_point, target=target)) scores = [_get_score_from_path(path, graph_edges) for path in all_simple_paths] index_of_max_score = scores.index(max(scores)) return all_simple_paths[index_of_max_score], scores[index_of_max_score] def _get_score_from_path(path, graph_edges): # first generate the links in the path as expected as input to networkx (see output of cell) # but this should look like the 'graph_edges' list links_in_longest_path = [ (path[i], path[i + 1]) for i in range(len(path) - 1) ] # now calculate the score for the longest path # initialise score to 0 total_score_for_longest_path = 0 # loop through all the links in 'graph_edges' and see # which ones are in the longest path links. If they are in # the longest path add that link's score to the toal for edge in graph_edges: if edge[:2] in links_in_longest_path: total_score_for_longest_path += edge[2] return total_score_for_longest_path def get_board_weights_longest_path_myopic_path(weight_choice=1, num_layers=4): """ worker funtion that generates a board with num layers, assigns the weights at random to the board then calculates the length of the longest path and the myopic path. """ board = generated_board(num_layers) edges, graph_edges = generate_board_weights(board=board, weight_choice=weight_choice, num_layers=num_layers) # Note that the graph edges must be in the format: # [(name of start node (string), name of end node (string), value of the line connntecting them (integer))] # i.e. MUST BE IN FORMAT LIST OF TUPLES WITH NAME OF NODE 1, NAME of NODE 2, VALUE THAT CONNECTS THEM # longest_path = get_longest_path(graph_edges, board) # longest_path_score = _get_score_from_path(longest_path, graph_edges) longest_path, longest_path_score = get_longest_path(graph_edges, board) # now get the mypoic path score myopic_path = _get_myopic_path(board, edges) myopic_path_score = _get_score_from_path(myopic_path, graph_edges) # now we need to set up some function to count the total weights of the longest # path print(f"The total score for the longest path is: {longest_path_score} using {longest_path}") print(' ') print(f"The total score for the myopic path is: {myopic_path_score} using {myopic_path}") return board, edges, longest_path_score, myopic_path_score