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 (+)