summary refs log tree commit diff stats
path: root/solutions/day9.fs
blob: b6812664169e70eb137fdeae314a0c524337f251 (plain) (blame)
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
module Solutions.Day9
open System.IO
open System.Text.RegularExpressions
open FSharpPlus.Operators

let parseInstruction line =
    let groups = Regex.Match(line, "([LRUD]) (\d+)").Groups
                    |> Seq.map (fun x -> x.Value)
                    |> Array.ofSeq
    match groups[1], groups[2] with
    | "L", count -> List.replicate (int count) (-1, 0)
    | "R", count -> List.replicate (int count) (1, 0)
    | "U", count -> List.replicate (int count) (0, 1)
    | "D", count -> List.replicate (int count) (0, -1)
    | _ -> failwith "invalid input"

let headPositions steps = List.scan (fun (x1, y1) (x2, y2) -> (x1 + x2, y1 + y2)) (0, 0) steps
let instructions = File.ReadLines("inputs/day9.txt") |> Seq.map parseInstruction |> Seq.concat |> List.ofSeq |> headPositions    

let rec followPath (rope: list<int * int>) (tailSet: Set<int*int>) (heads: list<int*int>) =
    let touches pointA pointB = abs (fst pointA - fst pointB) <= 1 && abs (snd pointA - snd pointB) <= 1
    let moveTowards head tail = (fst tail + signum (fst head - fst tail), snd tail + signum (snd head - snd tail))

    if List.length heads = 0 then Set.count tailSet
    else
        let newHead = List.head heads
        let newRope = List.scan (fun head tail -> if touches head tail then tail else moveTowards head tail) newHead (List.tail rope)
        followPath newRope (Set.add (List.last newRope) tailSet) (List.tail heads)

let solution ropeSize =
    followPath (List.replicate ropeSize (0, 0)) Set.empty

let part1 () = instructions
                |> solution 2

let part2 () = instructions
                |> solution 10