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
|
open System.IO
open System.Text.RegularExpressions
type Vector =
struct
val mutable x: int
val mutable y: int
val mutable z: int
new(X, Y, Z) = {x=X; y=Y; z=Z}
member this.add(other: Vector) =
this.x <- this.x + other.x
this.y <- this.y + other.y
this.z <- this.z + other.z
member this.manhattan() =
abs this.x + abs this.y + abs this.z
override this.ToString() =
sprintf "(%d, %d, %d)" this.x this.y this.z
end
type Projectile =
struct
val id: int
val mutable position: Vector
val mutable velocity: Vector
val acceleration: Vector
new(ID, pos, vel, acc) = {id=ID; position=pos; velocity=vel; acceleration=acc}
member this.update() =
this.velocity.add(this.acceleration)
this.position.add(this.velocity)
this
member this.distance() =
this.velocity.manhattan()
override this.ToString() =
sprintf "p=%A v=%A a=%A" this.position this.velocity this.acceleration
end
let parseInput i str =
let m = Regex("(-?\d+)").Matches(str)
let values = [for g in m -> int g.Value]
if List.length values <> 9 then printfn "%A" values; failwith "invalid input"
Projectile(i, Vector(values[0], values[1], values[2]),
Vector(values[3], values[4], values[5]),
Vector(values[6], values[7], values[8]))
let part1() =
let mutable projectiles = File.ReadAllLines "day20.txt" |> Array.mapi parseInput
// assume that 1000 simulations is good enough
for i = 1 to 1000 do
projectiles <- Array.map (fun (x: Projectile) -> x.update()) projectiles
Array.minBy (fun (x: Projectile) -> x.distance()) projectiles |> (fun x -> x.id) |> printfn "%d"
let part2() =
let mutable projectiles = File.ReadAllLines "day20.txt" |> Array.mapi parseInput
for i = 1 to 1000 do
projectiles <- Array.map (fun (x: Projectile) -> x.update()) projectiles
let uncollided = Array.groupBy (fun (x: Projectile) -> x.position) projectiles
|> Array.filter (fun (pos, xs) -> Array.length xs = 1)
|> Array.map snd
|> Array.fold Array.append Array.empty
projectiles <- uncollided
Array.length projectiles |> printfn "%d"
let () =
part1()
part2()
|