11# Advent of code Day 12
22# https://adventofcode.com/2025/day/12
33# 12/12/2025
4-
4+ # Failed
5+
6+ from copy import deepcopy
7+ from tqdm .auto import tqdm
8+ with open ("input.txt" ) as file :
9+ inp = list (
10+ map (
11+ lambda s : s .strip (),
12+ file .readlines ()
13+ )
14+ )
15+
16+
17+ class Region :
18+ def __init__ (self , row = None ):
19+ if row :
20+ row = row .split (": " )
21+ rows , cols = tuple (map (int , row [0 ].split ("x" )))
22+ self .needs = list (map (int , row [1 ].split (" " )))
23+ self .grid = [
24+ [0 for _ in range (cols )]
25+ for _ in range (rows )
26+ ]
27+
28+ def place (self , i , j , gift ):
29+ res = deepcopy (self )
30+ for i1 in range (3 ):
31+ for j1 in range (3 ):
32+ if gift [i1 ][j1 ]:
33+ if i + i1 >= len (res .grid ) or j + j1 >= len (res .grid [0 ]):
34+ return None
35+ if res .grid [i + i1 ][j + j1 ]: return None
36+ res .grid [i + i1 ][j + j1 ] = 1
37+ return res
38+
39+
40+ def isValid (self ):
41+ # Quick check
42+ totalCellsNeeded = 0
43+ for i , need in enumerate (self .needs ):
44+ if need :
45+ cells = sum (sum (row ) for row in gifts [i ].grid )
46+ totalCellsNeeded += cells * need
47+
48+ totalCellsAvailable = len (self .grid ) * len (self .grid [0 ])
49+ if totalCellsNeeded > totalCellsAvailable :
50+ return False
51+
52+ # Liste des gifts à placer
53+ toPlace = []
54+ for i , need in enumerate (self .needs ):
55+ toPlace .extend ([i ] * need )
56+
57+ maxTries = 100 # Limite absolue d'essais
58+ tries = [0 ]
59+
60+ def tryPlace (reg , placedCount ):
61+ tries [0 ] += 1
62+ if tries [0 ] > maxTries :
63+ return False
64+
65+ if placedCount == len (toPlace ):
66+ return True
67+
68+ giftIdx = toPlace [placedCount ]
69+
70+ for turn in gifts [giftIdx ].all ():
71+ for row in range (len (reg .grid )):
72+ for col in range (len (reg .grid [0 ])):
73+ placed = reg .place (row , col , turn )
74+ if placed and tryPlace (placed , placedCount + 1 ):
75+ return True
76+
77+ return False
78+
79+ result = tryPlace (self , 0 )
80+ print (f"Tried { tries [0 ]} combinations" )
81+ return result
82+
83+
84+ def __str__ (self ):
85+ return f"{ self .dims } -{ self .needs } "
86+
87+ def __repr__ (self ):
88+ return str (self )
89+
90+ class Gift :
91+ def __init__ (self , grid ):
92+ self .grid = grid
93+
94+ def flips (self ):
95+ grid = deepcopy (self .grid )
96+ horiz = [row [::- 1 ] for row in self .grid ]
97+ yield horiz
98+ vert = grid [::- 1 ]
99+ yield vert
100+
101+ def rots (self ):
102+ n = len (self .grid )
103+ current = self .grid
104+ for _ in range (3 ):
105+ res = self .empty ()
106+ for i in range (n ):
107+ for j in range (n ):
108+ res [j ][n - 1 - i ] = current [i ][j ]
109+ yield res
110+ current = res
111+
112+ def all (self ):
113+ yield self .grid
114+ yield from self .flips ()
115+ yield from self .rots ()
116+
117+ def empty (self ):
118+ return [
119+ [0 , 0 , 0 ],
120+ [0 , 0 , 0 ],
121+ [0 , 0 , 0 ]
122+ ]
123+
124+ gifts = []
125+ regions : list [Region ] = []
126+
127+ inp .append ("" )
128+ parts = []
129+
130+ l = 0
131+ for r in range (len (inp )):
132+ if not inp [r ]:
133+ parts .append (inp [l :r ])
134+ l = r + 1
135+
136+
137+ for part in parts :
138+ if ": " in part [0 ]:
139+ for region in part :
140+ regions .append (Region (region ))
141+ elif ":" in part [0 ]:
142+ gift = list (
143+ map (
144+ lambda s : list (map (int , s .replace ("#" , "1" ).replace ("." , "0" ))),
145+ part [1 :]
146+ )
147+ )
148+ gifts .append (Gift (gift ))
149+
150+
151+ res1 , res2 = 0 , 0
152+ for region in tqdm (regions ):
153+ res1 += region .isValid ()
154+
155+ print (res1 , res2 )
0 commit comments