Advent of code

 8 décembre 2024 

  Resonant Collinearity : Prolonger des lignes de points entiers à partir de paires de deux points.
.......A....h.R.
   
.A.4z......y.p..
   
...............h
   
        
Code qui vérifie (pour rien avec les données de départ) aussi les points intermédiaires, via un PGDC des différences x et y des points.

Visuel sympa fait par jimsqueak sur Reddit.
  1. code.py
  2. pointsTraitsExemple.jpg
  3. points.jpg
  4. pointsTraits.jpg
  5. vizualisation08_by_reddituser_jimsqueak.mp4
import math

with open("input.txt", 'r', encoding='utf-8') as f:
    lines = [line[:-1] for line in f.readlines()]

W = len(lines[0])
H = len(lines)

nb = 0

antennas = {}
for y,line in enumerate(lines):
    for x,c in enumerate(line):
        if c == '.':
            continue
        if c not in antennas:
            antennas[c] = []
        antennas[c].append((x,y))


# Legacy of bad understanding of part 1
def thirds(x1, y1, x2, y2):
    if (x2-x1) % 3 != 0 or (y2-y1) % 3 != 0:
        return []
    else:
        return [ ( (2*x1+x2)//3, (2*y1+y2)//3 ),
                 ( (x1+2*x2)//3, (y1+2*y2)//3 )  ]
    
        
def get_antinode_left_part1(x1, y1, x2, y2):
    xn = 2*x2 - x1
    yn = 2*y2 - y1
    if 0 <= xn < W and 0 <= yn < H:
        return (xn,yn)
    else:
        return None


def get_antinodes_part2(x1, y1, x2, y2):
    r = [(x1,y1)]
    dx = x2 - x1   
    dy = y2 - y1
    d = math.gcd(dx, dy)     # d is always 1 with the data provided :-/
    px = dx // d
    py = dy // d
    for direction in (1, -1):
        x,y = x1,y1
        while 0 <= x < W and 0 <= y < H:
            r.append((x,y)) 
            x += px * direction
            y += py * direction
    return r
    

antinodes1 = set()
antinodes2 = set()
for places in antennas.values():
    for i in range(len(places) - 1):
        for j in range(i+1, len(places)):
            antinodes1.add(get_antinode_left_part1(*places[i], *places[j]))
            antinodes1.add(get_antinode_left_part1(*places[j], *places[i]))
            antinodes2.update(get_antinodes_part2(*places[i], *places[j]))
antinodes1.remove(None)

answer_part1 = len(antinodes1)
answer_part2 = len(antinodes2)

    
    

# Draw initial grid
print('\n'.join(lines), '\n')
# and now with antinodes of part 2
for y,line in enumerate(lines):
    for x,c in enumerate(line):
        if (x,y) in antinodes2:
            print('·' if c == '.' else '#', end='')
        else:
             print(' ' if c == '.' else c, end='')
    print()


print("Réponse partie 1 :", answer_part1)
print("Réponse partie 2 :", answer_part2)


# A little stat
all_letters = set()
for start, end in ('09', 'AZ', 'az'):
    all_letters.update(chr(val) for val in range(ord(start), ord(end)+1))
present = antennas.keys()
if len(present) > len(all_letters) // 2:
    message = 'all but '
    letters = all_letters.difference(set(present))
else:
    message = ''
    letters = present
print("Number of frequencies :", len(antennas), '(' + message + ''.join(sorted(letters)) + ')')   # Tous les chiffres et lettres prises, sauf BKMV et bkmv.