diff --git a/2017/24/24.md b/2017/24/24.md index 09b66ed..400dbbd 100644 --- a/2017/24/24.md +++ b/2017/24/24.md @@ -59,7 +59,28 @@ a strength of `0+1 + 1+10 + 10+9 = 31`. *What is the strength of the strongest bridge you can make* with the components you have available? -To begin, [get your puzzle input](24/input). +Your puzzle answer was `2006`. + +The first half of this puzzle is complete! It provides one gold star: \* + +## \-\-- Part Two \-\-- {#part2} + +The bridge you\'ve built isn\'t long enough; you can\'t [jump the rest +of the way]{title="Who do you think you are, Mario?"}. + +In the example above, there are two longest bridges: + +- `0/2`\--`2/2`\--`2/3`\--`3/4` +- `0/2`\--`2/2`\--`2/3`\--`3/5` + +Of them, the one which uses the `3/5` component is stronger; its +strength is `0+2 + 2+2 + 2+3 + 3+5 = 19`. + +*What is the strength of the longest bridge you can make?* If you can +make multiple bridges of the longest length, pick the *strongest* one. Answer: +Although it hasn\'t changed, you can still [get your puzzle +input](24/input). + diff --git a/2017/24/solution.py b/2017/24/solution.py index 492a4cb..c3aa207 100644 --- a/2017/24/solution.py +++ b/2017/24/solution.py @@ -1,62 +1,47 @@ #!/bin/python3 import sys,re -from copy import deepcopy from pprint import pprint sys.path.insert(0, '../../') -from fred import list2int, lprint,get_re +from fred import list2int,get_re,nprint,lprint -input_f = 'test' +input_f = 'input' -part = 1 -log = True +part = 2 ######################################### # # # Part 1 # # # ######################################### -def find_match(comp:list,match:str,result:list): - i_match = get_re(r"^(\d+)\/(\d+)$",match) - #print(comp,match) - comp = [i for i in comp if i != match] - #print(comp,result) - for i in result: - try: - comp = [j for j in comp if j != i] - except: - print(i,'cant be removed from',j) - for j in comp: - j_match = get_re(r"^(\d+)\/(\d+)$",j) - #print(match,j) - #input() - if i_match.group(2) == j_match.group(1) or i_match.group(2) == j_match.group(2): - result.append(j) - find_match(comp[:],match,result[:]) - return result - -if part == 1: - components = [] +def parse_input(input_f): + list_of_components = [] with open(input_f) as file: for line in file: - components.append(line.rstrip()) + l = get_re(r"^(\d+)\/(\d+)$",line.rstrip()) + list_of_components.append([int(l.group(1)),int(l.group(2))]) + return list_of_components - lprint(components,log) - original_comp = deepcopy(components) - pairs = [] - result = [] - - for i in components[:]: - print(i) - if i[0] == '0': - result.append(find_match(original_comp,i,[i])) - - - pprint(result) - #nput() - #lprint(pairs,log) - +def make_bridge(components, last): + score = 0 + longest_bridge = [] + for cdx, component in enumerate(components): + if component[0] == last or component[1] == last: + if component[0] == last: + tmp = component[1] + else: + tmp = component[0] + x = component + make_bridge(components[:cdx]+components[cdx+1:],tmp) + if sum(x) > score: + score = sum(x) + longest_bridge = x + return longest_bridge +if part == 1: + components = parse_input(input_f) + #print(components) + bridge = make_bridge(components,0) + print(bridge) ######################################### @@ -64,5 +49,31 @@ if part == 1: # Part 2 # # # ######################################### + +def make_bridge_longest(components, last): + score = 0 + longest_bridge = [] + for cdx, component in enumerate(components): + if component[0] == last or component[1] == last: + if component[0] == last: + tmp = component[1] + else: + tmp = component[0] + x = component + make_bridge(components[:cdx]+components[cdx+1:],tmp) + if len(x) > len(longest_bridge) and sum(x) > score: + score = sum(x) + longest_bridge = x + + return longest_bridge + + if part == 2: - exit() + components = parse_input(input_f) + #print(components) + + bridge = make_bridge_longest(components,0) + + print(bridge) + #print(sum(bridge)) + + #print(sum(bridge)) diff --git a/2017/24/solution_old.py b/2017/24/solution_old.py new file mode 100644 index 0000000..9e6ff9c --- /dev/null +++ b/2017/24/solution_old.py @@ -0,0 +1,85 @@ +#!/bin/python3 +import sys,re +from copy import deepcopy +from pprint import pprint +sys.path.insert(0, '../../') +from fred import list2int, lprint,get_re + +input_f = 'test' + +part = 1 +log = True +######################################### +# # +# Part 1 # +# # +######################################### + +# def find_match(comp:list,match:str,result:list): +# #i_match = get_re(r"^(\d+)\/(\d+)$",match) +# #print(comp,match) +# #comp = [i for i in comp if i != match] +# #print(comp,result) +# #for i in result: +# # try: +# # comp = [j for j in comp if j != i] +# # except: +# # print(i,'cant be removed from',j) +# for j in comp: +# j_match = get_re(r"^(\d+)\/(\d+)$",j) +# #print(match,j) +# #input() +# if i_match.group(2) == j_match.group(1) or i_match.group(2) == j_match.group(2): +# result.append(j) +# find_match(comp[:],match,result[:]) +# return result + +# def find_match(components,match,results): +# #print(match,results) +# for j in components[:]: +# if match[1] == j[0] and j not in results: +# results.append(j) +# return find_match(components,j,results) +# return results + +def build_chain(chain:list, components:list): + last_componet = chain[len(chain)-1] + next_component = None + while len(components) > 0: + next_component = components.pop() + if ( + next_component[0] == last_componet[1] or + next_component[0] == last_componet[0] or + next_component[1] == last_componet[1] or + next_component[1] == last_componet[0] + ): + #print(next_component,components) + + chain.append(next_component) + build_chain(chain,deepcopy(components)) + return chain + + +if part == 1: + components = [] + with open(input_f) as file: + for line in file: + l = get_re(r"^(\d+)\/(\d+)$",line.rstrip()) + components.append(sorted([int(l.group(1)),int(l.group(2))])) + + pprint(components) + original_comp = deepcopy(components) + + for c in components[:]: + if c[0] == 0: + chain = build_chain([c],components) + print(chain) + + +######################################### +# # +# Part 2 # +# # +######################################### +if part == 2: + exit() diff --git a/2017/24/test.py b/2017/24/test.py index 1ba6bc0..70c3d6d 100644 --- a/2017/24/test.py +++ b/2017/24/test.py @@ -1,14 +1,33 @@ -from collections import defaultdict -import pprint -def build_graph(pairs): - graph = defaultdict(list) - for pair in pairs: - a, b = map(int, pair.split('/')) - graph[a].append(b) - graph[b].append(a) +def build_graph(node_list): + """ + Build a graph where: + - Each graph starts with a node containing `0`. + - Nodes are connected if they share a common value, except `0` cannot connect to another `0`. + """ + graph = {} + + # Parse nodes + parsed_nodes = [tuple(map(int, node.split('/'))) for node in node_list] + + # Build adjacency list + for node1 in parsed_nodes: + for node2 in parsed_nodes: + # Skip if both nodes contain `0` + if node1 == node2 or (0 in node1 and 0 in node2): + continue + + # Add edge if they share a common value + if node1[0] == node2[0] or node1[1] == node2[1] or node1[0] == node2[1] or node1[1] == node2[0]: + graph.setdefault(node1, []).append(node2) + graph.setdefault(node2, []).append(node1) + return graph -def find_all_paths(graph, start, visited=None, path=None): +def find_paths(graph, start, visited=None, path=None): + """ + Recursively find all paths starting from a given node. + Ensures that each node is visited only once per path. + """ if visited is None: visited = set() if path is None: @@ -17,42 +36,32 @@ def find_all_paths(graph, start, visited=None, path=None): visited.add(start) path.append(start) - paths = [list(path)] # Store the current path as a possible connection - - for neighbor in graph[start]: + # Print the current path + #print(" \--".join(f"{node[0]}/{node[1]}" for node in path)) + + # Explore neighbors + for neighbor in graph.get(start, []): if neighbor not in visited: - paths.extend(find_all_paths(graph, neighbor, visited.copy(), path.copy())) + find_paths(graph, neighbor, visited.copy(), path.copy()) + return path - return paths +def main(): + # Input list of nodes + nodes = [ + "0/2", "2/2", "2/3", "3/4", "3/5", "0/1", "10/1", "9/10" + ] -def count_connections(pairs): - graph = build_graph(pairs) - all_paths = [] + # Build the graph + graph = build_graph(nodes) + results = [] + # Find and print all paths for each subgraph starting with a `0` node + zero_nodes = [node for node in graph if 0 in node] + for start in zero_nodes: + print(f"Starting from {start[0]}/{start[1]}:") + tmp = find_paths(graph, start) + results.append(tmp) + + print(results) - for pair in pairs: - a, b = map(int, pair.split('/')) - paths_a = find_all_paths(graph, a) - paths_b = find_all_paths(graph, b) - - # Combine paths starting from both nodes in the pair - for path in paths_a: - if b in path: - all_paths.append(path) - - for path in paths_b: - if a in path: - all_paths.append(path) - - # Remove duplicate paths - unique_paths = {tuple(path) for path in all_paths} - return len(unique_paths), unique_paths - -# Example usage -pairs = ['0/2','2/2','2/3','3/4','3/5','0/1','10/1','9/10'] -connection_count, connections = count_connections(pairs) - -print(f"Number of connections: {connection_count}") -print("Connections:") -for connection in connections: - print(connection) -pprint(connections) +if __name__ == "__main__": + main() diff --git a/2017/24/test2.py b/2017/24/test2.py new file mode 100644 index 0000000..1a6bc2a --- /dev/null +++ b/2017/24/test2.py @@ -0,0 +1,36 @@ +import time +def solve(blocks): + new_bridges = [[block] for block in blocks if 0 in block] + strongest = 0 + longest_strength = 0 + while new_bridges: + bridges = new_bridges + new_bridges = [] + for bridge in bridges: + new_bridges.extend(list(extend(bridge, blocks))) + if new_bridges: + longest_strength = max(bridge_strength(bridge) for bridge in new_bridges) + strongest = max(strongest, longest_strength) + return strongest, longest_strength + +def bridge_strength(bridge): + return sum(map(sum, bridge)) + +def extend(bridge, blocks): + unused = list(filter(lambda b: b not in bridge and b[::-1] not in bridge, blocks)) + for block in unused: + if bridge[-1][1] == block[0]: + yield bridge + [block] + elif bridge[-1][1] == block[1]: + yield bridge + [block[::-1]] + +if __name__ == '__main__': + start = time.time() + block_list = [] + with open('input') as f: + for line in f: + block_list.append(tuple(map(int, line.split('/')))) + block_list = [(a, b) if a < b else (b, a) for a, b in block_list] + + print('Part 1: {}\nPart 2: {}'.format(*solve(block_list))) + print(f'Solved in {time.time() - start}') diff --git a/README.md b/README.md index 65da290..16a42de 100644 --- a/README.md +++ b/README.md @@ -62,7 +62,7 @@ .-----------------------------------------------. | o──────*──────┐o┬──────────────────┐┌───────┐ | 25 * - | o──*──┐└───┐o─┴─┘o────────┬─────o┌─┘├───o┌──┤ | 24 + | o──*──┐└───┐o─┴─┘o────────┬─────o┌─┘├───o┌──┤ | 24 * | ┌──┘o─┴────┘┌────────────*├──────┘o─┘┌───┘┌─┘ | 23 * | ├───┐┌──────┴o*──|(────┐┌┘└──────────┘o┬──┘o┐ | 22 ** | └┐o┐└┘*───────┘o┬─┬──┬┴┴┴┬───┬┴┴┴┴┬───┐└────┤ | 21 **