Coverage for Day2 / part2.py: 100%
26 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 : 2
10Ce script identifie et additionne tous les identifiants invalides dans
11les intervalles fournis. Un identifiant est considéré invalide s'il est
12entièrement composé d'un motif de chiffres répété au moins deux fois.
14Exemples :
15 - 12341234 → motif "1234" répété deux fois
16 - 1111111 → motif "1" répété sept fois
17 - 565656 → motif "56" répété trois fois
19Cette version utilise une méthode directe et fiable pour vérifier
20les motifs répétés.
22.. codeauthor:: Alexandre Condette <alexandre.condette@wanadoo.fr>
23"""
25# %% ========================================================================
26# Constantes
27N: int = 2
28# ===========================================================================
30# %% ========================================================================
31# Input data
32def get_input(day: int = 1, example: bool = False) -> list:
33 """
34 Lit le fichier d'input pour le jour donné.
36 :param day: numéro du jour AOC
37 :param example: si True, utilise le fichier example.txt sinon input.txt
38 :return: liste de lignes du fichier
39 :rtype: list
40 """
41 file = 'example.txt' if example else 'input.txt'
42 with open(f"./Day{day}/{file}", 'r', encoding='utf-8') as f:
43 return f.read()
45# ===========================================================================
47# %% ========================================================================
48# Résolution
49def is_repeated_pattern(x: int, n: int = 2) -> bool:
50 """
51 Vérifie si un entier `x` est composé d'un motif répété au moins `n` fois.
53 La logique :
54 - Convertir le nombre en chaîne.
55 - Tester toutes les longueurs possibles de motif (1 à L/n).
56 - Un motif est valide si :
57 * sa longueur divise exactement la longueur totale,
58 * il se répète assez de fois (au moins `n`),
59 * la concaténation du motif recrée le nombre.
61 :param x: entier à analyser
62 :param n: nombre minimal de répétitions requises
63 :return: True si `x` est invalide (motif répété), False sinon
64 :rtype: bool
65 """
66 L:str = len(str(x))
68 for k in range(1, L // n + 1):
69 if L % k != 0 :
70 continue
72 times = L // k
74 pattern = str(x)[:k]
75 if pattern * times == str(x):
76 return True
78 return False
80# ---------------------------------------------------------------------------
81def solve(data: list, n: int = 2) -> int:
82 """
83 Parcourt chaque intervalle "start-stop" listé dans l'input
84 et additionne tous les identifiants invalides selon la règle
85 des motifs répétés.
87 :param data: chaîne contenant les intervalles séparés par des virgules
88 :param n: nombre minimal de répétitions exigées pour être invalide
89 :return: somme de tous les identifiants invalides
90 :rtype: int
91 """
92 invalid_id: int = 0
93 all_ids = data.split(",")
95 for ids in all_ids:
96 start, stop = ids.split("-")
97 start = int(start)
98 stop = int(stop)
100 # Vérification brute-force (fiable pour la taille de l'énigme)
101 for x in range(start, stop + 1):
102 if is_repeated_pattern(x, n):
103 invalid_id += x
105 return invalid_id
107# ===========================================================================
109# %%
110if __name__ == "__main__":
111 RESULT = solve(get_input(2, False), N)
113 print("\n" + "═" * 60)
114 print(" 🔐 Advent of Code 2025 — Day 2 | Part 2".center(60))
115 print("═" * 60)
116 print(f"ID Invalides trouvés : \033[96m{RESULT}\033[0m")
117 print("═" * 60 + "\n")