aboutsummaryrefslogtreecommitdiff
path: root/aoc-2022-dotnet/Day05/Program.fs
blob: 9d9be485b28ac69dc2778fa88bdbb0faf4ccd8e7 (plain)
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
module Day05

open System
open System.IO
open FParsec
open Common

type Move =
    | Move of int * int * int

    static member parse =
        let dec n = n - 1
        let pPart str = pstring str >>. pint32
        let pMove = tuple3 (pPart "move ") (pPart " from " |>> dec) (pPart " to " |>> dec)
        Util.parse pMove >> Move

    static member execute order stacks (Move (n, fi, ti)) =
        List.mapi
            (fun i x ->
                if i = fi then
                    List.item fi stacks |> List.skip n
                elif i = ti then
                    (List.item fi stacks |> List.take n |> order)
                    @ List.item ti stacks
                else
                    x)
            stacks

let parseStacks str =
    let pFullCrate = pchar '[' >>. anyChar .>> pchar ']' |>> Some
    let pEmptyCrate = pstring "   " >>% None
    let pCrate = pFullCrate <|> pEmptyCrate
    let pCrateLine = sepBy pCrate (pchar ' ') .>> skipNewline
    let pHeader = many pCrateLine

    str
    |> Util.parse pHeader
    |> List.transpose
    |> List.map (List.choose id)

let solve order input =
    let headerList =
        input
        |> Seq.takeWhile (not << String.IsNullOrEmpty)
        |> Seq.toList

    let stacks = parseStacks <| String.Join("\n", headerList)

    String.Concat(
        input
        |> Seq.skip (headerList.Length + 1)
        |> Seq.map Move.parse
        |> Seq.fold (Move.execute order) stacks
        |> List.map List.head
    )

let test = File.ReadLines "test.txt"
assert (solve List.rev test = "CMZ")
assert (solve id test = "MCD")

let input = File.ReadLines "input.txt"
printfn "%s" <| solve List.rev input
printfn "%s" <| solve id input