-
Notifications
You must be signed in to change notification settings - Fork 0
/
Day03.fs
110 lines (82 loc) · 2.99 KB
/
Day03.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
module aoc23.Day03
open FSharp.Stats
open Xunit
open Swensen.Unquote
type Coordinate = int * int
module Coordinate =
let add (x1, y1) (x2, y2) = (x1 + x2, y1 + y2)
let allDirections =
let s = seq { -1 .. 1 }
Seq.allPairs s s |> Seq.filter ((<>) (0, 0)) |> Seq.toList
let adjacent (x, y) =
allDirections |> Seq.map (fun dir -> add dir (x, y)) |> Set.ofSeq
let tryGet (x, y) (lines: string array) =
lines |> Array.tryItem y |> Option.bind (fun line -> line |> Seq.tryItem x)
type Part =
{ Number: int; Points: (int * int) Set }
module Part =
let private getValue digits =
digits |> Seq.map snd |> Seq.toArray |> System.String |> int
let fromLine lineId line =
let folder item =
function
| [] -> [ [ item ] ]
| (pos, _) :: _ as ys :: xs when pos - 1 = fst item -> (item :: ys) :: xs
| list -> [ item ] :: list
let indexedDigits = line |> Seq.indexed |> Seq.filter (snd >> System.Char.IsDigit)
Seq.foldBack folder indexedDigits []
|> Seq.map (fun digits ->
{ Number = digits |> Seq.map snd |> Seq.toArray |> System.String |> int
Points = digits |> Seq.map fst |> Seq.map (fun x -> (x, lineId)) |> Set.ofSeq })
let fromLines lines =
lines |> Seq.mapi fromLine |> Seq.collect id
let part1 lines =
let parts = lines |> Part.fromLines
let partsNextToSymbols =
parts
|> Seq.filter (fun part ->
part.Points
|> Seq.exists (fun point ->
let adjacentChars =
Coordinate.adjacent point |> Seq.choose (fun adj -> tryGet adj lines)
adjacentChars
|> Seq.exists (fun char -> char <> '.' && not <| System.Char.IsDigit(char))))
partsNextToSymbols |> Seq.sumBy _.Number
let part2 lines =
let anchorCoordinates =
lines
|> Seq.mapi (fun y lines ->
lines
|> Seq.indexed
|> Seq.filter (snd >> ((=) '*'))
|> Seq.map (fun i -> (fst i, y)))
|> Seq.collect id
|> Seq.toArray
let parts = lines |> Part.fromLines |> Seq.toArray
let anchorAdjacentParts =
anchorCoordinates
|> Seq.map Coordinate.adjacent
|> Seq.map (fun adjacentCoordinates ->
parts
|> Array.filter (fun part -> Set.intersect part.Points adjacentCoordinates |> Set.count > 0))
anchorAdjacentParts
|> Seq.filter (fun parts -> parts.Length = 2)
|> Seq.map (Seq.map _.Number >> Seq.reduce (*))
|> Seq.sum
let run = runReadAllLines part1 part2
module Tests =
let example =
[| "467..114.."
"...*......"
"..35..633."
"......#..."
"617*......"
".....+.58."
"..592....."
"......755."
"...$.*...."
".664.598.." |]
[<Fact>]
let ``Test Part 1`` () = part1 example =! 4361
[<Fact>]
let ``Test Part 2`` () = part2 example =! 467835