Untitled

mail@pastecode.io avatar
unknown
fsharp
3 years ago
4.5 kB
2
Indexable
Never
module AdventOfCode2021.day08.part2

open System
open Microsoft.FSharp.Core

let readInput =
    let path = $@"{__SOURCE_DIRECTORY__}\input.txt"
    System.IO.File.ReadAllLines path |> Array.toList

let testInput =
    "be cfbegad cbdgef fgaecd cgeb fdcge agebfd fecdb fabcd edb | fdgacbe cefdb cefbgd gcbe
  edbfga begcd cbg gc gcadebf fbgde acbgfd abcde gfcbed gfec | fcgedb cgb dgebacf gc
  fgaebd cg bdaec gdafb agbcfd gdcbef bgcad gfac gcb cdgabef | cg cg fdcagb cbg
  fbegcd cbd adcefb dageb afcb bc aefdc ecdab fgdeca fcdbega | efabcd cedba gadfec cb
  aecbfdg fbg gf bafeg dbefa fcge gcbea fcaegb dgceab fcbdga | gecf egdcabf bgf bfgea
  fgeab ca afcebg bdacfeg cfaedg gcfdb baec bfadeg bafgc acf | gebdcfa ecba ca fadegcb
  dbcfg fgd bdegcaf fgec aegbdf ecdfab fbedc dacgb gdcebf gf | cefg dcbef fcge gbcadfe
  bdfegc cbegaf gecbf dfcage bdacg ed bedf ced adcbefg gebcd | ed bcgafe cdgba cbgef
  egadfb cdbfeg cegd fecab cgb gbdefca cg fgcdab egfdb bfceg | gbdfcae bgc cg cgb
  gcafb gcf dcaebfg ecagb gf abcdeg gaef cafbge fdbac fegbdc | fgae cfgab fg bagce"

let splitByLines (input: string) =
    input.Split("\n") |> List.ofSeq |> List.distinct

let getOutputSegs (s: string) =
    s.Split(" | ").[1].Split(" ")
    |> List.ofSeq
    |> List.map (fun x -> x.Trim())

let getInputSegs (s: string) =
    s.Split(" | ").[0].Split(" ")
    |> List.ofSeq
    |> List.map (fun x -> x.Trim())


let combined =
    splitByLines testInput
    |> List.map
        (fun x ->
            let ip = getInputSegs x
            let second = getOutputSegs x
            (ip, second))

let combinedInput =
    readInput
    |> List.map
        (fun x ->
            let ip = getInputSegs x
            let second = getOutputSegs x
            (ip, second))

let uniqueSegs (sl: string list) (length: int) =
    sl |> List.find (fun x -> x.Length = length)

let multipleSegs (sl: string list) (length: int) =
    sl |> List.filter (fun x -> x.Length = length)

let toChars (s: string) = Seq.toList s

let removeChars (s: string) (s2: string) =
    // Segment - Segment2
    toChars s
    |> List.filter (fun x -> toChars s2 |> List.contains x |> not)

let containsAll (cl: char list) (cl2: char list) =
    // first charlist contains all from second
    cl2
    |> List.forall (fun x -> cl |> List.contains x)

let toString (cl: char list) = cl |> Array.ofList |> String

let rec findInpOutMatch (sl: string list) (os: string) =
    match sl with
    | [] -> failwith "Should not happen"
    | [ x ] -> x
    | x :: xs ->
        if (String.length x) = (String.length os)
           && (containsAll (toChars x) (toChars os)) then
            x
        else
            findInpOutMatch xs os

// Number: Segment length. {1: 2}, {4: 4}, {7: 3}, {8: 7}
let figureOutNumbers (inp: string list, out: string list) =
    let one = uniqueSegs inp 2
    let four = uniqueSegs inp 4
    let seven = uniqueSegs inp 3
    let eight = uniqueSegs inp 7

    let three =
        multipleSegs inp 5
        |> List.map toChars
        |> List.filter (fun x -> containsAll x (toChars one))
        |> List.head

    let five =
        multipleSegs inp 5
        |> List.map toChars
        |> List.filter (fun x -> containsAll x (removeChars four one))
        |> List.head

    let two =
        multipleSegs inp 5
        |> List.map toChars
        |> List.filter (fun x -> [ three; five ] |> List.contains x |> not)
        |> List.head

    let six =
        multipleSegs inp 6
        |> List.map toChars
        |> List.filter (fun x -> containsAll x (toChars one) |> not)
        |> List.head

    let nine =
        multipleSegs inp 6
        |> List.map toChars
        |> List.filter (fun x -> containsAll x (toChars one))
        |> List.filter (fun x -> containsAll x (toChars four))
        |> List.head

    let zero =
        multipleSegs inp 6
        |> List.map toChars
        |> List.except [ nine; six ]
        |> List.head

    let asList =
        [ toString zero
          one
          toString two
          toString three
          four
          toString five
          toString six
          seven
          eight
          toString nine ]

    let numbers = [ 0; 1; 2; 3; 4; 5; 6; 7; 8; 9 ]
    let mappi = List.zip asList numbers |> Map.ofList

    out
    |> List.map (findInpOutMatch asList)
    |> List.map (fun x -> mappi |> Map.find x)
    |> List.map string
    |> String.concat ""
    |> int

let res =
    combinedInput
    |> List.map figureOutNumbers
    |> List.reduce (+)