This repository has been archived by the owner on Nov 22, 2024. It is now read-only.
generated from mazharenko/aoc-agent-template
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathday22.fs
109 lines (100 loc) · 3.57 KB
/
day22.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
module impl.day22
open Farkle
open Farkle.Builder
type Point3 = int*int*int
module private Point3 =
let x (x',_,_) = x'
let y (_,y',_) = y'
let z (_,_,z') = z'
type Brick = { From: Point3; To: Point3 }
module private Brick =
let allXY brick =
Seq.allPairs
(seq {Point3.x brick.From .. Point3.x brick.To})
(seq {Point3.y brick.From .. Point3.y brick.To})
let private number = Terminals.int "Number"
let private point = "Point" ||= [
!@ number .>> "," .>>. number .>> "," .>>. number
=> fun x y z -> x,y,z
]
let private brick = "Brick" ||= [
!@ point .>> "~" .>>. point
=> fun p1 p2 -> { From = p1; To = p2 }
]
let parse input =
Pattern1.read (RuntimeFarkle.parseUnsafe (RuntimeFarkle.build brick)) input
type private State = {
Bricks: Brick list
Top: Map<int*int, int*Brick>
Supports: Map<Brick, Set<Brick>>
SupportedBy: Map<Brick, Set<Brick>>
}
module private State =
let fromBricks bricks =
{
Bricks = bricks |> Seq.sortBy (_.From >> Point3.z) |> Seq.toList
Top = Map.empty
Supports = Map.empty
SupportedBy = Map.empty
}
let rec private fall state =
match state.Bricks with
| [] -> state
| brick::rest ->
let toRestBricks, toRestZ =
Brick.allXY brick
|> Seq.fold (fun (foundPointsToRest,z) p ->
let existing = Map.tryFind p state.Top
match existing with
| None -> foundPointsToRest,z
| Some (existingZ,brick) ->
if existingZ > z then (Set.add brick Set.empty),existingZ
elif existingZ = z then (Set.add brick foundPointsToRest),existingZ
else foundPointsToRest,z
) (Set.empty,0)
let newTop =
Brick.allXY brick
|> Seq.fold (fun top xy -> Map.add xy (toRestZ + Point3.z brick.To - Point3.z brick.From + 1, brick) top) state.Top
{
Bricks = rest
Top = newTop
SupportedBy =
state.SupportedBy |> Map.add brick toRestBricks
Supports =
toRestBricks |> Seq.fold (
fun supports b ->
supports
|> Map.change b (
function
| None -> Set.ofList [brick] |> Some
| Some bb -> Set.add brick bb |> Some
)
) state.Supports
} |> fall
let solve1 input =
let {Supports = supports; SupportedBy = supportedBy} =
input |> State.fromBricks |> fall
input
|> Seq.where (
fun brick ->
match Map.tryFind brick supports with
| None -> true
| Some supported ->
supported |> Seq.forall (fun sup -> supportedBy[sup] |> Set.count > 1)
)
|> Seq.length
let rec private wouldFall supports supportedBy falling brick =
match supports |> Map.tryFind brick with
| None -> falling
| Some supported ->
let newFalling =
supported
|> Set.filter (fun s -> supportedBy |> Map.find s |> Seq.forall(fun x -> x = brick || Set.contains x falling))
newFalling
|> Seq.fold (wouldFall supports supportedBy) (Set.union falling newFalling)
let solve2 input =
let {Supports = supports; SupportedBy = supportedBy} =
input |> State.fromBricks |> fall
input
|> Seq.map (fun brick -> wouldFall supports supportedBy Set.empty brick)
|> Seq.sumBy Seq.length