1
+
2
+ def extract_data (input ):
3
+ """Extract"""
4
+ garden_map = []
5
+ with open (f"./input/{ input } " , 'r' ) as f :
6
+ lines = f .readlines ()
7
+ for line in lines :
8
+ garden_map .append (line .strip ())
9
+ return garden_map
10
+
11
+ def get_clusters (matrix ):
12
+ """Using a Depth-First search method."""
13
+ clusters = {}
14
+ visited = [[False for _ in range (len (matrix [0 ]))] for _ in range (len (matrix ))]
15
+ directions = [(0 ,1 ), (0 ,- 1 ), (1 ,0 ), (- 1 ,0 )]
16
+
17
+ def dfs (i ,j ,cluster ):
18
+ visited [i ][j ] = True
19
+ cluster .append ((i ,j ))
20
+ for di , dj in directions :
21
+ ni , nj = i + di , j + dj
22
+ if 0 <= ni < len (matrix ) and 0 <= nj < len (matrix [0 ]):
23
+ if not visited [ni ][nj ] and matrix [ni ][nj ] == matrix [i ][j ]:
24
+ dfs (ni , nj , cluster )
25
+
26
+ for i in range (len (matrix )):
27
+ for j in range (len (matrix [0 ])):
28
+ if not visited [i ][j ]:
29
+ cluster = []
30
+ dfs (i ,j ,cluster )
31
+ value = matrix [i ][j ]
32
+ if value not in clusters :
33
+ clusters [value ] = []
34
+ clusters [value ].append (cluster )
35
+ return clusters
36
+
37
+ def get_region_cost (region ):
38
+ directions = [(0 ,1 ), (0 ,- 1 ), (1 ,0 ), (- 1 ,0 )]
39
+ fences = 0
40
+ region_size = len (region )
41
+ for coord in region :
42
+ #print(coord)
43
+ for di , dj in directions :
44
+ prox_coord = (coord [0 ] + di , coord [1 ] + dj )
45
+ if prox_coord not in region :
46
+ fences += 1
47
+ return fences * region_size
48
+
49
+ def get_bulk_region_cost (region , matrix ):
50
+ """Use a Moore-Neighbor tracing algorithm to find boundaries?"""
51
+ region_size = len (region )
52
+
53
+ # Amount of corners should be equal to sides.
54
+ def find_corners (region ):
55
+ outer_corners = []
56
+ inner_corners = []
57
+ for item in region :
58
+ i , j = item [0 ], item [1 ]
59
+ N = (i - 1 ,j )
60
+ NW = (i - 1 ,j - 1 )
61
+ W = (i ,j - 1 )
62
+ SW = (i + 1 ,j - 1 )
63
+ S = (i + 1 ,j )
64
+ SE = (i + 1 ,j + 1 )
65
+ E = (i , j + 1 )
66
+ NE = (i - 1 , j + 1 )
67
+ if N not in region and NW not in region and W not in region :
68
+ outer_corners .append (NW )
69
+ if S not in region and SW not in region and W not in region :
70
+ outer_corners .append (SW )
71
+ if S not in region and SE not in region and E not in region :
72
+ outer_corners .append (SE )
73
+ if N not in region and NE not in region and E not in region :
74
+ outer_corners .append (NE )
75
+ if N in region and E in region and (NE not in region ):
76
+ inner_corners .append (item )
77
+ if S in region and E in region and (SE not in region ):
78
+ inner_corners .append (item )
79
+ if S in region and W in region and (SW not in region ):
80
+ inner_corners .append (item )
81
+ if N in region and W in region and (NW not in region ):
82
+ inner_corners .append (item )
83
+ return len (outer_corners ) + len (inner_corners )
84
+
85
+ corners = find_corners (region )
86
+
87
+ return corners * region_size
88
+
89
+
90
+
91
+ def part1 ():
92
+ garden_map = extract_data ("12" )
93
+ regions = get_clusters (garden_map )
94
+ score = 0
95
+ for region_type in regions :
96
+ for region in regions [region_type ]:
97
+ cost = get_region_cost (region )
98
+ score += cost
99
+
100
+ return score
101
+
102
+ def part2 ():
103
+ garden_map = extract_data ("12" )
104
+ regions = get_clusters (garden_map )
105
+ score = 0
106
+ for region_type in regions :
107
+ for region in regions [region_type ]:
108
+ cost = get_bulk_region_cost (region , garden_map )
109
+ score += cost
110
+
111
+ return score
112
+
113
+ if __name__ == "__main__" :
114
+ print (f"Answer part 1: { part1 ()} " )
115
+ print (f"Answer part 2: { part2 ()} " )
0 commit comments