diff options
-rw-r--r-- | README.md | 2 | ||||
-rw-r--r-- | aoc-2022-dotnet/Day12/Program.fs | 2 | ||||
-rw-r--r-- | aoc-2022-dotnet/Day16/Program.fs | 4 | ||||
-rw-r--r-- | aoc-2022-dotnet/Day19/Day19.fsproj | 24 | ||||
-rw-r--r-- | aoc-2022-dotnet/Day19/Program.fs | 148 | ||||
-rw-r--r-- | aoc-2022-dotnet/Day21/Program.fs | 2 | ||||
-rw-r--r-- | aoc-2022-dotnet/Day24/Program.fs | 2 | ||||
-rw-r--r-- | aoc-2022-dotnet/README.md | 56 | ||||
-rw-r--r-- | aoc-2022-dotnet/aoc-2022-dotnet.sln | 6 |
9 files changed, 212 insertions, 34 deletions
@@ -10,7 +10,7 @@ Repository storing my solutions to Advent of Code. See other people's solutions ### [2022](aoc-2022-dotnet)  - + [awesome]: https://github.com/Bogdanp/awesome-advent-of-code [aoc]: https://adventofcode.com diff --git a/aoc-2022-dotnet/Day12/Program.fs b/aoc-2022-dotnet/Day12/Program.fs index 7e1a409..ccd7697 100644 --- a/aoc-2022-dotnet/Day12/Program.fs +++ b/aoc-2022-dotnet/Day12/Program.fs @@ -77,7 +77,7 @@ let solution distanceCalculation = && Square.canTraverse square (Util.mAt matrix np)) |> Set.map (Vec2.toIndexOf matrix))) >> Seq.indexed - >> Map.ofSeq + >> Map >> Graph >> distanceCalculation >> Option.get diff --git a/aoc-2022-dotnet/Day16/Program.fs b/aoc-2022-dotnet/Day16/Program.fs index 87b0ffa..208d975 100644 --- a/aoc-2022-dotnet/Day16/Program.fs +++ b/aoc-2022-dotnet/Day16/Program.fs @@ -48,7 +48,7 @@ let buildGraph input = bfsExplore Set.empty [] [ (start, 0) ] - let valveMap = input |> Seq.map parseValve |> Map.ofSeq + let valveMap = input |> Seq.map parseValve |> Map let flows = valveMap @@ -59,7 +59,7 @@ let buildGraph input = valveMap |> Map.keys |> Seq.collect (distancesFrom valveMap) - |> Map.ofSeq + |> Map |> Map.filter (fun (f, t) _ -> f <> t && Map.containsKey f flows diff --git a/aoc-2022-dotnet/Day19/Day19.fsproj b/aoc-2022-dotnet/Day19/Day19.fsproj new file mode 100644 index 0000000..d723b37 --- /dev/null +++ b/aoc-2022-dotnet/Day19/Day19.fsproj @@ -0,0 +1,24 @@ +<Project Sdk="Microsoft.NET.Sdk"> + + <PropertyGroup> + <OutputType>Exe</OutputType> + <TargetFramework>net7.0</TargetFramework> + </PropertyGroup> + + <ItemGroup> + <Content Include="test.txt"> + <CopyToOutputDirectory>Always</CopyToOutputDirectory> + </Content> + <Content Include="input.txt"> + <CopyToOutputDirectory>Always</CopyToOutputDirectory> + </Content> + <Compile Include="Program.fs" /> + </ItemGroup> + + <ItemGroup> + <PackageReference Update="FSharp.Core"> + <TreatAsUsed>true</TreatAsUsed> + </PackageReference> + </ItemGroup> + +</Project> diff --git a/aoc-2022-dotnet/Day19/Program.fs b/aoc-2022-dotnet/Day19/Program.fs new file mode 100644 index 0000000..e8770b6 --- /dev/null +++ b/aoc-2022-dotnet/Day19/Program.fs @@ -0,0 +1,148 @@ +module Day19 + +open System +open System.IO +open System.Text.RegularExpressions + +type Resource = + | Ore + | Clay + | Obsidian + | Geode + + static member list = [ Ore; Clay; Obsidian; Geode ] + +type State = + { Robots: Map<Resource, int> + Gathered: Map<Resource, int> + TimeLeft: int } + + static member initial time = + { Robots = + Map [ (Ore, 1) + (Clay, 0) + (Obsidian, 0) + (Geode, 0) ] + Gathered = + Map [ (Ore, 0) + (Clay, 0) + (Obsidian, 0) + (Geode, 0) ] + TimeLeft = time } + + member inline state.optimisticGeodeCount = + state.Gathered[Geode] + + state.Robots[Geode] * state.TimeLeft + + state.TimeLeft * (state.TimeLeft - 1) / 2 + + static member inline tick state = + { state with + Gathered = Map.map (fun resource -> (+) state.Robots[resource]) state.Gathered + TimeLeft = state.TimeLeft - 1 } + + member inline state.isImpossibleToBuy = + function + | Geode -> state.Robots[Obsidian] = 0 + | Obsidian -> state.Robots[Clay] = 0 + | _ -> false + +type Blueprint = + { Id: int + RobotCosts: Map<Resource, Map<Resource, int>> } + + static member private regex = Regex(@"\d+", RegexOptions.Compiled) + + static member parse input = + Blueprint.regex.Matches(input) + |> Seq.map (fun kv -> int kv.Value) + |> List.ofSeq + |> function + | [ id; oreOreCost; clayOreCost; obsidianOreCost; obsidianClayCost; geodeOreCost; geodeObsidianCost ] -> + { Id = id + RobotCosts = + Map [ (Ore, + Map [ (Ore, oreOreCost) + (Clay, 0) + (Obsidian, 0) + (Geode, 0) ]) + (Clay, + Map [ (Ore, clayOreCost) + (Clay, 0) + (Obsidian, 0) + (Geode, 0) ]) + (Obsidian, + Map [ (Ore, obsidianOreCost) + (Clay, obsidianClayCost) + (Obsidian, 0) + (Geode, 0) ]) + (Geode, + Map [ (Ore, geodeOreCost) + (Clay, 0) + (Obsidian, geodeObsidianCost) + (Geode, 0) ]) ] } + | _ -> failwith "Invalid blueprint format!" + + member inline private blueprint.canBuyRobot robotResource state = + Map.forall (fun resource -> (>=) state.Gathered[resource]) blueprint.RobotCosts[robotResource] + + member inline private blueprint.buyRobot robotResource state = + { state with + Robots = state.Robots.Change(robotResource, Option.map <| (+) 1) + Gathered = + state.Gathered + |> Map.map (fun costResource previousCount -> + previousCount + - blueprint.RobotCosts[robotResource][costResource]) } + + static member private robotCaps blueprint = + Resource.list + |> List.map (fun costResource -> + costResource, + Resource.list + |> List.map (fun robotResource -> blueprint.RobotCosts[robotResource][costResource]) + |> List.max) + |> Map.ofList + |> Map.add Geode Int32.MaxValue + + static member evaluate time blueprint = + let robotCaps = Blueprint.robotCaps blueprint + + let rec solve bestScore robotGoal state = + if state.TimeLeft <= 0 then + state.Gathered[Geode] + elif state.Robots[robotGoal] >= robotCaps[robotGoal] + || state.isImpossibleToBuy robotGoal + || state.optimisticGeodeCount <= bestScore then + bestScore + elif blueprint.canBuyRobot robotGoal state then + let state = + state + |> State.tick + |> blueprint.buyRobot robotGoal + + List.fold (fun bestScore nextRobotGoal -> solve bestScore nextRobotGoal state) bestScore Resource.list + else + state |> State.tick |> solve bestScore robotGoal + + List.fold (fun bestScore robotGoal -> solve bestScore robotGoal (State.initial time)) 0 Resource.list + + static member inline qualityLevel blueprint = + blueprint.Id * Blueprint.evaluate 24 blueprint + +let solution1 = + Seq.map Blueprint.parse + >> Seq.sumBy Blueprint.qualityLevel + +let solution2 = + Seq.map Blueprint.parse + >> Seq.truncate 3 + >> Seq.map (Blueprint.evaluate 32) + >> Seq.reduce (*) + +let test = File.ReadLines("test.txt") +assert (solution1 test = 33) +assert (solution2 test = 56 * 62) + +let input = File.ReadLines("input.txt") +printfn "%d" <| solution1 input +printfn "%d" <| solution2 input diff --git a/aoc-2022-dotnet/Day21/Program.fs b/aoc-2022-dotnet/Day21/Program.fs index f9a608d..6ca702c 100644 --- a/aoc-2022-dotnet/Day21/Program.fs +++ b/aoc-2022-dotnet/Day21/Program.fs @@ -65,7 +65,7 @@ let solution modification input = let monkeys = input |> Seq.map Monkey.parse - |> Map.ofSeq + |> Map |> modification let nodeValues = diff --git a/aoc-2022-dotnet/Day24/Program.fs b/aoc-2022-dotnet/Day24/Program.fs index 0446c06..2cb5ef8 100644 --- a/aoc-2022-dotnet/Day24/Program.fs +++ b/aoc-2022-dotnet/Day24/Program.fs @@ -19,7 +19,7 @@ type Valley = Blizzards = Vec2.directions4 |> Set.map (fun d -> d, Set.empty) - |> Map.ofSeq } + |> Map } static member private withExpeditionAt target valley = { valley with ExpeditionSuperposition = Set.singleton <| target valley } diff --git a/aoc-2022-dotnet/README.md b/aoc-2022-dotnet/README.md index 34d872f..2cf006d 100644 --- a/aoc-2022-dotnet/README.md +++ b/aoc-2022-dotnet/README.md @@ -1,31 +1,31 @@ # Advent of Code 2022 in F#  - + -| Day | Problem Name | Part 1 | Part 2 | Practiced Concepts | -| :----: | ---------------------------------------------------------------- | :----: | :----: | ---------------------------------------------------- | -| **01** | [Calorie Counting](https://adventofcode.com/2022/day/1) | :star: | :star: | `Seq`, `\|>` and `>>`, FSharpPlus | -| **02** | [Rock Paper Scissors](https://adventofcode.com/2022/day/2) | :star: | :star: | ADTs, type members, patterns | -| **03** | [Rucksack Reorganization](https://adventofcode.com/2022/day/3) | :star: | :star: | ASCII code, `Set` | -| **04** | [Camp Cleanup](https://adventofcode.com/2022/day/4) | :star: | :star: | ranges, FParsec | -| **05** | [Supply Stacks](https://adventofcode.com/2022/day/5) | :star: | :star: | functional stacks, `List.transpose`, `Seq.fold` | -| **06** | [Tuning Trouble](https://adventofcode.com/2022/day/6) | :star: | :star: | `Seq.windowed`, `Set` | -| **07** | [No Space Left On Device](https://adventofcode.com/2022/day/7) | :star: | :star: | patterns, ADTs, FParsec | -| **08** | [Treetop Tree House](https://adventofcode.com/2022/day/8) | :star: | :star: | `Array2D`, slices | -| **09** | [Rope Bridge](https://adventofcode.com/2022/day/9) | :star: | :star: | 2D vectors, Chebyshev distance, `Seq.scan` | -| **10** | [Cathode-Ray Tube](https://adventofcode.com/2022/day/10) | :star: | :star: | `Map`, `Seq.fold` | -| **11** | [Monkey in the Middle](https://adventofcode.com/2022/day/11) | :star: | :star: | records, type abbrevs, `List.choose`, tail recursion | -| **12** | [Hill Climbing Algorithm](https://adventofcode.com/2022/day/12) | :star: | :star: | functional graphs, functional BFS, `Array2D` | -| **13** | [Distress Signal](https://adventofcode.com/2022/day/13) | :star: | :star: | `IComparable`, ADTs, patterns, FParsec | -| **14** | [Regolith Reservoir](https://adventofcode.com/2022/day/14) | :star: | :star: | `Seq.unfold`, `Seq.pairwise`, functional DFS | -| **15** | [Beacon Exclusion Zone](https://adventofcode.com/2022/day/15) | :star: | :star: | ranges, mahattan distance, parallel computing | -| **16** | [Proboscidea Volcanium](https://adventofcode.com/2022/day/16) | :star: | :star: | graphs, dynamic programming, `Seq` | -| **17** | [Pyroclastic Flow](https://adventofcode.com/2022/day/17) | :star: | :star: | cycle detection, bitwise operators, `hash` | -| **18** | [Boiling Boulders](https://adventofcode.com/2022/day/18) | :star: | :star: | functional DFS, 3D vectors, position bound checking | -| **19** | [Not Enough Minerals](https://adventofcode.com/2022/day/19) | | | | -| **20** | [Grove Positioning System](https://adventofcode.com/2022/day/20) | :star: | :star: | linked lists, remainder | -| **21** | [Monkey Math](https://adventofcode.com/2022/day/21) | :star: | :star: | topological sort, ADTs, complex numbers | -| **22** | [Monkey Map](https://adventofcode.com/2022/day/22) | | | | -| **23** | [Unstable Diffusion](https://adventofcode.com/2022/day/23) | :star: | :star: | `Set`, 2D vectors, `Seq.unfold`, composition | -| **24** | [Blizzard Basin](https://adventofcode.com/2022/day/24) | :star: | :star: | `Set`, 2D vectors, remainder, records | -| **25** | [Full of Hot Air](https://adventofcode.com/2022/day/25) | :star: | | positional numeral systems, recursion | +| Day | Problem Name | Part 1 | Part 2 | Practiced Concepts | +| :----: | ---------------------------------------------------------------- | :----: | :----: | ----------------------------------------------------- | +| **01** | [Calorie Counting](https://adventofcode.com/2022/day/1) | :star: | :star: | `Seq`, `\|>` and `>>`, FSharpPlus | +| **02** | [Rock Paper Scissors](https://adventofcode.com/2022/day/2) | :star: | :star: | ADTs, type members, patterns | +| **03** | [Rucksack Reorganization](https://adventofcode.com/2022/day/3) | :star: | :star: | ASCII code, `Set` | +| **04** | [Camp Cleanup](https://adventofcode.com/2022/day/4) | :star: | :star: | ranges, FParsec | +| **05** | [Supply Stacks](https://adventofcode.com/2022/day/5) | :star: | :star: | functional stacks, `List.transpose`, `Seq.fold` | +| **06** | [Tuning Trouble](https://adventofcode.com/2022/day/6) | :star: | :star: | `Seq.windowed`, `Set` | +| **07** | [No Space Left On Device](https://adventofcode.com/2022/day/7) | :star: | :star: | patterns, ADTs, FParsec | +| **08** | [Treetop Tree House](https://adventofcode.com/2022/day/8) | :star: | :star: | `Array2D`, slices | +| **09** | [Rope Bridge](https://adventofcode.com/2022/day/9) | :star: | :star: | 2D vectors, Chebyshev distance, `Seq.scan` | +| **10** | [Cathode-Ray Tube](https://adventofcode.com/2022/day/10) | :star: | :star: | `Map`, `Seq.fold` | +| **11** | [Monkey in the Middle](https://adventofcode.com/2022/day/11) | :star: | :star: | records, type abbrevs, `List.choose`, tail recursion | +| **12** | [Hill Climbing Algorithm](https://adventofcode.com/2022/day/12) | :star: | :star: | functional graphs, functional BFS, `Array2D` | +| **13** | [Distress Signal](https://adventofcode.com/2022/day/13) | :star: | :star: | `IComparable`, ADTs, patterns, FParsec | +| **14** | [Regolith Reservoir](https://adventofcode.com/2022/day/14) | :star: | :star: | `Seq.unfold`, `Seq.pairwise`, functional DFS | +| **15** | [Beacon Exclusion Zone](https://adventofcode.com/2022/day/15) | :star: | :star: | ranges, mahattan distance, parallel computing | +| **16** | [Proboscidea Volcanium](https://adventofcode.com/2022/day/16) | :star: | :star: | graphs, dynamic programming, `Seq` | +| **17** | [Pyroclastic Flow](https://adventofcode.com/2022/day/17) | :star: | :star: | cycle detection, bitwise operators, `hash` | +| **18** | [Boiling Boulders](https://adventofcode.com/2022/day/18) | :star: | :star: | functional DFS, 3D vectors, position bound checking | +| **19** | [Not Enough Minerals](https://adventofcode.com/2022/day/19) | :star: | :star: | `List.fold`, records, `Map`, mutability, optimization | +| **20** | [Grove Positioning System](https://adventofcode.com/2022/day/20) | :star: | :star: | linked lists, remainder | +| **21** | [Monkey Math](https://adventofcode.com/2022/day/21) | :star: | :star: | topological sort, ADTs, complex numbers | +| **22** | [Monkey Map](https://adventofcode.com/2022/day/22) | | | | +| **23** | [Unstable Diffusion](https://adventofcode.com/2022/day/23) | :star: | :star: | `Set`, 2D vectors, `Seq.unfold`, composition | +| **24** | [Blizzard Basin](https://adventofcode.com/2022/day/24) | :star: | :star: | `Set`, 2D vectors, remainder, records | +| **25** | [Full of Hot Air](https://adventofcode.com/2022/day/25) | :star: | | positional numeral systems, recursion | diff --git a/aoc-2022-dotnet/aoc-2022-dotnet.sln b/aoc-2022-dotnet/aoc-2022-dotnet.sln index a233bf2..5d1708a 100644 --- a/aoc-2022-dotnet/aoc-2022-dotnet.sln +++ b/aoc-2022-dotnet/aoc-2022-dotnet.sln @@ -60,6 +60,8 @@ Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "Day23", "Day23\Day23.fsproj EndProject Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "Day24", "Day24\Day24.fsproj", "{253313A4-C9F8-4A83-89A5-8FCB426004E0}" EndProject +Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "Day19", "Day19\Day19.fsproj", "{65ED4E60-D36D-4519-9DF1-EFCE6787D480}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -166,6 +168,10 @@ Global {253313A4-C9F8-4A83-89A5-8FCB426004E0}.Debug|Any CPU.Build.0 = Debug|Any CPU {253313A4-C9F8-4A83-89A5-8FCB426004E0}.Release|Any CPU.ActiveCfg = Release|Any CPU {253313A4-C9F8-4A83-89A5-8FCB426004E0}.Release|Any CPU.Build.0 = Release|Any CPU + {65ED4E60-D36D-4519-9DF1-EFCE6787D480}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {65ED4E60-D36D-4519-9DF1-EFCE6787D480}.Debug|Any CPU.Build.0 = Debug|Any CPU + {65ED4E60-D36D-4519-9DF1-EFCE6787D480}.Release|Any CPU.ActiveCfg = Release|Any CPU + {65ED4E60-D36D-4519-9DF1-EFCE6787D480}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE |