diff options
author | Tomasz Chojnacki <tomaszchojnacki2001@gmail.com> | 2022-12-21 11:45:04 +0100 |
---|---|---|
committer | Tomasz Chojnacki <tomaszchojnacki2001@gmail.com> | 2022-12-21 11:45:04 +0100 |
commit | 9e378a9f80260c2f729daaf83d8e74f7bad70b16 (patch) | |
tree | db61e67a7222cd0666ea7fe4976e2fded327599a /aoc-2022-dotnet | |
parent | a8c844a12fa2d91410fda7b37f08c58f5be34ed9 (diff) | |
download | gleam_aoc2020-9e378a9f80260c2f729daaf83d8e74f7bad70b16.tar.gz gleam_aoc2020-9e378a9f80260c2f729daaf83d8e74f7bad70b16.zip |
Finish day 17
Diffstat (limited to 'aoc-2022-dotnet')
-rw-r--r-- | aoc-2022-dotnet/Common/Util.fs | 16 | ||||
-rw-r--r-- | aoc-2022-dotnet/Common/Vec2.fs | 13 | ||||
-rw-r--r-- | aoc-2022-dotnet/Day17/Day17.fsproj | 26 | ||||
-rw-r--r-- | aoc-2022-dotnet/Day17/Program.fs | 155 | ||||
-rw-r--r-- | aoc-2022-dotnet/README.md | 56 | ||||
-rw-r--r-- | aoc-2022-dotnet/aoc-2022-dotnet.sln | 10 |
6 files changed, 245 insertions, 31 deletions
diff --git a/aoc-2022-dotnet/Common/Util.fs b/aoc-2022-dotnet/Common/Util.fs index acf89af..568f2c2 100644 --- a/aoc-2022-dotnet/Common/Util.fs +++ b/aoc-2022-dotnet/Common/Util.fs @@ -38,7 +38,11 @@ module Util = let mAt matrix (Vec2 (col, row)) = Array2D.get matrix row col - let composition n f = List.replicate n f |> List.reduce (>>) + let rec composition n f x = + if n = 0 then + x + else + composition (n - 1) f (f x) let notIn set element = not <| Set.contains element set @@ -51,6 +55,16 @@ module Util = | h :: t -> min h x :: (insertSorted (max h x) t) | [] -> [ x ] + let liftList xs = + match List.forall Option.isSome xs with + | true -> Some(List.map Option.get xs) + | false -> None + + let cycle = + function + | h :: t -> h, t @ [ h ] + | [] -> failwith "Empty list!" + let topN n xs = Seq.fold (fun acc x -> diff --git a/aoc-2022-dotnet/Common/Vec2.fs b/aoc-2022-dotnet/Common/Vec2.fs index 8835a5a..61b313d 100644 --- a/aoc-2022-dotnet/Common/Vec2.fs +++ b/aoc-2022-dotnet/Common/Vec2.fs @@ -13,6 +13,8 @@ type Vec2 = static member down = Vec2(0, -1) static member left = Vec2(-1, 0) + static member upRight = Vec2(1, 1) + static member upLeft = Vec2(-1, 1) static member downLeft = Vec2(-1, -1) static member downRight = Vec2(1, -1) @@ -22,6 +24,16 @@ type Vec2 = Vec2.down Vec2.left ] + static member directions8 = + [ Vec2.up + Vec2.upRight + Vec2.right + Vec2.downRight + Vec2.down + Vec2.downLeft + Vec2.left + Vec2.upLeft ] + static member inline (~-) = Vec2.map (~-) static member inline (+)(Vec2 (x1, y1), Vec2 (x2, y2)) = Vec2(x1 + x2, y1 + y2) static member inline (-)(v1, v2) = v1 + Vec2.op_UnaryNegation (v2) @@ -34,6 +46,7 @@ type Vec2 = static member mahattanDist (Vec2 (x1, y1)) (Vec2 (x2, y2)) = abs (x2 - x1) + abs (y2 - y1) static member chebyshevDist (Vec2 (x1, y1)) (Vec2 (x2, y2)) = max (abs <| x2 - x1) (abs <| y2 - y1) static member neighbours4 v = List.map ((+) v) Vec2.directions4 + static member neighbours8 v = List.map ((+) v) Vec2.directions8 static member lineBetween(Vec2 (x1, y1), Vec2 (x2, y2)) = if x1 = x2 then diff --git a/aoc-2022-dotnet/Day17/Day17.fsproj b/aoc-2022-dotnet/Day17/Day17.fsproj new file mode 100644 index 0000000..795d59c --- /dev/null +++ b/aoc-2022-dotnet/Day17/Day17.fsproj @@ -0,0 +1,26 @@ +<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 Include="FSharpPlus" Version="1.3.2" /> + </ItemGroup> + + <ItemGroup> + <ProjectReference Include="..\Common\Common.fsproj" /> + </ItemGroup> + +</Project> diff --git a/aoc-2022-dotnet/Day17/Program.fs b/aoc-2022-dotnet/Day17/Program.fs new file mode 100644 index 0000000..70374f4 --- /dev/null +++ b/aoc-2022-dotnet/Day17/Program.fs @@ -0,0 +1,155 @@ +module Day17 + +open System.IO +open FSharpPlus +open Common + +type Dir = + | Left + | Right + + static member movesFromInput(input: string) = + input + |> String.trimWhiteSpaces + |> Seq.map Dir.fromChar + |> List.ofSeq + + static member private fromChar = + function + | '<' -> Left + | '>' -> Right + | c -> failwithf "Invalid character: %c" c + + static member shiftOp = + function + | Left -> (<<<) + | Right -> (>>>) + +module Row = + let full = 0b1111111uy + let empty = 0b0000000uy + + let private countBlocks row = + let rec helper = + function + | 0uy -> 0 + | n -> int (n &&& 1uy) + helper (n >>> 1) + + helper (row &&& full) + + let shift dir shape settled = + let shape' = (Dir.shiftOp dir) shape 1 + + let overflow = countBlocks shape' <> countBlocks shape + let collision = shape' &&& settled <> empty + + match overflow || collision with + | true -> None + | false -> Some(shape') + +module Chamber = + let private shapes = + [ [ 0b0011110uy ] // horizontal line + + [ 0b0001000uy + 0b0011100uy + 0b0001000uy ] // cross + + [ 0b0000100uy + 0b0000100uy + 0b0011100uy ] // L-shape + + [ 0b0010000uy + 0b0010000uy + 0b0010000uy + 0b0010000uy ] // vertical line + + [ 0b0011000uy; 0b0011000uy ] ] // square + + let private makeSpaceFor shape settled = + (List.replicate (List.length shape + 3) Row.empty) + @ settled + + let private shift dir (shape, settled) = + let shiftedRows = List.map2Shortest (Row.shift dir) shape settled + + let shape = + shiftedRows + |> Util.liftList + |> Option.defaultValue shape + + shape, settled + + let private fall (shape, settled) = + let (shape', settled') = + match settled with + | [ _ ] -> [], shape + | h :: t when h = Row.empty -> shape, t + | _ -> Row.empty :: shape, settled + + let collision = + List.map2Shortest (&&&) shape' settled' + |> List.exists ((<>) Row.empty) + + if collision then + [], + (List.map2Shortest (|||) shape settled) + @ List.skip (List.length shape) settled + else + shape', settled' + + let private stateFingerprint moves shapes tower = + hash (moves, List.head shapes, List.truncate 128 tower) + + let towerHeight n moves = + let rec helper (moves, shapes, tower, cache, n) = + let cacheKey = stateFingerprint moves shapes tower + let towerHeight = int64 <| List.length tower + + if Map.containsKey cacheKey cache then + let (oldCount, oldHeight) = cache[cacheKey] + let countDiff = oldCount - n + let heightDiff = towerHeight - oldHeight + let skippedCycles = n / countDiff + let skippedHeight = skippedCycles * heightDiff + let leftoverCount = n - skippedCycles * countDiff + 1L + + skippedHeight + + helper (moves, shapes, tower, Map.empty, leftoverCount) + else + let cache = cache |> Map.add cacheKey (n, towerHeight) + + let (shape, shapes) = Util.cycle shapes + let tower = tower |> makeSpaceFor shape + + let rec step moves shape tower = + let (move, moves) = Util.cycle moves + let (shape, tower) = shift move (shape, tower) + let (shape, tower) = fall (shape, tower) + + if List.isEmpty shape then + (moves, tower) + else + step moves shape tower + + let (moves, tower) = step moves shape tower + + let n = n - 1L + + if n = 0L then + towerHeight + else + helper (moves, shapes, tower, cache, n) + + helper (moves, shapes, [], Map.empty, n) + +let solution n = + Dir.movesFromInput >> Chamber.towerHeight n + +let test = File.ReadAllText("test.txt") +assert (solution 2022 test = 3068) +assert (solution 1_000_000_000_000L test = 1514285714288L) + +let input = File.ReadAllText("input.txt") +printfn "%d" <| solution 2022 input +printfn "%d" <| solution 1_000_000_000_000L input diff --git a/aoc-2022-dotnet/README.md b/aoc-2022-dotnet/README.md index 506101c..25192a0 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: | 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) | | | | -| **18** | ??? | | | | -| **19** | ??? | | | | -| **20** | ??? | | | | -| **21** | ??? | | | | -| **22** | ??? | | | | -| **23** | ??? | | | | -| **24** | ??? | | | | -| **25** | ??? | | | | +| 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: | 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, hashing | +| **18** | [Boiling Boulders](https://adventofcode.com/2022/day/18) | | | | +| **19** | [Not Enough Minerals](https://adventofcode.com/2022/day/19) | | | | +| **20** | [Grove Positioning System](https://adventofcode.com/2022/day/20) | | | | +| **21** | [Monkey Math](https://adventofcode.com/2022/day/21) | | | | +| **22** | ??? | | | | +| **23** | ??? | | | | +| **24** | ??? | | | | +| **25** | ??? | | | | diff --git a/aoc-2022-dotnet/aoc-2022-dotnet.sln b/aoc-2022-dotnet/aoc-2022-dotnet.sln index e533c60..c8afbfc 100644 --- a/aoc-2022-dotnet/aoc-2022-dotnet.sln +++ b/aoc-2022-dotnet/aoc-2022-dotnet.sln @@ -42,9 +42,11 @@ Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "Day13", "Day13\Day13.fsproj EndProject Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "Day14", "Day14\Day14.fsproj", "{3241E7B6-B58B-4032-9746-DF87B1F0D666}" EndProject -Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "Day15", "Day15\Day15.fsproj", "{52EA45CC-A60B-4B2D-B91F-A7B3874879BB}" +Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "Day15", "Day15\Day15.fsproj", "{52EA45CC-A60B-4B2D-B91F-A7B3874879BB}" EndProject -Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "Day16", "Day16\Day16.fsproj", "{4CABEF49-D9D8-4211-8714-95E118820C8F}" +Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "Day16", "Day16\Day16.fsproj", "{4CABEF49-D9D8-4211-8714-95E118820C8F}" +EndProject +Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "Day17", "Day17\Day17.fsproj", "{7DEA7521-24E1-4ED4-9530-70E91731ADB3}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -124,6 +126,10 @@ Global {4CABEF49-D9D8-4211-8714-95E118820C8F}.Debug|Any CPU.Build.0 = Debug|Any CPU {4CABEF49-D9D8-4211-8714-95E118820C8F}.Release|Any CPU.ActiveCfg = Release|Any CPU {4CABEF49-D9D8-4211-8714-95E118820C8F}.Release|Any CPU.Build.0 = Release|Any CPU + {7DEA7521-24E1-4ED4-9530-70E91731ADB3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {7DEA7521-24E1-4ED4-9530-70E91731ADB3}.Debug|Any CPU.Build.0 = Debug|Any CPU + {7DEA7521-24E1-4ED4-9530-70E91731ADB3}.Release|Any CPU.ActiveCfg = Release|Any CPU + {7DEA7521-24E1-4ED4-9530-70E91731ADB3}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE |