diff --git a/solutions/orso/day08/day08.py b/solutions/orso/day08/day08.py new file mode 100644 index 0000000..77563e8 --- /dev/null +++ b/solutions/orso/day08/day08.py @@ -0,0 +1,192 @@ +#-------------------------------------------------------------------------------------------------------------------------------- +# INCLUDE +#-------------------------------------------------------------------------------------------------------------------------------- + +import logging + +from itertools import product, combinations + +import copy + +from typing import Generator, Dict, Tuple, List + +#-------------------------------------------------------------------------------------------------------------------------------- +# RULES +#-------------------------------------------------------------------------------------------------------------------------------- + +""" +There is a map +Within the map there are low case, high case and numbers +For each pair of the same symbol, two special location are generated. + d = vector distance between pair of same symbols + two focus # are generated at vector distance d from each of the symbols + #...A...A...# + #..A..A..# + Focus must be within the map +Calculate the focus generated by the total sum of all pairs of antennas of each symbol +If multiple symbols generate a focus in the same place, that count multiple times + +NO! multiple focus in the same place count as 1 +""" + + +#-------------------------------------------------------------------------------------------------------------------------------- +# ALGORITHM +#-------------------------------------------------------------------------------------------------------------------------------- + +""" +PART1 +I create a dictionary, where the key is the symbol (case sensitive) +the dictionary is associated with a list of coordinates XY that map all the same symbols +for each unique pair of those symbols, i generate a list of all the focus coordinates +I save that in a dictionary of focus, with one key per symbol +the solution is the total sum of all items in the focus dictionary +""" + +class Focus: + def __init__(self): + """ + Initialize the Focus class + """ + self.gn_width = -1 + self.gn_height = -1 + # store symbol as key, and item is a list of coordinates where that symbol appears + self.gd_symbol = dict() + #store coordinates, with the symbol associated with that coordinate + self.gd_coordinate_symbol = dict() + #for each symbol as key, store the focus as list of coordinates + self.gd_focus = dict() + #store coordinates, and the number of unique focus in that coordinate + self.gd_coordinate_focus = dict() + + def load_map_from_file(self, is_filename: str) -> bool: + """ + From a file, load a map. + For each symbol in a coordinate, add that coordinate to the dictionary as a list of coordinates with the symbol as key + """ + try: + with open(is_filename, 'r') as file: + lines = file.readlines() + self.gn_height = len(lines) + self.gn_width = max(len(line.strip()) for line in lines) + + for n_y, line in enumerate(lines): + for n_x, s_symbol in enumerate(line.strip()): + if s_symbol != '.': + tnn_coordinate = (n_x, n_y) + #fill symbol dictionary + if s_symbol not in self.gd_symbol: + self.gd_symbol[s_symbol] = [] + self.gd_symbol[s_symbol].append( tnn_coordinate ) + #fill coordinate dictionary + self.gd_coordinate_symbol[tnn_coordinate] = s_symbol + + except Exception as e: + print(f"Error loading map: {e}") + return False + logging.info(f"Map Size: Width: {self.gn_width} | Height: {self.gn_height}") + logging.info(f"Number of frequencies (symbols): {len(self.gd_symbol)}") + logging.info(f"Number of antennas: {len(self.gd_coordinate_symbol)}") + logging.info(f"Symbols: {self.gd_symbol}") + logging.info(f"Antennas: {self.gd_coordinate_symbol }") + + def show(self): + logging.info(f"Map Size: Width: {self.gn_width} | Height: {self.gn_height}") + s_line = "\n" + for n_y in range(self.gn_height): + for n_x in range(self.gn_width): + tnn_coordinate = (n_x, n_y) + if tnn_coordinate in self.gd_coordinate_symbol: + s_line += f"{self.gd_coordinate_symbol[tnn_coordinate]}" + else: + s_line += "." + s_line += '\n' + logging.debug(s_line) + + def sum_vector( self, tnn_origin : Tuple[int, int], tnn_vector : Tuple[int, int] ) -> Tuple[int, int]: + """ + sum two XY coordinates, + """ + return (tnn_origin[0]+tnn_vector[0], tnn_origin[1]+tnn_vector[1]) + + def sub_vector( self, tnn_origin : Tuple[int, int], tnn_vector : Tuple[int, int] ) -> Tuple[int, int]: + """ + fsub two XY coordinates + """ + return (tnn_origin[0]-tnn_vector[0], tnn_origin[1]-tnn_vector[1]) + + def is_oob( self, tnn_origin : Tuple[int, int] ) -> bool: + """ + if the coordinate is out of bound, return True + """ + if (tnn_origin[0] < 0): + return True #OOB + if (tnn_origin[1] < 0): + return True #OOB + if (tnn_origin[0] >= self.gn_width): + return True #OOB + if (tnn_origin[1] >= self.gn_height): + return True #OOB + return False + + def compute_focus(self): + """ + for each pair of symbols + create two focus in line with the symbols + at the distance between the symbols + """ + #for each symbol + for s_symbol in self.gd_symbol: + #create an empty list in the focus dictionary associated with the symbol + self.gd_focus[s_symbol] = list() + #get the list of coordinates where that symbol appear + ltnn_coordinates = self.gd_symbol[s_symbol] + #for each pair of coordinates + for tst_pair_of_coordinates in combinations( ltnn_coordinates, 2 ): + logging.debug(f"Pair: {tst_pair_of_coordinates}") + #compute distance between pair + tnn_vector_distance_ab = self.sub_vector( tst_pair_of_coordinates[1], tst_pair_of_coordinates[0]) + #compute coordinate of first focus + tnn_focus_a = self.sub_vector( tst_pair_of_coordinates[0], tnn_vector_distance_ab ) + tnn_focus_b = self.sum_vector( tst_pair_of_coordinates[1], tnn_vector_distance_ab ) + logging.debug(f"Distance: {tnn_vector_distance_ab} Focus A {tnn_focus_a} OOB:{self.is_oob(tnn_focus_a)} | Focus B {tnn_focus_b} OOB:{self.is_oob(tnn_focus_b)} ") + #if coordinates are within the map, add them to the focus dictionary + if self.is_oob(tnn_focus_a) == False: + self.gd_focus[s_symbol].append(tnn_focus_a) + #add focus to the coordinate of the focus + if tnn_focus_a not in self.gd_coordinate_focus: + self.gd_coordinate_focus[tnn_focus_a] = 1 + else: + self.gd_coordinate_focus[tnn_focus_a] += 1 + if self.is_oob(tnn_focus_b) == False: + self.gd_focus[s_symbol].append(tnn_focus_b) + #add focus to the coordinate of the focus + if tnn_focus_b not in self.gd_coordinate_focus: + self.gd_coordinate_focus[tnn_focus_b] = 1 + else: + self.gd_coordinate_focus[tnn_focus_b] += 1 + logging.info(f"Number of focus for symbol {s_symbol}: {len(self.gd_focus[s_symbol])}") + logging.info(f"Focus Coordinates: {self.gd_coordinate_focus}") + print(f"UNIQUE FOCUS: {len(self.gd_coordinate_focus)}") + +#-------------------------------------------------------------------------------------------------------------------------------- +# MAIN +#-------------------------------------------------------------------------------------------------------------------------------- + +# if interpreter has the intent of executing this file +if __name__ == "__main__": + logging.basicConfig( + filename='day08\day_8.log', + # Specify the log file name + level=logging.DEBUG, + # Set the level of debug to show + format='[%(asctime)s] %(levelname)s %(module)s:%(lineno)d > %(message)s ', + filemode='w' + ) + logging.info("Begin") + + cl_focus = Focus() + #cl_focus.load_map_from_file('day08\day_8_example.txt') + cl_focus.load_map_from_file('day08\day_8_map.txt') + cl_focus.show() + cl_focus.compute_focus() \ No newline at end of file diff --git a/solutions/orso/day08/day_8_example.txt b/solutions/orso/day08/day_8_example.txt new file mode 100644 index 0000000..de0f909 --- /dev/null +++ b/solutions/orso/day08/day_8_example.txt @@ -0,0 +1,12 @@ +............ +........0... +.....0...... +.......0.... +....0....... +......A..... +............ +............ +........A... +.........A.. +............ +............ \ No newline at end of file diff --git a/solutions/orso/day08/day_8_example_solution.txt b/solutions/orso/day08/day_8_example_solution.txt new file mode 100644 index 0000000..15ecd65 --- /dev/null +++ b/solutions/orso/day08/day_8_example_solution.txt @@ -0,0 +1,12 @@ +......#....# +...#....0... +....#0....#. +..#....0.... +....0....#.. +.#....A..... +...#........ +#......#.... +........A... +.........A.. +..........#. +..........#. \ No newline at end of file diff --git a/solutions/orso/day08/day_8_formulation.txt b/solutions/orso/day08/day_8_formulation.txt new file mode 100644 index 0000000..505b3d4 --- /dev/null +++ b/solutions/orso/day08/day_8_formulation.txt @@ -0,0 +1,90 @@ +--- Day 8: Resonant Collinearity --- + +You find yourselves on the roof of a top-secret Easter Bunny installation. +While The Historians do their thing, you take a look at the familiar huge antenna. +Much to your surprise, it seems to have been reconfigured to emit a signal that makes people 0.1% more likely +to buy Easter Bunny brand Imitation Mediocre Chocolate as a Christmas gift! Unthinkable! +Scanning across the city, you find that there are actually many such antennas. +Each antenna is tuned to a specific frequency indicated by a single lowercase letter, uppercase letter, or digit. +You create a map (your puzzle input) of these antennas. For example: + +............ +........0... +.....0...... +.......0.... +....0....... +......A..... +............ +............ +........A... +.........A.. +............ +............ + +The signal only applies its nefarious effect at specific antinodes based on the resonant frequencies of the antennas. +In particular, an antinode occurs at any point that is perfectly in line with two antennas of the same frequency +- but only when one of the antennas is twice as far away as the other. +This means that for any pair of antennas with the same frequency, there are two antinodes, one on either side of them. + +So, for these two antennas with frequency a, they create the two antinodes marked with #: + +.......... +...#...... +.......... +....a..... +.......... +.....a.... +.......... +......#... +.......... +.......... + +Adding a third antenna with the same frequency creates several more antinodes. +It would ideally add four antinodes, but two are off the right side of the map, so instead it adds only two: + +.......... +...#...... +#......... +....a..... +........a. +.....a.... +..#....... +......#... +.......... +.......... + +Antennas with different frequencies don't create antinodes; +A and a count as different frequencies. However, antinodes can occur at locations that contain antennas. +In this diagram, the lone antenna with frequency capital A creates no antinodes but has a lowercase-a-frequency antinode at its location: + +.......... +...#...... +#......... +....a..... +........a. +.....a.... +..#....... +......A... +.......... +.......... + +The first example has antennas with two different frequencies, +so the antinodes they create look like this, plus an antinode overlapping the topmost A-frequency antenna: + +......#....# +...#....0... +....#0....#. +..#....0.... +....0....#.. +.#....A..... +...#........ +#......#.... +........A... +.........A.. +..........#. +..........#. + +Because the topmost A-frequency antenna overlaps with a 0-frequency antinode, +there are 14 total unique locations that contain an antinode within the bounds of the map. + +Calculate the impact of the signal. How many unique locations within the bounds of the map contain an antinode? diff --git a/solutions/orso/day08/day_8_map.txt b/solutions/orso/day08/day_8_map.txt new file mode 100644 index 0000000..3f6d830 --- /dev/null +++ b/solutions/orso/day08/day_8_map.txt @@ -0,0 +1,50 @@ +....................................8............. +..................E............................... +.................................g................ +...........................................l...b.. +..C...........s..............8..........b......... +..................3..1........................b... +............N....3.....................1.....b.... +.....................N.....8....1..............2.. +..q....................................P.......... +......................N........................... +...........E.................................l.... +.............S.....c.............T..2v............ +.........w....E........q............L.....P.....l. +........w..............................a...V...... +...........t..................v..V................ +.....w.C............................V....4.....L.. +........................................I.n..T.... +.....E.5..C...8....3..q........................... +...............s..0...A........W...........a....T. +...............A................vPT...L..W..e.4... +...........Cw..................2.....G.p.....4.... +....S........q........s.............a............. +S.............c......e....................V....... +......5........................................... +....5............................................. +...........................I............g......... +...............c.........A........................ +.................s.............G.............etg.. +.........5...L.........f...v......W............... +............................0.W.....I........t.... +.................................................. +...................f...........Q.0................ +..............1m9.f..........0........3.........F. +..f...9................B.......................... +...........S...........................F......e... +........c.............n.....Q..................... +.....N...............B............g..7....t....... +..........B.........P.......G..................... +..m...........................Q................... +.............m.....................p...........F.. +.....M..B......Q..i.....................7.4....... +............M..................7.................. +...........n...................................... +................................p.....6.F.7....... +..........M...........p.........6................. +.M............i................................... +..............................G................... +..............li.......................6.......... +.....9.....................i...6.................. +.....n.............................9.............. \ No newline at end of file