-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathday10_part02.fs
183 lines (156 loc) · 6.21 KB
/
day10_part02.fs
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
module day10_part02
open System.IO
open AdventOfCode_2023.Modules
let ReadLines(path: string) =
File.ReadLines(__SOURCE_DIRECTORY__ + @"../../../" + path)
type Coord = {
row: int
col: int
}
let buildMap (input: string list) =
let array = Array2D.create (input.Length) (input.[0].Length) "."
let startPoint = Array.create 1 { row = 0; col = 0 }
for rowIdx in 0..input.Length - 1 do
for colIdx in 0..input.[0].Length - 1 do
let value = input.[rowIdx].[colIdx].ToString()
array[rowIdx, colIdx] <- value
if value = "S" then
startPoint.[0] <- { row = rowIdx; col = colIdx }
(startPoint.[0], array)
let getValidDirections (position: Coord) (map: string[,]) =
let directions = [[|-1; 0|]; [|1; 0|]; [|0; -1|]; [|0; 1|]]
let validDirections = directions |> List.filter (fun direction ->
let row = position.row + direction.[0]
let col = position.col + direction.[1]
row >= 0 && row < map.GetLength(0) && col >= 0 && col < map.GetLength(1) && map.[row, col] <> "."
)
validDirections
let getStartDirections (position: Coord) (map: string[,]) =
let availableDirections = getValidDirections position map
let startDirections = seq {
for d in availableDirections do
let posToCheck = { row = position.row + d.[0]; col = position.col + d.[1] }
let value = map.[posToCheck.row, posToCheck.col]
match d, value with
| [|-1; 0|], p when ["|"; "7"; "F"] |> List.contains p -> yield d
| [|0; -1|], p when ["-"; "L"; "F"] |> List.contains p -> yield d
| [|0; 1|], p when ["-"; "J"; "7"] |> List.contains p -> yield d
| [|1; 0|], p when ["|"; "J"; "L"] |> List.contains p -> yield d
| _ -> ()
}
startDirections |> List.ofSeq
let getConnections (position: Coord) (map: string[,])=
let value = map.[position.row, position.col]
let directions =
match value with
| "|" -> [[|-1; 0|]; [|1; 0|]]
| "-" -> [[|0; -1|]; [|0; 1|]]
| "L" -> [[|-1; 0|]; [|0; 1|]]
| "J" -> [[|-1; 0|]; [|0; -1|]]
| "7" -> [[|1; 0|]; [|0; -1|]]
| "F" -> [[|1; 0|]; [|0; 1|]]
| "S" -> getStartDirections position map
| _ -> []
let connections = seq {
for d in directions do
let posToCheck = { row = position.row + d.[0]; col = position.col + d.[1] }
yield { row = posToCheck.row; col = posToCheck.col }
}
connections |> Set.ofSeq
let printMap (map: string[,]) =
for row in 0..map.GetLength(0) - 1 do
for col in 0..map.GetLength(1) - 1 do
printf "%s" map.[row, col]
printfn ""
let rec numOfCuts (from: Coord) (target: Coord) (visited: Coord Set) (map: string[,]) (cuts: int) =
if from.col = target.col then
cuts
else
let next = { row = from.row; col = from.col + 1 }
if Set.contains next visited then
let point = map.[next.row, next.col]
// count all vertical | and then either: nonzero rule
// F and 7 for -><-
// J and L for <->
if point = "F" || point = "7" || point = "|" then
numOfCuts next target visited map (cuts + 1)
else
numOfCuts next target visited map cuts
else
numOfCuts next target visited map cuts
let rec travelMap (startPosition: Coord) (map: string[,]) (visited: Coord Set) =
let possiblePositions = getConnections startPosition map
let nextPosition = Set.difference possiblePositions visited
if nextPosition.IsEmpty then visited
else
let point = nextPosition.MinimumElement
let visited' = Set.add point visited
travelMap point map visited'
let replaceStartPoint (map: string[,]) (startPoint: Coord) =
let right = map.[startPoint.row, startPoint.col + 1]
let left = map.[startPoint.row, startPoint.col - 1]
let top = map.[startPoint.row - 1, startPoint.col]
let bottom = map.[startPoint.row + 1, startPoint.col]
match right, left, top, bottom with
// horizontal
| "-", "-", _, _ -> "-"
| "-", "L", _, _ -> "-"
| "J", "-", _, _ -> "-"
| "J", "L", _, _ -> "-"
// vertical
| _, _, "|", "|" -> "|"
| _, _, "|", "J" -> "|"
| _, _, "7", "|" -> "|"
| _, _, "7", "J" -> "|"
// top left
| _, "-", "|", _ -> "J"
| _, "-", "7", _ -> "J"
| _, "L", "|", _ -> "J"
| _, "L", "7", _ -> "J"
| _, "F", "|", _ -> "J"
| _, "F", "7", _ -> "J"
// top right
| "-", _, "|", _ -> "L"
| "-", _, "7", _ -> "L"
| "J", _, "|", _ -> "L"
| "J", _, "7", _ -> "L"
| "7", _, "|", _ -> "L"
| "7", _, "7", _ -> "L"
// bottom left
| _, "-", _, "|" -> "7"
| _, "-", _, "J" -> "7"
| _, "L", _, "|" -> "7"
| _, "L", _, "J" -> "7"
| _, "F", _, "|" -> "7"
| _, "F", _, "J" -> "7"
// bottom right
| "-", _, _, "|" -> "F"
| "-", _, _, "J" -> "F"
| "7", _, _, "|" -> "F"
| "7", _, _, "J" -> "F"
| "J", _, _, "|" -> "F"
| "J", _, _, "J" -> "F"
| _ -> "S"
let execute =
let path = "day10/day10_input.txt"
let input = LocalHelper.ReadLines path |> Seq.toList
let (startPoint, map) = buildMap input
let visited = Set.add(startPoint) Set.empty
let pipePath = travelMap startPoint map visited
let pipePath' = pipePath |> List.ofSeq
let top = pipePath' |> List.minBy (fun p -> p.row)
let bottom = pipePath' |> List.maxBy (fun p -> p.row)
let left = pipePath' |> List.minBy (fun p -> p.col)
let right = pipePath' |> List.maxBy (fun p -> p.col)
map.[startPoint.row, startPoint.col] <- replaceStartPoint map startPoint
let points =
seq {
for rowIdx in (top.row + 1)..(bottom.row - 1) do
for colIdx in (left.col + 1)..(right.col - 1) do
let pointToCheck = { row = rowIdx; col = colIdx }
if not (pipePath.Contains(pointToCheck)) then
let cuts = numOfCuts pointToCheck { row = rowIdx; col = right.col } pipePath map 0
if cuts % 2 = 1 then
yield { row = rowIdx; col = colIdx }
} |> List.ofSeq
points.Length