Coverage for Day2 / part1.py: 100%
24 statements
« prev ^ index » next coverage.py v7.13.0, created at 2025-12-12 09:47 +0000
« prev ^ index » next coverage.py v7.13.0, created at 2025-12-12 09:47 +0000
1#! /usr/bin/env python
2# -*- coding: utf-8 -*-
4"""
5Advent Of Code 2025
6===================
7Day : 2
8Part : 1
10Ce script identifie tous les identifiants "invalides" dans une liste
11de plages numériques. Un ID est invalide s'il est composé de deux fois
12la même séquence de chiffres (ex : 12 → 1212, 345 → 345345).
14.. codeauthor:: Alexandre Condette <alexandre.condette@wanadoo.fr>
15"""
17# %% ========================================================================
18# Imports
19from math import ceil, floor
20# ===========================================================================
22# %% ========================================================================
23# Input data
24def get_input(day: int = 1, example: bool = False) -> list:
25 """
26 Lit le fichier d'input pour le jour donné.
28 :param day: numéro du jour AOC
29 :param example: si True, utilise le fichier example.txt sinon input.txt
30 :return: liste de lignes du fichier
31 :rtype: list
32 """
33 file = 'example.txt' if example else 'input.txt'
34 with open(f"./Day{day}/{file}", 'r', encoding='utf-8') as f:
35 return f.read()
37# ===========================================================================
39# %% ========================================================================
40# Résolution
41def solve(data: list) -> int:
42 """
43 Calcule la somme de tous les identifiants invalides dans les plages spécifiées.
45 Une plage a la forme "A-B". Un ID est considéré invalide si sa
46 représentation est constituée de *deux fois* la même séquence de chiffres :
47 - 11 → invalide (1 répété deux fois)
48 - 1212 → invalide (12 répété deux fois)
49 - 9999 → invalide (99 répété deux fois)
50 - etc.
52 Optimisation :
53 - Plutôt que de tester chaque nombre : on détecte mathématiquement
54 toutes les valeurs ayant le pattern s * m où m = 10^k + 1.
56 :param data: Chaîne contenant plusieurs plages, séparées par des virgules.
57 :return: Somme de tous les identifiants invalides présents dans les plages.
58 :rtype: int
59 """
60 invalid_id: int = 0
61 all_ids = data.split(",")
63 for ids in all_ids:
64 # Extraction bornes [start, stop]
65 start, stop = ids.split('-')
66 start = int(start)
67 stop = int(stop) + 1 # inclure la borne supérieure
69 # Kmax = nombre max de digits pour les patterns divisés en deux (ex: 1234 → k=2)
70 Kmax = floor(len(str(stop)) / 2)
72 for k in range(1, Kmax + 1):
73 # m = 10^k + 1 → génère les nombres duplicables (ex : k=2 → 101 → s * 101 = ss)
74 m = 10 ** k + 1
76 # On cherche les valeurs s telles que s*m tombe dans [start, stop]
77 s_lo = ceil(start / m)
78 s_hi = floor(stop / m)
80 # Restreindre s aux nombres k-digits
81 s_lo = max(s_lo, 10 ** (k - 1))
82 s_hi = min(s_hi, 10 ** k - 1)
84 # Si la borne basse dépasse la borne haute → aucune valeur possible
85 if s_lo <= s_hi:
86 # Nombre de valeurs possibles
87 count = s_hi - s_lo + 1
88 # Somme des s du range
89 sum_s = (s_lo + s_hi) * count // 2
90 # Contribution total = m * somme(s)
91 invalid_id += m * sum_s
93 return invalid_id
95# ===========================================================================
97# %%
98if __name__ == "__main__":
99 RESULT = solve(get_input(2, False))
101 print("\n" + "═" * 60)
102 print(" 🔐 Advent of Code 2025 — Day 2 | Part 1".center(60))
103 print("═" * 60)
104 print(f"ID Invalides trouvés : \033[96m{RESULT}\033[0m")
105 print("═" * 60 + "\n")