From: Ummon Date: Thu, 7 Dec 2017 09:07:07 +0000 (+0100) Subject: Day 7 X-Git-Url: https://git.euphorik.ch/?a=commitdiff_plain;h=daa3e9be0946bac56e79b7653c65a107119ac8a6;p=advent_of_code_2017.git Day 7 --- diff --git a/AdventOfCode2017.sln b/AdventOfCode2017.sln index bc9b5dc..34d98a2 100644 --- a/AdventOfCode2017.sln +++ b/AdventOfCode2017.sln @@ -40,4 +40,7 @@ Global GlobalSection(Performance) = preSolution HasPerformanceSessions = true EndGlobalSection + GlobalSection(Performance) = preSolution + HasPerformanceSessions = true + EndGlobalSection EndGlobal diff --git a/AdventOfCode2017/AdventOfCode2017.fsproj b/AdventOfCode2017/AdventOfCode2017.fsproj index 0af4157..dcabd03 100644 --- a/AdventOfCode2017/AdventOfCode2017.fsproj +++ b/AdventOfCode2017/AdventOfCode2017.fsproj @@ -25,7 +25,7 @@ AnyCPU bin\$(Configuration)\$(AssemblyName).XML true - 6 + 7 pdbonly @@ -62,6 +62,7 @@ + @@ -79,6 +80,9 @@ PreserveNewest + + PreserveNewest + diff --git a/AdventOfCode2017/Day7.fs b/AdventOfCode2017/Day7.fs new file mode 100644 index 0000000..869c0a9 --- /dev/null +++ b/AdventOfCode2017/Day7.fs @@ -0,0 +1,56 @@ +module AdventOfCode2017.Day7 + +open System +open System.Linq +open System.Collections.Generic + +type Tower = + { + Name : string + Weight : int + Above : List + } + +type Input = (Tower * string list) list + +let parseInput (lines : string list) : Input = + lines + |> List.map ( + fun line -> + let items = line.Split ([| '\r'; '\t'; ' '; ','; ')'; '(' |], StringSplitOptions.RemoveEmptyEntries) + { + Name = items.[0] + Weight = int items.[1] + Above = List () + }, + [ for i in 3 .. items.Length - 1 -> items.[i] ] + ) + +let buildTower (input : Input) : Tower = + let rootTowers = Dictionary () + + for tower, _ in input do + rootTowers.Add (tower.Name, tower) + + for tower, towersAbove in input do + for towerAbove in towersAbove do + tower.Above.Add rootTowers.[towerAbove] + rootTowers.Remove towerAbove |> ignore + + rootTowers.First().Value + +// Returns the tower and its corrected weight. +let rec findUnbalanced (tower : Tower) : (Tower * int) option = + let rec weight tower = + tower.Weight + (tower.Above |> Seq.map weight |> Seq.sum) + + let towersByWeight = tower.Above |> Seq.groupBy weight + + if towersByWeight |> Seq.length > 1 then + let unbalanced = towersByWeight |> Seq.minBy (snd >> Seq.length) + let others = towersByWeight |> Seq.maxBy (snd >> Seq.length) + let delta = fst others - fst unbalanced + let unbalanced' = unbalanced |> snd |> Seq.head + findUnbalanced unbalanced' |> Option.orElse (Some (unbalanced', unbalanced'.Weight + delta)) + else + tower.Above |> Seq.tryPick (fun t -> findUnbalanced t) diff --git a/AdventOfCode2017/Program.fs b/AdventOfCode2017/Program.fs index e64ecf4..7344c5c 100644 --- a/AdventOfCode2017/Program.fs +++ b/AdventOfCode2017/Program.fs @@ -28,6 +28,11 @@ let day6 () = let part1, part2 = Day6.nbRedistribution input sprintf "part1 = %A, part2 = %A" part1 part2 +let day7 () = + let input = File.ReadAllLines "Data/day7.input" |> List.ofArray |> Day7.parseInput + let tower = Day7.buildTower input + sprintf "part1 = %A, part2 = %A" tower.Name (Day7.findUnbalanced tower |> Option.map (fun (t, w) -> t.Name, w)) + let doDay (n : int) = let sw = Diagnostics.Stopwatch () sw.Start () @@ -39,6 +44,7 @@ let doDay (n : int) = | 4 -> day4 () | 5 -> day5 () | 6 -> day6 () + | 7 -> day7 () | _ -> raise <| NotImplementedException () printfn "Result of day %i: %s (time : %i ms)" n result sw.ElapsedMilliseconds diff --git a/Tests/Day7 tests.fs b/Tests/Day7 tests.fs new file mode 100644 index 0000000..022e615 --- /dev/null +++ b/Tests/Day7 tests.fs @@ -0,0 +1,56 @@ +namespace AdventOfCode2017.Tests + +open Xunit +open Xunit.Abstractions +open Swensen.Unquote + +open AdventOfCode2017 + +type ``Day7 tests`` (output : ITestOutputHelper) = + + [] + let ``(Part1) From web page`` () = + let input = + [ + "pbga (66)" + "xhth (57)" + "ebii (61)" + "havc (66)" + "ktlj (57)" + "fwft (72) -> ktlj, cntj, xhth" + "qoyq (66)" + "padx (45) -> pbga, havc, qoyq" + "tknk (41) -> ugml, padx, fwft" + "jptl (61)" + "ugml (68) -> gyxo, ebii, jptl" + "gyxo (61)" + "cntj (57)" + ] + let tower = Day7.buildTower (Day7.parseInput input) + tower.Name =! "tknk" + + [] + let ``(Part2) From web page`` () = + let input = + [ + "pbga (66)" + "xhth (57)" + "ebii (61)" + "havc (66)" + "ktlj (57)" + "fwft (72) -> ktlj, cntj, xhth" + "qoyq (66)" + "padx (45) -> pbga, havc, qoyq" + "tknk (41) -> ugml, padx, fwft" + "jptl (61)" + "ugml (68) -> gyxo, ebii, jptl" + "gyxo (61)" + "cntj (57)" + ] + let tower = Day7.buildTower (Day7.parseInput input) + + match Day7.findUnbalanced tower with + | Some (tower, weight) -> + tower.Name =! "ugml" + weight =! 60 + | None -> failwith "no tower found" \ No newline at end of file diff --git a/Tests/Tests.fsproj b/Tests/Tests.fsproj index fe51460..0bec47c 100644 --- a/Tests/Tests.fsproj +++ b/Tests/Tests.fsproj @@ -61,6 +61,7 @@ +