-
Notifications
You must be signed in to change notification settings - Fork 0
/
day10.nim
211 lines (183 loc) · 5.51 KB
/
day10.nim
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
import std/strutils
import options
import std/enumerate
import lib
type
Direction = enum
UP
RIGHT
DOWN
LEFT
TileType = enum
LOOP = "L"
OUTSIDE = "O"
INSIDE = "I"
Pipe = tuple[c1: Direction, c2: Direction]
Piece = Option[Pipe]
PieceGrid = seq[seq[Piece]]
LoopGrid = seq[seq[TileType]]
CharGrid = seq[seq[char]]
Position = tuple[x: int, y: int]
func opposite(direction: Direction): Direction =
case direction:
of UP:
DOWN
of DOWN:
UP
of LEFT:
RIGHT
of RIGHT:
LEFT
proc walk(direction: Direction, pos: Position): Position =
case direction:
of UP:
result = (x: pos.x, y: pos.y - 1)
of DOWN:
result = (x: pos.x, y: pos.y + 1)
of LEFT:
result = (x: pos.x - 1, y: pos.y)
of RIGHT:
result = (x: pos.x + 1, y: pos.y)
# let input = strip readFile "inputs/day10-example.txt"
let input = strip readFile "inputs/day10.txt"
var grid: PieceGrid = @[]
var char_grid: CharGrid = @[]
var start: Position = (x: 0, y: 0)
for (lidx, line) in enumerate(input.split("\n")):
var row: seq[Piece] = @[]
var char_row: seq[char] = @[]
for (cidx, c) in enumerate(line):
char_row.add c
case c:
of 'F':
row.add some (c1: DOWN, c2: RIGHT)
of '7':
row.add some (c1: DOWN, c2: LEFT)
of 'L':
row.add some (c1: UP, c2: RIGHT)
of 'J':
row.add some (c1: UP, c2: LEFT)
of '-':
row.add some (c1: LEFT, c2: RIGHT)
of '|':
row.add some (c1: UP, c2: DOWN)
of 'S':
row.add none Pipe
start = (x: cidx, y: lidx)
else:
row.add none Pipe
grid.add row
char_grid.add char_row
func valid_connection(pipe: Pipe, direction: Direction): bool =
case direction:
of UP:
pipe.c1 == DOWN or pipe.c2 == DOWN
of DOWN:
pipe.c1 == UP or pipe.c2 == UP
of LEFT:
pipe.c1 == RIGHT or pipe.c2 == RIGHT
of RIGHT:
pipe.c1 == LEFT or pipe.c2 == LEFT
# infer what type of pipe the start is
# var startPipe: Pipe
# in all 4 adjacent cells, add a pipe
var connections: seq[Direction] = @[]
for (pos, direction) in [
((start.x, start.y - 1), UP),
((start.x + 1, start.y), RIGHT),
((start.x, start.y + 1), DOWN),
((start.x - 1, start.y), LEFT)
]:
let (x, y) = pos
if x < 0 or y < 0 or y >= grid.len or x >= grid[y].len:
continue
let piece = grid[y][x]
if isSome piece:
if valid_connection(piece.get, direction):
connections.add direction
else:
echo "no piece"
continue
grid[start.y][start.x] = some (c1: connections[0], c2: connections[1])
# for row in grid:
# echo row
# echo ""
var steps: seq[Direction] = @[]
var pos = start
var ended = false
var came_from: Option[Direction] = none Direction
var loop_grid: LoopGrid = newSeq[seq[TileType]](grid.len)
for r in 0 ..< grid.len:
loop_grid[r] = newSeq[TileType](grid[r].len)
for c in 0 ..< grid[r].len:
loop_grid[r][c] = OUTSIDE
# echo loop_grid
loop_grid[start.y][start.x] = LOOP
while not ended:
let piece = grid[pos.y][pos.x]
if pos.x == start.x and pos.y == start.y and isSome came_from:
ended = true
break
let pipe = get piece
let next_direction = if isNone came_from:
pipe.c1 else:
if pipe.c1 == came_from.get:
pipe.c2
else: pipe.c1
came_from = some opposite next_direction
pos = walk(next_direction, pos)
loop_grid[pos.y][pos.x] = LOOP
steps.add next_direction
func is_7(pipe: Pipe): bool =
return pipe.c1 == DOWN and pipe.c2 == LEFT or
pipe.c1 == LEFT and pipe.c2 == DOWN
func is_J(pipe: Pipe): bool =
return pipe.c1 == UP and pipe.c2 == LEFT or
pipe.c1 == LEFT and pipe.c2 == UP
func is_F(pipe: Pipe): bool =
return pipe.c1 == DOWN and pipe.c2 == RIGHT or
pipe.c1 == RIGHT and pipe.c2 == DOWN
func is_L(pipe: Pipe): bool =
return pipe.c1 == UP and pipe.c2 == RIGHT or
pipe.c1 == RIGHT and pipe.c2 == UP
func is_vertical(pipe: Pipe): bool =
return pipe.c1 == UP and pipe.c2 == DOWN or
pipe.c1 == DOWN and pipe.c2 == UP
proc check_enclosed(pos: Position): bool =
var left_amount = 0
var prev = ""
var moving_pos = pos
while true:
moving_pos = walk(LEFT, moving_pos)
if moving_pos.x < 0 or moving_pos.y < 0 or moving_pos.y > loop_grid.high or moving_pos.x > loop_grid[moving_pos.y].high:
break
if loop_grid[moving_pos.y][moving_pos.x] == LOOP:
let piece = grid[moving_pos.y][moving_pos.x]
let pipe = get piece
if is_vertical(pipe):
# echo "vertical"
left_amount += 1
elif is_7(pipe):
prev = "7"
elif is_J(pipe):
prev = "J"
elif is_F(pipe):
if prev == "J":
left_amount += 1
prev = "F"
elif is_L(pipe):
if prev == "7":
left_amount += 1
prev = "L"
return odd left_amount
var enclosed_area = 0
for r in 0 ..< loop_grid.len:
for c in 0 ..< loop_grid[r].len:
if loop_grid[r][c] == OUTSIDE:
if check_enclosed((x: c, y: r)):
loop_grid[r][c] = INSIDE
enclosed_area += 1
for row in loop_grid:
echo row.join("")
echo int steps.len / 2
echo enclosed_area