1
+ '''
2
+ 2023 Advent of Code - Day 10 (https://adventofcode.com/2023/day/10)
3
+ Solution by Sav Bell (https://github.com/savbell)
4
+ Challenge: Solve every day in a single line of Python code.
5
+ See full progress at https://github.com/savbell/advent-of-code-one-liners
6
+ '''
7
+
8
+ from sys import setrecursionlimit
9
+
10
+ # Input files not included in repo per copyright & Eric Wastl's request.
11
+ # https://www.reddit.com/r/adventofcode/wiki/faqs/copyright/inputs/
12
+ # Replace with path to your personal input file if you would like to run the code.
13
+ input_file = '2023/day-10.txt'
14
+
15
+ # To match the format of input files for the Basilisk.
16
+ q = { 10 : open (input_file ).read ().strip () }
17
+
18
+
19
+ ######################### PART 1: MULTI-LINE SOLUTION #########################
20
+ grid = [[x for x in row ] for row in q [10 ].strip ().split ('\n ' )]
21
+ pipe_map = {'|' : [(0 , - 1 ), (0 , 1 )], '-' : [(1 , 0 ), (- 1 , 0 )],
22
+ 'L' : [(0 , - 1 ), (1 , 0 )], 'J' : [(0 , - 1 ), (- 1 , 0 )],
23
+ '7' : [(0 , 1 ), (- 1 , 0 )], 'F' : [(0 , 1 ), (1 , 0 )],
24
+ '.' : [], 'S' : [(0 , - 1 ), (0 , 1 ), (1 , 0 ), (- 1 , 0 )]}
25
+
26
+ def find_valid_moves (grid , pos , pipe_map , prev_dir = None ):
27
+ char = grid [pos [1 ]][pos [0 ]]
28
+ valid_directions = pipe_map [char ]
29
+ valid_moves = []
30
+ for d in valid_directions :
31
+ new_pos = (pos [0 ] + d [0 ], pos [1 ] + d [1 ])
32
+ new_char = grid [new_pos [1 ]][new_pos [0 ]]
33
+ if 0 <= new_pos [0 ] < len (grid [0 ]) and 0 <= new_pos [1 ] < len (grid ):
34
+ if d == (0 , - 1 ) and (0 , 1 ) in pipe_map [new_char ] and prev_dir != (0 , 1 ):
35
+ valid_moves .append (new_pos )
36
+ if d == (0 , 1 ) and (0 , - 1 ) in pipe_map [new_char ] and prev_dir != (0 , - 1 ):
37
+ valid_moves .append (new_pos )
38
+ if d == (1 , 0 ) and (- 1 , 0 ) in pipe_map [new_char ] and prev_dir != (- 1 , 0 ):
39
+ valid_moves .append (new_pos )
40
+ if d == (- 1 , 0 ) and (1 , 0 ) in pipe_map [new_char ] and prev_dir != (1 , 0 ):
41
+ valid_moves .append (new_pos )
42
+ return valid_moves
43
+
44
+ def find_start_char (grid , pos , pipe_map ):
45
+ valid_moves = find_valid_moves (grid , pos , pipe_map )
46
+ valid_directions = [(x [0 ]- pos [0 ], x [1 ]- pos [1 ]) for x in valid_moves ]
47
+ for k , v in pipe_map .items ():
48
+ if v == valid_directions :
49
+ return k
50
+
51
+ def solve (grid , pos , pipe_map , visited , prev_dir = None ):
52
+ move = find_valid_moves (grid , pos , pipe_map , prev_dir )[0 ]
53
+ if move == start_pos and len (visited ) > 0 :
54
+ return visited
55
+ visited .add (move )
56
+ return solve (grid , move , pipe_map , visited , (move [0 ]- pos [0 ], move [1 ]- pos [1 ]))
57
+
58
+ start_pos = [(x , y ) for y , row in enumerate (grid ) for x , char in enumerate (row ) if char == 'S' ][0 ]
59
+ grid [start_pos [1 ]][start_pos [0 ]] = find_start_char (grid , start_pos , pipe_map )
60
+
61
+ setrecursionlimit (30000 )
62
+ print ('Day 10 Part 1:' ,len (solve (grid , start_pos , pipe_map , { start_pos }))// 2 )
63
+
64
+ ########################## PART 1: ONE-LINE SOLUTION ##########################
65
+ print ('Day 10 Part 1:' ,(g := [[x for x in row ] for row in q [10 ].strip ().split ('\n ' )],p := {'|' :[(0 ,- 1 ),(0 ,1 )],'-' :[(1 ,0 ),(- 1 ,0 )],'L' :[(0 ,- 1 ),(1 ,0 )],'J' :[(0 ,- 1 ),(- 1 ,0 )],'7' :[(0 ,1 ),(- 1 ,0 )],'F' :[(0 ,1 ),(1 ,0 )],'.' :[],'S' :[(0 ,- 1 ),(0 ,1 ),(1 ,0 ),(- 1 ,0 )]},f := lambda g ,c ,p ,e = None :(r := g [c [1 ]][c [0 ]],s := p [r ],l := [],[(o := (c [0 ]+ d [0 ],c [1 ]+ d [1 ]),n := g [o [1 ]][o [0 ]],(0 <= o [0 ]< len (g [0 ]) and 0 <= o [1 ]< len (g )) and ((d == (0 ,- 1 ) and (0 ,1 ) in p [n ] and e != (0 ,1 )) and l .append (o ),(d == (0 ,1 ) and (0 ,- 1 ) in p [n ] and e != (0 ,- 1 )) and l .append (o ),(d == (1 ,0 ) and (- 1 ,0 ) in p [n ] and e != (- 1 ,0 )) and l .append (o ),(d == (- 1 ,0 ) and (1 ,0 ) in p [n ] and e != (1 ,0 )) and l .append (o ))) for d in s ]) and l ,w := lambda g ,pos ,p :[k for k ,v in p .items () if v == [(x [0 ]- pos [0 ],x [1 ]- pos [1 ]) for x in f (g ,pos ,p )]][0 ],y := lambda g ,c ,p ,v ,t = None :(v .add (u ) or y (g ,u ,p ,v ,(u [0 ]- c [0 ],u [1 ]- c [1 ]))) if (u := f (g ,c ,p ,t )[0 ])!= a or not v else v ,a := [(x ,y ) for y ,r in enumerate (g ) for x ,c in enumerate (r ) if c == 'S' ][0 ],g [a [1 ]].__setitem__ (a [0 ],w (g ,a ,p ))) and len (y (g ,a ,p ,{a }))// 2 )
66
+
67
+
68
+ ######################## PART 2: MULTI-LINE SOLUTION ##########################
69
+ grid = [[x for x in row ] for row in q [10 ].strip ().split ('\n ' )]
70
+ pipe_map = {'|' : [(0 , - 1 ), (0 , 1 )], '-' : [(1 , 0 ), (- 1 , 0 )],
71
+ 'L' : [(0 , - 1 ), (1 , 0 )], 'J' : [(0 , - 1 ), (- 1 , 0 )],
72
+ '7' : [(0 , 1 ), (- 1 , 0 )], 'F' : [(0 , 1 ), (1 , 0 )],
73
+ '.' : [], 'S' : [(0 , - 1 ), (0 , 1 ), (1 , 0 ), (- 1 , 0 )]}
74
+
75
+ def find_valid_moves (grid , pos , pipe_map , prev_dir = None ):
76
+ char = grid [pos [1 ]][pos [0 ]]
77
+ valid_directions = pipe_map [char ]
78
+ valid_moves = []
79
+ for d in valid_directions :
80
+ new_pos = (pos [0 ] + d [0 ], pos [1 ] + d [1 ])
81
+ new_char = grid [new_pos [1 ]][new_pos [0 ]]
82
+ if 0 <= new_pos [0 ] < len (grid [0 ]) and 0 <= new_pos [1 ] < len (grid ):
83
+ if d == (0 , - 1 ) and (0 , 1 ) in pipe_map [new_char ] and prev_dir != (0 , 1 ):
84
+ valid_moves .append (new_pos )
85
+ if d == (0 , 1 ) and (0 , - 1 ) in pipe_map [new_char ] and prev_dir != (0 , - 1 ):
86
+ valid_moves .append (new_pos )
87
+ if d == (1 , 0 ) and (- 1 , 0 ) in pipe_map [new_char ] and prev_dir != (- 1 , 0 ):
88
+ valid_moves .append (new_pos )
89
+ if d == (- 1 , 0 ) and (1 , 0 ) in pipe_map [new_char ] and prev_dir != (1 , 0 ):
90
+ valid_moves .append (new_pos )
91
+ return valid_moves
92
+
93
+ def find_start_char (grid , pos , pipe_map ):
94
+ valid_moves = find_valid_moves (grid , pos , pipe_map )
95
+ valid_directions = [(x [0 ]- pos [0 ], x [1 ]- pos [1 ]) for x in valid_moves ]
96
+ for k , v in pipe_map .items ():
97
+ if v == valid_directions :
98
+ return k
99
+
100
+ def solve (grid , pos , pipe_map , visited , prev_dir = None ):
101
+ move = find_valid_moves (grid , pos , pipe_map , prev_dir )[0 ]
102
+ if move == start_pos and len (visited ) > 0 :
103
+ return visited
104
+ visited .add (move )
105
+ return solve (grid , move , pipe_map , visited , (move [0 ]- pos [0 ], move [1 ]- pos [1 ]))
106
+
107
+ start_pos = [(x , y ) for y , row in enumerate (grid ) for x , char in enumerate (row ) if char == 'S' ][0 ]
108
+ grid [start_pos [1 ]][start_pos [0 ]] = find_start_char (grid , start_pos , pipe_map )
109
+ visited = solve (grid , start_pos , pipe_map , { start_pos })
110
+
111
+ contained = set ()
112
+ for i in range (len (grid )):
113
+ within = 0
114
+ for j in range (len (grid [0 ])):
115
+ if (j , i ) in visited :
116
+ if grid [i ][j ] in ['|' , 'L' , 'J' ]:
117
+ within = not within
118
+ elif within :
119
+ contained .add ((j , i ))
120
+
121
+ print ('Day 10 Part 2:' ,len (contained ))
122
+
123
+ ########################## PART 2: ONE-LINE SOLUTION ##########################
124
+ print ('Day 10 Part 2:' ,(g := [[x for x in row ] for row in q [10 ].strip ().split ('\n ' )],p := {'|' :[(0 ,- 1 ),(0 ,1 )],'-' :[(1 ,0 ),(- 1 ,0 )],'L' :[(0 ,- 1 ),(1 ,0 )],'J' :[(0 ,- 1 ),(- 1 ,0 )],'7' :[(0 ,1 ),(- 1 ,0 )],'F' :[(0 ,1 ),(1 ,0 )],'.' :[],'S' :[(0 ,- 1 ),(0 ,1 ),(1 ,0 ),(- 1 ,0 )]},f := lambda g ,c ,p ,e = None :(r := g [c [1 ]][c [0 ]],s := p [r ],l := [],[(o := (c [0 ]+ d [0 ],c [1 ]+ d [1 ]),n := g [o [1 ]][o [0 ]],(0 <= o [0 ]< len (g [0 ]) and 0 <= o [1 ]< len (g )) and ((d == (0 ,- 1 ) and (0 ,1 ) in p [n ] and e != (0 ,1 )) and l .append (o ),(d == (0 ,1 ) and (0 ,- 1 ) in p [n ] and e != (0 ,- 1 )) and l .append (o ),(d == (1 ,0 ) and (- 1 ,0 ) in p [n ] and e != (- 1 ,0 )) and l .append (o ),(d == (- 1 ,0 ) and (1 ,0 ) in p [n ] and e != (1 ,0 )) and l .append (o ))) for d in s ]) and l ,w := lambda g ,c ,p :[k for k ,v in p .items () if v == [(x [0 ]- c [0 ],x [1 ]- c [1 ]) for x in f (g ,c ,p )]][0 ],y := lambda g ,c ,p ,v ,t = None :(v .add (u ) or y (g ,u ,p ,v ,(u [0 ]- c [0 ],u [1 ]- c [1 ]))) if (u := f (g ,c ,p ,t )[0 ])!= a or not v else v ,a := [(x ,y ) for y ,r in enumerate (g ) for x ,c in enumerate (r ) if c == 'S' ][0 ],g [a [1 ]].__setitem__ (a [0 ],w (g ,a ,p )),(v := y (g ,a ,p ,{ a }),c := set (),[((w := 0 ),[((j ,i ) in v and (g [i ][j ] in '|LJ' and (w := not w )),(j ,i ) not in v and w and c .add ((j ,i ))) for j in range (len (g [0 ]))]) for i in range (len (g ))])) and len (c ))
0 commit comments