-
Notifications
You must be signed in to change notification settings - Fork 0
/
day22_part02.fs
110 lines (94 loc) · 3.88 KB
/
day22_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
module day22_part02
open System.Collections.Generic
open AdventOfCode_2023.Modules
type BrickSize = { start: int; finish: int }
type Brick =
{
xSize: BrickSize
ySize: BrickSize
zSize: BrickSize
}
member this.Top = this.zSize.finish
member this.Bottom = this.zSize.start
type Holders = {
blocksToHold : Dictionary<Brick, HashSet<Brick>>
blocksThatHoldMe : Dictionary<Brick, HashSet<Brick>>
}
let collides (a: BrickSize) (b: BrickSize) =
a.start <= b.finish && b.start <= a.finish
let collidesInXandY (a: Brick) (b: Brick) =
collides a.xSize b.xSize && collides a.ySize b.ySize
let startFall (bricks: Brick[]) =
let sortedbricks = bricks |> Array.sortBy (fun b -> b.Bottom)
for idx in 0..sortedbricks.Length - 1 do
let mutable minBottom = 1
for jdx in 0..idx - 1 do
if collidesInXandY sortedbricks.[idx] sortedbricks.[jdx] then
minBottom <- System.Math.Max(minBottom, sortedbricks.[jdx].Top + 1)
let fall = sortedbricks.[idx].Bottom - minBottom
sortedbricks.[idx] <- {
sortedbricks.[idx]
with zSize = {
start = sortedbricks.[idx].Bottom - fall;
finish = sortedbricks.[idx].Top - fall
}
}
sortedbricks
let holders (bricks: Brick[]) =
let blocksToHold = Dictionary<Brick, HashSet<Brick>>()
let blocksThatHoldMe = Dictionary<Brick, HashSet<Brick>>()
for b in bricks do
blocksToHold.Add(b, HashSet<Brick>())
blocksThatHoldMe.Add(b, HashSet<Brick>())
for idx in 0..bricks.Length - 1 do
for jdx in 0..bricks.Length - 1 do
let zs = bricks.[jdx].Bottom = (1 + bricks.[idx].Top)
if zs && collidesInXandY bricks.[idx] bricks.[jdx] then
blocksThatHoldMe.[bricks.[jdx]].Add(bricks.[idx]) |> ignore
blocksToHold.[bricks.[idx]].Add(bricks.[jdx]) |> ignore
{ blocksToHold = blocksToHold; blocksThatHoldMe = blocksThatHoldMe }
let explode(bricks: Brick[]) =
let fallenBricks = startFall bricks
let holders = holders fallenBricks
let blocksFalling (holders: Holders) (bricks: Brick) (falling: Set<Brick>) =
let blocksToHold = holders.blocksToHold.[bricks]
let subsets =
seq {
for b in blocksToHold do
let belows = holders.blocksThatHoldMe.[b]
if Set.isSubset (belows |> Set.ofSeq) falling then
yield b
}
subsets |> List.ofSeq
let explossions =
seq {
for brick in fallenBricks do
let queue = new Queue<Brick>()
queue.Enqueue(brick)
let falling = HashSet<Brick>()
while queue.Count > 0 do
let b = queue.Dequeue()
falling.Add(b) |> ignore
let blocksToFall = blocksFalling holders b (falling |> Set.ofSeq)
blocksToFall |> List.iter (fun b -> queue.Enqueue(b))
yield falling.Count - 1
}
explossions
let parseInput (input: string list) =
let bricks =
input
|> List.map (fun line ->
let parts = line.Split([|'~'|])
let front = parts.[0].Split([|','|]) |> Array.map int
let back = parts.[1].Split([|','|]) |> Array.map int
{
xSize = { start = front.[0]; finish = back.[0] }
ySize = { start = front.[1]; finish = back.[1] }
zSize = { start = front.[2]; finish = back.[2] }
}
)
bricks
let execute =
let path = "day22/day22_input.txt"
let bricks = LocalHelper.GetLinesFromFile path |> List.ofSeq |> parseInput |> Array.ofList
(explode bricks) |> Seq.sum