Coverage for Day2 / part2.py: 100%

26 statements  

« 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 -*- 

3 

4""" 

5Advent Of Code 2025 

6=================== 

7Day : 2 

8Part : 2 

9 

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. 

13 

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 

18 

19Cette version utilise une méthode directe et fiable pour vérifier 

20les motifs répétés. 

21 

22.. codeauthor:: Alexandre Condette <alexandre.condette@wanadoo.fr> 

23""" 

24 

25# %% ======================================================================== 

26# Constantes 

27N: int = 2 

28# =========================================================================== 

29 

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é. 

35 

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() 

44 

45# =========================================================================== 

46 

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. 

52 

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. 

60 

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)) 

67 

68 for k in range(1, L // n + 1): 

69 if L % k != 0 : 

70 continue 

71 

72 times = L // k 

73 

74 pattern = str(x)[:k] 

75 if pattern * times == str(x): 

76 return True 

77 

78 return False 

79 

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. 

86 

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(",") 

94 

95 for ids in all_ids: 

96 start, stop = ids.split("-") 

97 start = int(start) 

98 stop = int(stop) 

99 

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 

104 

105 return invalid_id 

106 

107# =========================================================================== 

108 

109# %% 

110if __name__ == "__main__": 

111 RESULT = solve(get_input(2, False), N) 

112 

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") 

118