-
Notifications
You must be signed in to change notification settings - Fork 0
/
day03.fsx
129 lines (108 loc) · 3.57 KB
/
day03.fsx
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
open System
// --- Part A ---
type Position = {
X: int
Y: int
Content: string
IsNumber: bool
}
// converts the line of items into a sequence of numbers and symbols with their offset
let readLine (input: char list) =
let addToAcc (buffer: char list) (isNumber: bool) (index: int) acc =
if buffer.IsEmpty then
acc
else
{ X = (index - buffer.Length); IsNumber = isNumber; Content = (Seq.rev buffer |> String.Concat); Y = 0 } :: acc
let rec loop (working: char list) (buffer: char list) (index: int) acc =
match working with
| head :: tail ->
match head with
| '.' ->
loop tail [] (index + 1) (addToAcc buffer true index acc)
| c when Char.IsDigit c ->
loop tail (c :: buffer) (index + 1) acc
| c ->
loop tail [] (index + 1)
// for cases where symbol is directly after a number add buffer
(addToAcc buffer true index
(addToAcc [c] false (index + 1) acc))
| [] -> addToAcc buffer true index acc
loop input [] 0 []
let readPositions (input: string seq) =
Seq.map2 (fun (y: int) (line: string) ->
let ps = readLine (line |> List.ofSeq)
ps |> List.map (fun p -> { p with Y = y })
) [0..(Seq.length input)] input
|> List.concat
let example = [
"467..114..";
"...*......";
"..35..633.";
"......#...";
"617*......";
".....+.58.";
"..592.....";
"......755.";
"...$.*....";
".664.598.."
]
// check if points are present
readPositions example
// returns the x coordinate of where the position starts and ends
let numberDimensions position =
(position.X, position.X + (position.Content.Length - 1))
let allNearY y (positions: Position list) =
positions |> List.filter (fun p -> p.Y >= y - 1 && p.Y <= y + 1)
let allBetweenX (startX, endX) (positions: Position list) =
positions |> List.filter (fun p ->
let (sx, ex) = numberDimensions p
sx >= (startX - 1) && sx <= (endX + 1)
|| ex >= (startX - 1) && sx <= (endX + 1))
let hasSymbol (positions: Position list) =
positions |> List.filter (fun p -> not p.IsNumber)
let hasNumber (positions: Position list) =
positions |> List.filter (fun p -> p.IsNumber)
// looking for Content = 755, X = 6, Y = 7
readPositions example
|> allNearY 7
|> allBetweenX (5, 7)
|> hasSymbol
// finds all points near position
let near position points =
points
|> allNearY position.Y
|> allBetweenX (numberDimensions position)
let validPositions (lines: seq<string>) =
let positions = readPositions lines
let symbols = positions |> hasSymbol
positions
|> hasNumber
|> List.filter (fun p ->
(near p symbols) |> Seq.isEmpty |> not
)
let partA (lines: seq<string>) =
validPositions lines
|> Seq.map (fun (p: Position) -> p.Content |> int)
|> Seq.sum
let lines = (IO.File.ReadAllLines "day03inp.txt")
partA lines
// -- Part B ---
let validCogs (lines: seq<string>) =
let positions = readPositions lines
let numbers = positions |> hasNumber
positions
|> List.filter (fun p -> p.Content = "*")
|> List.map (fun p ->
(p, near p numbers)
)
|> List.map (fun (p, ns) ->
if ns.Length = 2 then
(ns[0].Content |> int) * (ns[1].Content |> int)
else
0)
|> List.sum
validCogs example
validCogs lines
// TODO:
// union type for position
// store dimensions in type