Advent of code

 14 décembre 2023 

  Parabolic Reflector Dish : Faire glisser des cailloux dans 4 directions successives
...O.....#O#...
   
#OO..O.##..#...
   
.###..O.#...O.#
   
O.O......OO.O#.
   
.#....#.O#...O.
   
.#.....O..#...#
   
        
  1. code.py
  2. code_optim_deplacer_cailloux.py
  3. code_oneLiners_lievreTortue.py
  4. code_numpy.py
from typing import MutableSequence

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

NOMBRE_CYCLES_A_FAIRE = 1000000000
CAILLOU = 'O'
VIDE = '.'

Grille = list[list[str]]


def calc_north_load(grille: Grille) -> int :
    """ Nord à gauche ! """
    nb = 0
    for ligne in grille:
        for c,v in enumerate(ligne):
            if v == CAILLOU:
                nb += len(ligne) - c
    return nb


def rotation_droite(grille: Grille) -> Grille:
    return [  [ grille[len(grille)-1-r][c]  for r in range(len(grille)) ]
              for c in range(len(grille[0]))  ]

def rotation_gauche(grille: Grille) -> Grille :
    return [  [ grille[r][len(grille[0])-1-c]  for r in range(len(grille)) ]
              for c in range(len(grille[0]))  ]


""" Plus agréable de déplacer les cailloux sur une même ligne
    Donc on décide que le nord est à gauche et on tourne la grille au départ en conséquence """

def grille_penchee_a_gauche(grille: Grille) -> Grille:
    return [ligne_penchee_a_gauche(ligne) for ligne in grille]

def ligne_penchee_a_gauche(ligne: MutableSequence[str]) -> MutableSequence[str]:
    for c in range(len(ligne)):
        if ligne[c] == CAILLOU:
            ligne[c] = VIDE
            for i in range(c,-1,-1):
                if i == 0 or not ligne[i-1] == VIDE:
                    ligne[i] = CAILLOU
                    break
    return ligne


def cycle(grille: Grille) -> Grille:
    for _ in range(4):
        grille = grille_penchee_a_gauche(grille)
        grille = rotation_droite(grille)
    return grille


grille: Grille = rotation_gauche([list(line) for line in lines]) # mettre le nord à gauche

solution_partie1 = calc_north_load(grille_penchee_a_gauche(grille))


anciennes_grilles: dict[str,int] = {}    # stocke les indices en fonction de la repr. str de la grille
for nb_deja_faits in range(1, NOMBRE_CYCLES_A_FAIRE+1):
    grille = cycle(grille)
    ancien_nb_deja_faits = anciennes_grilles.get(str(grille), False)
    if ancien_nb_deja_faits:
        longueur_boucle = nb_deja_faits - ancien_nb_deja_faits
        print(f"Trouvé boucle de longueur {longueur_boucle} après le {nb_deja_faits}e cycle.")
        # On réduit ce qui reste à faire modulo la longueur du cycle de réapparition
        reste_a_faire = (NOMBRE_CYCLES_A_FAIRE - nb_deja_faits) % longueur_boucle
        for _ in range(reste_a_faire):
            grille = cycle(grille)
        break
    else:
        anciennes_grilles[str(grille)] = nb_deja_faits
    
print("Réponse partie 1:", solution_partie1)
print("Réponse partie 2:", calc_north_load(grille))