Skip to content

Commit

Permalink
Day 8 Part 1. UNIQUE FOCUS: 280.
Browse files Browse the repository at this point in the history
  • Loading branch information
OrsoEric committed Dec 8, 2024
1 parent ebca438 commit d37ccbb
Show file tree
Hide file tree
Showing 5 changed files with 356 additions and 0 deletions.
192 changes: 192 additions & 0 deletions solutions/orso/day08/day08.py
Original file line number Diff line number Diff line change
@@ -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()
12 changes: 12 additions & 0 deletions solutions/orso/day08/day_8_example.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
............
........0...
.....0......
.......0....
....0.......
......A.....
............
............
........A...
.........A..
............
............
12 changes: 12 additions & 0 deletions solutions/orso/day08/day_8_example_solution.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
......#....#
...#....0...
....#0....#.
..#....0....
....0....#..
.#....A.....
...#........
#......#....
........A...
.........A..
..........#.
..........#.
90 changes: 90 additions & 0 deletions solutions/orso/day08/day_8_formulation.txt
Original file line number Diff line number Diff line change
@@ -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?
50 changes: 50 additions & 0 deletions solutions/orso/day08/day_8_map.txt
Original file line number Diff line number Diff line change
@@ -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..............

0 comments on commit d37ccbb

Please sign in to comment.