mirror of
https://github.com/Smaug123/AdventOfCode2022
synced 2025-10-06 18:18:40 +00:00
Day 22 and speedups (#34)
This commit is contained in:
@@ -31,6 +31,7 @@
|
|||||||
<EmbeddedResource Include="..\AdventOfCode2022.Test\Inputs\Day19.txt" />
|
<EmbeddedResource Include="..\AdventOfCode2022.Test\Inputs\Day19.txt" />
|
||||||
<EmbeddedResource Include="..\AdventOfCode2022.Test\Inputs\Day20.txt" />
|
<EmbeddedResource Include="..\AdventOfCode2022.Test\Inputs\Day20.txt" />
|
||||||
<EmbeddedResource Include="..\AdventOfCode2022.Test\Inputs\Day21.txt" />
|
<EmbeddedResource Include="..\AdventOfCode2022.Test\Inputs\Day21.txt" />
|
||||||
|
<EmbeddedResource Include="..\AdventOfCode2022.Test\Inputs\Day22.txt" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
@@ -2,5 +2,5 @@ namespace AdventOfCode2022.App
|
|||||||
|
|
||||||
[<RequireQualifiedAccess>]
|
[<RequireQualifiedAccess>]
|
||||||
module Inputs =
|
module Inputs =
|
||||||
let days = Array.init 21 (fun day -> Assembly.readResource $"Day%i{day + 1}.txt")
|
let days = Array.init 22 (fun day -> Assembly.readResource $"Day%i{day + 1}.txt")
|
||||||
let inline day (i : int) = days.[i - 1]
|
let inline day (i : int) = days.[i - 1]
|
||||||
|
@@ -79,7 +79,7 @@ type Benchmark21To25 () =
|
|||||||
[<GlobalSetup>]
|
[<GlobalSetup>]
|
||||||
member _.Setup () = Run.shouldWrite <- false
|
member _.Setup () = Run.shouldWrite <- false
|
||||||
|
|
||||||
[<Params(21)>]
|
[<Params(21, 22)>]
|
||||||
member val Day = 0 with get, set
|
member val Day = 0 with get, set
|
||||||
|
|
||||||
[<Params(false, true)>]
|
[<Params(false, true)>]
|
||||||
|
@@ -303,6 +303,20 @@ module Run =
|
|||||||
if shouldWrite then
|
if shouldWrite then
|
||||||
printfn "%i" output
|
printfn "%i" output
|
||||||
|
|
||||||
|
let day22 (partTwo : bool) (input : string) =
|
||||||
|
let day22 = StringSplitEnumerator.make '\n' input
|
||||||
|
|
||||||
|
if not partTwo then
|
||||||
|
let output = Day22.part1 day22
|
||||||
|
|
||||||
|
if shouldWrite then
|
||||||
|
printfn "%i" output
|
||||||
|
else
|
||||||
|
let output = Day22.part2 day22
|
||||||
|
|
||||||
|
if shouldWrite then
|
||||||
|
printfn "%i" output
|
||||||
|
|
||||||
let allRuns =
|
let allRuns =
|
||||||
[|
|
[|
|
||||||
day1
|
day1
|
||||||
@@ -326,4 +340,5 @@ module Run =
|
|||||||
day19
|
day19
|
||||||
day20
|
day20
|
||||||
day21
|
day21
|
||||||
|
day22
|
||||||
|]
|
|]
|
||||||
|
@@ -29,6 +29,7 @@
|
|||||||
<Compile Include="Day19.fs" />
|
<Compile Include="Day19.fs" />
|
||||||
<Compile Include="Day20.fs" />
|
<Compile Include="Day20.fs" />
|
||||||
<Compile Include="Day21.fs" />
|
<Compile Include="Day21.fs" />
|
||||||
|
<Compile Include="Day22.fs" />
|
||||||
<EmbeddedResource Include="Inputs\Day1.txt" />
|
<EmbeddedResource Include="Inputs\Day1.txt" />
|
||||||
<EmbeddedResource Include="Inputs\Day2.txt" />
|
<EmbeddedResource Include="Inputs\Day2.txt" />
|
||||||
<EmbeddedResource Include="Inputs\Day3.txt" />
|
<EmbeddedResource Include="Inputs\Day3.txt" />
|
||||||
@@ -50,6 +51,7 @@
|
|||||||
<EmbeddedResource Include="Inputs\Day19.txt" />
|
<EmbeddedResource Include="Inputs\Day19.txt" />
|
||||||
<EmbeddedResource Include="Inputs\Day20.txt" />
|
<EmbeddedResource Include="Inputs\Day20.txt" />
|
||||||
<EmbeddedResource Include="Inputs\Day21.txt" />
|
<EmbeddedResource Include="Inputs\Day21.txt" />
|
||||||
|
<EmbeddedResource Include="Inputs\Day22.txt" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
46
AdventOfCode2022.Test/Day22.fs
Normal file
46
AdventOfCode2022.Test/Day22.fs
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
namespace AdventOfCode2022.Test
|
||||||
|
|
||||||
|
open NUnit.Framework
|
||||||
|
open FsUnitTyped
|
||||||
|
open AdventOfCode2022
|
||||||
|
|
||||||
|
[<TestFixture>]
|
||||||
|
module TestDay22 =
|
||||||
|
|
||||||
|
let input =
|
||||||
|
""" ...#
|
||||||
|
.#..
|
||||||
|
#...
|
||||||
|
....
|
||||||
|
...#.......#
|
||||||
|
........#...
|
||||||
|
..#....#....
|
||||||
|
..........#.
|
||||||
|
...#....
|
||||||
|
.....#..
|
||||||
|
.#......
|
||||||
|
......#.
|
||||||
|
|
||||||
|
10R5L5R10L4R5L5
|
||||||
|
"""
|
||||||
|
|
||||||
|
[<Test>]
|
||||||
|
let ``Part 1, given`` () =
|
||||||
|
Day22.part1 (StringSplitEnumerator.make '\n' input) |> shouldEqual 6032
|
||||||
|
|
||||||
|
[<Test>]
|
||||||
|
let ``Part 1`` () =
|
||||||
|
let input = Assembly.readResource "Day22.txt"
|
||||||
|
|
||||||
|
Day22.part1 (StringSplitEnumerator.make '\n' input) |> shouldEqual 103224
|
||||||
|
|
||||||
|
|
||||||
|
[<Test>]
|
||||||
|
let ``Part 2, given`` () =
|
||||||
|
Day22.part2Example (StringSplitEnumerator.make '\n' input) |> shouldEqual 5031
|
||||||
|
|
||||||
|
[<Test>]
|
||||||
|
let ``Part 2`` () =
|
||||||
|
let input = Assembly.readResource "Day22.txt"
|
||||||
|
|
||||||
|
Day22.part2 (StringSplitEnumerator.make '\n' input) |> shouldEqual 189097
|
202
AdventOfCode2022.Test/Inputs/Day22.txt
Normal file
202
AdventOfCode2022.Test/Inputs/Day22.txt
Normal file
File diff suppressed because one or more lines are too long
@@ -33,6 +33,7 @@
|
|||||||
<Compile Include="Day19.fs" />
|
<Compile Include="Day19.fs" />
|
||||||
<Compile Include="Day20.fs" />
|
<Compile Include="Day20.fs" />
|
||||||
<Compile Include="Day21.fs" />
|
<Compile Include="Day21.fs" />
|
||||||
|
<Compile Include="Day22.fs" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
@@ -11,6 +11,7 @@ open Checked
|
|||||||
#nowarn "9"
|
#nowarn "9"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
[<Struct>]
|
||||||
type Coordinate =
|
type Coordinate =
|
||||||
{
|
{
|
||||||
X : int
|
X : int
|
||||||
|
@@ -12,28 +12,73 @@ open Checked
|
|||||||
[<Struct>]
|
[<Struct>]
|
||||||
[<IsReadOnly>]
|
[<IsReadOnly>]
|
||||||
type Day13Packet =
|
type Day13Packet =
|
||||||
| PacketList of leaf : Day13Packet[]
|
{
|
||||||
| Int of int : int
|
Packet : Day13Packet ResizeArray ValueOption
|
||||||
|
/// If Packet is None, this is an int.
|
||||||
|
/// If Packet is Some, this is the start index of a slice.
|
||||||
|
StartIndexOrInt : int
|
||||||
|
}
|
||||||
|
|
||||||
[<RequireQualifiedAccess>]
|
[<RequireQualifiedAccess>]
|
||||||
module Day13 =
|
module Day13 =
|
||||||
|
|
||||||
/// True if they're in the right order.
|
/// True if they're in the right order.
|
||||||
let rec cmp (packet1 : Day13Packet) (packet2 : Day13Packet) : bool option =
|
let rec cmp (packet1 : Day13Packet) (packet2 : Day13Packet) : bool ValueOption =
|
||||||
match packet1, packet2 with
|
match packet1.Packet, packet2.Packet with
|
||||||
| Day13Packet.Int i1, Day13Packet.Int i2 ->
|
| ValueNone, ValueNone ->
|
||||||
if i1 < i2 then Some true
|
if packet1.StartIndexOrInt < packet2.StartIndexOrInt then
|
||||||
elif i1 > i2 then Some false
|
ValueSome true
|
||||||
else None
|
elif packet1.StartIndexOrInt > packet2.StartIndexOrInt then
|
||||||
| PacketList [||], PacketList [||] -> None
|
ValueSome false
|
||||||
| PacketList [||], PacketList _ -> Some true
|
else
|
||||||
| PacketList _, PacketList [||] -> Some false
|
ValueNone
|
||||||
| PacketList arr1, PacketList arr2 ->
|
| ValueSome arr1, ValueSome arr2 ->
|
||||||
match cmp arr1.[0] arr2.[0] with
|
if packet1.StartIndexOrInt = arr1.Count then
|
||||||
| Some v -> Some v
|
if packet2.StartIndexOrInt = arr2.Count then
|
||||||
| None -> cmp (PacketList arr1.[1..]) (PacketList arr2.[1..])
|
ValueNone
|
||||||
| PacketList _, Int _ -> cmp packet1 (PacketList [| packet2 |])
|
else
|
||||||
| Int _, PacketList _ -> cmp (PacketList [| packet1 |]) packet2
|
ValueSome true
|
||||||
|
elif packet2.StartIndexOrInt = arr2.Count then
|
||||||
|
ValueSome false
|
||||||
|
else
|
||||||
|
match cmp arr1.[packet1.StartIndexOrInt] arr2.[packet2.StartIndexOrInt] with
|
||||||
|
| ValueSome v -> ValueSome v
|
||||||
|
| ValueNone ->
|
||||||
|
let advanced1 =
|
||||||
|
{
|
||||||
|
Packet = ValueSome arr1
|
||||||
|
StartIndexOrInt = packet1.StartIndexOrInt + 1
|
||||||
|
}
|
||||||
|
|
||||||
|
let advanced2 =
|
||||||
|
{
|
||||||
|
Packet = ValueSome arr2
|
||||||
|
StartIndexOrInt = packet2.StartIndexOrInt + 1
|
||||||
|
}
|
||||||
|
|
||||||
|
cmp advanced1 advanced2
|
||||||
|
| ValueSome arr1, ValueNone ->
|
||||||
|
if packet1.StartIndexOrInt = arr1.Count then
|
||||||
|
ValueSome true
|
||||||
|
else
|
||||||
|
match cmp arr1.[packet1.StartIndexOrInt] packet2 with
|
||||||
|
| ValueSome v -> ValueSome v
|
||||||
|
| ValueNone ->
|
||||||
|
if packet1.StartIndexOrInt + 1 = arr1.Count then
|
||||||
|
ValueNone
|
||||||
|
else
|
||||||
|
ValueSome false
|
||||||
|
| ValueNone, ValueSome arr2 ->
|
||||||
|
if packet2.StartIndexOrInt = arr2.Count then
|
||||||
|
ValueSome false
|
||||||
|
else
|
||||||
|
match cmp packet1 arr2.[packet2.StartIndexOrInt] with
|
||||||
|
| ValueSome v -> ValueSome v
|
||||||
|
| ValueNone ->
|
||||||
|
if packet2.StartIndexOrInt + 1 = arr2.Count then
|
||||||
|
ValueNone
|
||||||
|
else
|
||||||
|
ValueSome true
|
||||||
|
|
||||||
let parse (lines : StringSplitEnumerator) : Day13Packet ResizeArray =
|
let parse (lines : StringSplitEnumerator) : Day13Packet ResizeArray =
|
||||||
use mutable enum = lines
|
use mutable enum = lines
|
||||||
@@ -54,12 +99,20 @@ module Day13 =
|
|||||||
curr <- curr.Slice 1
|
curr <- curr.Slice 1
|
||||||
|
|
||||||
if curr.[0] <> ']' then
|
if curr.[0] <> ']' then
|
||||||
stack
|
let int =
|
||||||
.Peek()
|
{
|
||||||
.Add (Day13Packet.Int (Int32.Parse (curr.TrimEnd ']', NumberStyles.None)))
|
StartIndexOrInt = Int32.Parse (curr.TrimEnd ']', NumberStyles.None)
|
||||||
|
Packet = ValueNone
|
||||||
|
}
|
||||||
|
|
||||||
|
stack.Peek().Add int
|
||||||
|
|
||||||
while curr.Length > 0 && curr.[curr.Length - 1] = ']' do
|
while curr.Length > 0 && curr.[curr.Length - 1] = ']' do
|
||||||
let closed = Day13Packet.PacketList (stack.Pop().ToArray ())
|
let closed =
|
||||||
|
{
|
||||||
|
Packet = ValueSome (stack.Pop ())
|
||||||
|
StartIndexOrInt = 0
|
||||||
|
}
|
||||||
|
|
||||||
if stack.Count = 0 then
|
if stack.Count = 0 then
|
||||||
output.Add closed
|
output.Add closed
|
||||||
@@ -77,39 +130,66 @@ module Day13 =
|
|||||||
|
|
||||||
for i in 0..2 .. data.Count - 1 do
|
for i in 0..2 .. data.Count - 1 do
|
||||||
match cmp data.[i] data.[i + 1] with
|
match cmp data.[i] data.[i + 1] with
|
||||||
| None -> failwith "should have decided"
|
| ValueNone -> failwith "should have decided"
|
||||||
| Some false -> ()
|
| ValueSome false -> ()
|
||||||
| Some true -> sum <- sum + (i / 2 + 1)
|
| ValueSome true -> sum <- sum + (i / 2 + 1)
|
||||||
|
|
||||||
sum
|
sum
|
||||||
|
|
||||||
|
|
||||||
let part2 (lines : StringSplitEnumerator) : int =
|
let part2 (lines : StringSplitEnumerator) : int =
|
||||||
let data = parse lines
|
let data = parse lines
|
||||||
|
|
||||||
let marker1 =
|
let marker1 =
|
||||||
Day13Packet.PacketList [| Day13Packet.PacketList [| Day13Packet.Int 2 |] |]
|
let arr = ResizeArray 1
|
||||||
|
let arr2 = ResizeArray 1
|
||||||
|
|
||||||
data.Add marker1
|
arr2.Add
|
||||||
|
{
|
||||||
|
StartIndexOrInt = 2
|
||||||
|
Packet = ValueNone
|
||||||
|
}
|
||||||
|
|
||||||
|
arr.Add
|
||||||
|
{
|
||||||
|
StartIndexOrInt = 0
|
||||||
|
Packet = ValueSome arr2
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
Packet = ValueSome arr
|
||||||
|
StartIndexOrInt = 0
|
||||||
|
}
|
||||||
|
|
||||||
let marker2 =
|
let marker2 =
|
||||||
Day13Packet.PacketList [| Day13Packet.PacketList [| Day13Packet.Int 6 |] |]
|
let arr = ResizeArray 1
|
||||||
|
let arr2 = ResizeArray 1
|
||||||
|
|
||||||
data.Add marker2
|
arr2.Add
|
||||||
let data = data.ToArray () |> Array.indexed
|
{
|
||||||
Array.sortInPlaceWith (fun (_, a) (_, b) -> if Option.get (cmp a b) then -1 else 1) data
|
StartIndexOrInt = 6
|
||||||
|
Packet = ValueNone
|
||||||
|
}
|
||||||
|
|
||||||
let mutable answer = 1
|
arr.Add
|
||||||
let mutable keepGoing = true
|
{
|
||||||
let mutable i = 0
|
StartIndexOrInt = 0
|
||||||
|
Packet = ValueSome arr2
|
||||||
|
}
|
||||||
|
|
||||||
while keepGoing do
|
{
|
||||||
if answer = 1 && fst data.[i] = data.Length - 2 then
|
Packet = ValueSome arr
|
||||||
answer <- answer * (i + 1)
|
StartIndexOrInt = 0
|
||||||
elif fst data.[i] = data.Length - 1 then
|
}
|
||||||
answer <- answer * (i + 1)
|
|
||||||
keepGoing <- false
|
|
||||||
|
|
||||||
i <- i + 1
|
let mutable howManyLessThan = 0
|
||||||
|
let mutable howManyGreaterThan = 0
|
||||||
|
|
||||||
answer
|
for i in 0 .. data.Count - 1 do
|
||||||
|
match cmp data.[i] marker1 with
|
||||||
|
| ValueSome true -> howManyLessThan <- howManyLessThan + 1
|
||||||
|
| _ ->
|
||||||
|
match cmp marker2 data.[i] with
|
||||||
|
| ValueSome true -> howManyGreaterThan <- howManyGreaterThan + 1
|
||||||
|
| _ -> ()
|
||||||
|
|
||||||
|
(howManyLessThan + 1) * (data.Count - howManyGreaterThan + 2)
|
||||||
|
@@ -14,6 +14,13 @@ open Checked
|
|||||||
|
|
||||||
type Day14Shape = Coordinate ResizeArray
|
type Day14Shape = Coordinate ResizeArray
|
||||||
|
|
||||||
|
[<RequireQualifiedAccess>]
|
||||||
|
type MutableCoordinate =
|
||||||
|
{
|
||||||
|
mutable X : int
|
||||||
|
mutable Y : int
|
||||||
|
}
|
||||||
|
|
||||||
[<RequireQualifiedAccess>]
|
[<RequireQualifiedAccess>]
|
||||||
module Day14 =
|
module Day14 =
|
||||||
|
|
||||||
@@ -33,7 +40,7 @@ module Day14 =
|
|||||||
let y = StringSplitEnumerator.consumeInt &coords
|
let y = StringSplitEnumerator.consumeInt &coords
|
||||||
|
|
||||||
{
|
{
|
||||||
X = x
|
Coordinate.X = x
|
||||||
Y = y
|
Y = y
|
||||||
}
|
}
|
||||||
|> thisLine.Add
|
|> thisLine.Add
|
||||||
@@ -55,12 +62,6 @@ module Day14 =
|
|||||||
for x = min point1.X point2.X to max point1.X point2.X do
|
for x = min point1.X point2.X to max point1.X point2.X do
|
||||||
Arr2D.set arr x point1.Y true
|
Arr2D.set arr x point1.Y true
|
||||||
|
|
||||||
type MutableCoordinate =
|
|
||||||
{
|
|
||||||
mutable X : int
|
|
||||||
mutable Y : int
|
|
||||||
}
|
|
||||||
|
|
||||||
let inline fallOnce (sandPos : MutableCoordinate) (arr : Arr2D<bool>) : bool =
|
let inline fallOnce (sandPos : MutableCoordinate) (arr : Arr2D<bool>) : bool =
|
||||||
if not (Arr2D.get arr sandPos.X (sandPos.Y + 1)) then
|
if not (Arr2D.get arr sandPos.X (sandPos.Y + 1)) then
|
||||||
sandPos.Y <- sandPos.Y + 1
|
sandPos.Y <- sandPos.Y + 1
|
||||||
@@ -101,7 +102,7 @@ module Day14 =
|
|||||||
let sandPos =
|
let sandPos =
|
||||||
{
|
{
|
||||||
MutableCoordinate.X = 500
|
MutableCoordinate.X = 500
|
||||||
Y = 0
|
MutableCoordinate.Y = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
let mutable stillFalling = true
|
let mutable stillFalling = true
|
||||||
@@ -166,7 +167,7 @@ module Day14 =
|
|||||||
let sandPos =
|
let sandPos =
|
||||||
{
|
{
|
||||||
MutableCoordinate.X = 1000
|
MutableCoordinate.X = 1000
|
||||||
Y = 0
|
MutableCoordinate.Y = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
let mutable stillFalling = true
|
let mutable stillFalling = true
|
||||||
|
@@ -79,14 +79,13 @@ module Day15 =
|
|||||||
keepGoing
|
keepGoing
|
||||||
|
|
||||||
let toHashSet (arr : Coordinate ResizeArray) : Coordinate HashSet =
|
let toHashSet (arr : Coordinate ResizeArray) : Coordinate HashSet =
|
||||||
let output = HashSet ()
|
let output = HashSet arr.Count
|
||||||
|
|
||||||
for beacon in arr do
|
for beacon in arr do
|
||||||
output.Add beacon |> ignore
|
output.Add beacon |> ignore
|
||||||
|
|
||||||
output
|
output
|
||||||
|
|
||||||
|
|
||||||
let part1 (y : int) (lines : StringSplitEnumerator) : int =
|
let part1 (y : int) (lines : StringSplitEnumerator) : int =
|
||||||
let sensors, beacons = parse lines
|
let sensors, beacons = parse lines
|
||||||
|
|
||||||
|
@@ -31,7 +31,6 @@ module Day21 =
|
|||||||
type Day21Input =
|
type Day21Input =
|
||||||
| Literal of int
|
| Literal of int
|
||||||
| Operation of Day21Name * Day21Name * Day21Operation
|
| Operation of Day21Name * Day21Name * Day21Operation
|
||||||
| Calculated of float
|
|
||||||
|
|
||||||
/// Returns the name of the root node and human node, too.
|
/// Returns the name of the root node and human node, too.
|
||||||
let parse (line : StringSplitEnumerator) : Dictionary<Day21Name, Day21Input> * Day21Name * Day21Name =
|
let parse (line : StringSplitEnumerator) : Dictionary<Day21Name, Day21Input> * Day21Name * Day21Name =
|
||||||
@@ -77,20 +76,28 @@ module Day21 =
|
|||||||
| Day21Operation.Divide -> v1 / v2
|
| Day21Operation.Divide -> v1 / v2
|
||||||
| _ -> failwith "bad enum"
|
| _ -> failwith "bad enum"
|
||||||
|
|
||||||
let rec evaluate (d : Dictionary<Day21Name, Day21Input>) (s : Day21Name) : float =
|
let rec evaluate
|
||||||
|
(calculated : Dictionary<Day21Name, float>)
|
||||||
|
(d : Dictionary<Day21Name, Day21Input>)
|
||||||
|
(s : Day21Name)
|
||||||
|
: float
|
||||||
|
=
|
||||||
|
match calculated.TryGetValue s with
|
||||||
|
| true, v -> v
|
||||||
|
| false, _ ->
|
||||||
|
|
||||||
match d.[s] with
|
match d.[s] with
|
||||||
| Day21Input.Literal v ->
|
| Day21Input.Literal v ->
|
||||||
let result = float v
|
let result = float v
|
||||||
d.[s] <- Day21Input.Calculated result
|
calculated.[s] <- result
|
||||||
result
|
result
|
||||||
| Day21Input.Calculated f -> f
|
|
||||||
| Day21Input.Operation (s1, s2, op) ->
|
| Day21Input.Operation (s1, s2, op) ->
|
||||||
let v1 = evaluate d s1
|
let v1 = evaluate calculated d s1
|
||||||
let v2 = evaluate d s2
|
let v2 = evaluate calculated d s2
|
||||||
|
|
||||||
let result = compute v1 v2 op
|
let result = compute v1 v2 op
|
||||||
|
|
||||||
d.[s] <- Day21Input.Calculated result
|
calculated.[s] <- result
|
||||||
result
|
result
|
||||||
|
|
||||||
let inline round (v : float) : int64 =
|
let inline round (v : float) : int64 =
|
||||||
@@ -103,8 +110,9 @@ module Day21 =
|
|||||||
|
|
||||||
let part1 (lines : StringSplitEnumerator) : int64 =
|
let part1 (lines : StringSplitEnumerator) : int64 =
|
||||||
let original, root, _ = parse lines
|
let original, root, _ = parse lines
|
||||||
|
let calculated = Dictionary original.Count
|
||||||
|
|
||||||
let result = evaluate original root
|
let result = evaluate calculated original root
|
||||||
|
|
||||||
round result
|
round result
|
||||||
|
|
||||||
@@ -135,7 +143,6 @@ module Day21 =
|
|||||||
let answer = Day21Expr.Literal (float v)
|
let answer = Day21Expr.Literal (float v)
|
||||||
result.[key] <- answer
|
result.[key] <- answer
|
||||||
answer
|
answer
|
||||||
| Day21Input.Calculated _ -> failwith "no never"
|
|
||||||
| Day21Input.Operation (s1, s2, op) ->
|
| Day21Input.Operation (s1, s2, op) ->
|
||||||
let v1 = convert human s1 d result
|
let v1 = convert human s1 d result
|
||||||
let v2 = convert human s2 d result
|
let v2 = convert human s2 d result
|
||||||
@@ -153,8 +160,7 @@ module Day21 =
|
|||||||
|
|
||||||
let lhs, rhs =
|
let lhs, rhs =
|
||||||
match original.[root] with
|
match original.[root] with
|
||||||
| Day21Input.Literal _
|
| Day21Input.Literal _ -> failwith "expected operation"
|
||||||
| Day21Input.Calculated _ -> failwith "expected operation"
|
|
||||||
| Day21Input.Operation (s1, s2, _) -> s1, s2
|
| Day21Input.Operation (s1, s2, _) -> s1, s2
|
||||||
|
|
||||||
let converted = Dictionary original.Count
|
let converted = Dictionary original.Count
|
||||||
|
550
AdventOfCode2022/Day22.fs
Normal file
550
AdventOfCode2022/Day22.fs
Normal file
@@ -0,0 +1,550 @@
|
|||||||
|
namespace AdventOfCode2022
|
||||||
|
|
||||||
|
open System
|
||||||
|
|
||||||
|
#if DEBUG
|
||||||
|
open Checked
|
||||||
|
#else
|
||||||
|
#nowarn "9"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
[<RequireQualifiedAccess>]
|
||||||
|
module Day22 =
|
||||||
|
|
||||||
|
/// Returns the board (where 0 means "nothing here", 1 means "space", 2 means "wall"),
|
||||||
|
/// the set of instructions (move * change-direction), and the final trailing instruction to move.
|
||||||
|
let parse (line : StringSplitEnumerator) : int[][] * ResizeArray<struct (int * Direction)> * int =
|
||||||
|
use mutable enum = line.GetEnumerator ()
|
||||||
|
let output = ResizeArray ()
|
||||||
|
|
||||||
|
let mutable maxBoardLength = 0
|
||||||
|
let row = ResizeArray ()
|
||||||
|
// 2 here in case there's a trailing \r
|
||||||
|
while enum.MoveNext () && enum.Current.Length >= 2 do
|
||||||
|
for i = 0 to enum.Current.Length - 1 do
|
||||||
|
match enum.Current.[i] with
|
||||||
|
| ' ' -> row.Add 0
|
||||||
|
| '.' -> row.Add 1
|
||||||
|
| '#' -> row.Add 2
|
||||||
|
| '\r' -> ()
|
||||||
|
| c -> failwithf "unexpected char: %c" c
|
||||||
|
|
||||||
|
output.Add (row.ToArray ())
|
||||||
|
maxBoardLength <- max maxBoardLength row.Count
|
||||||
|
row.Clear ()
|
||||||
|
|
||||||
|
if not (enum.MoveNext ()) then
|
||||||
|
failwith "expected instruction line"
|
||||||
|
|
||||||
|
let directions = ResizeArray ()
|
||||||
|
let line = enum.Current.TrimEnd ()
|
||||||
|
let mutable i = 0
|
||||||
|
|
||||||
|
for count = 0 to line.Length - 1 do
|
||||||
|
if '0' <= line.[count] && line.[count] <= '9' then
|
||||||
|
i <- i * 10 + (int line.[count] - int '0')
|
||||||
|
else
|
||||||
|
let dir =
|
||||||
|
match line.[count] with
|
||||||
|
| 'L' -> Direction.Left
|
||||||
|
| 'R' -> Direction.Right
|
||||||
|
| c -> failwithf "Unexpected: %c" c
|
||||||
|
|
||||||
|
directions.Add (struct (i, dir))
|
||||||
|
i <- 0
|
||||||
|
|
||||||
|
let finalOutput =
|
||||||
|
Array.init
|
||||||
|
output.Count
|
||||||
|
(fun i -> Array.append output.[i] (Array.zeroCreate (maxBoardLength - output.[i].Length)))
|
||||||
|
|
||||||
|
finalOutput, directions, i
|
||||||
|
|
||||||
|
let inline rotateRight (dir : Direction) =
|
||||||
|
match dir with
|
||||||
|
| Direction.Up -> Direction.Right
|
||||||
|
| Direction.Right -> Direction.Down
|
||||||
|
| Direction.Down -> Direction.Left
|
||||||
|
| Direction.Left -> Direction.Up
|
||||||
|
| _ -> failwith "bad direction"
|
||||||
|
|
||||||
|
let inline rotateLeft (dir : Direction) =
|
||||||
|
match dir with
|
||||||
|
| Direction.Up -> Direction.Left
|
||||||
|
| Direction.Right -> Direction.Up
|
||||||
|
| Direction.Down -> Direction.Right
|
||||||
|
| Direction.Left -> Direction.Down
|
||||||
|
| _ -> failwith "bad direction"
|
||||||
|
|
||||||
|
/// Returns false if we got stuck due to a wall.
|
||||||
|
let private moveOneStep (currPos : MutableCoordinate) (direction : Direction) (board : int[][]) : bool =
|
||||||
|
let answer =
|
||||||
|
{
|
||||||
|
MutableCoordinate.X = currPos.X
|
||||||
|
MutableCoordinate.Y = currPos.Y
|
||||||
|
}
|
||||||
|
|
||||||
|
match direction with
|
||||||
|
| Direction.Up ->
|
||||||
|
if answer.Y = 0 then
|
||||||
|
answer.Y <- board.Length - 1
|
||||||
|
else
|
||||||
|
answer.Y <- answer.Y - 1
|
||||||
|
|
||||||
|
while board.[answer.Y].[answer.X] = 0 do
|
||||||
|
if answer.Y = 0 then
|
||||||
|
answer.Y <- board.Length - 1
|
||||||
|
else
|
||||||
|
answer.Y <- answer.Y - 1
|
||||||
|
| Direction.Down ->
|
||||||
|
if answer.Y = board.Length - 1 then
|
||||||
|
answer.Y <- 0
|
||||||
|
else
|
||||||
|
answer.Y <- answer.Y + 1
|
||||||
|
|
||||||
|
while board.[answer.Y].[answer.X] = 0 do
|
||||||
|
if answer.Y = board.Length - 1 then
|
||||||
|
answer.Y <- 0
|
||||||
|
else
|
||||||
|
answer.Y <- answer.Y + 1
|
||||||
|
| Direction.Left ->
|
||||||
|
if answer.X = 0 then
|
||||||
|
answer.X <- board.[0].Length - 1
|
||||||
|
else
|
||||||
|
answer.X <- answer.X - 1
|
||||||
|
|
||||||
|
while board.[answer.Y].[answer.X] = 0 do
|
||||||
|
if answer.X = 0 then
|
||||||
|
answer.X <- board.[0].Length - 1
|
||||||
|
else
|
||||||
|
answer.X <- answer.X - 1
|
||||||
|
| Direction.Right ->
|
||||||
|
if answer.X = board.[0].Length - 1 then
|
||||||
|
answer.X <- 0
|
||||||
|
else
|
||||||
|
answer.X <- answer.X + 1
|
||||||
|
|
||||||
|
while board.[answer.Y].[answer.X] = 0 do
|
||||||
|
if answer.X = board.[0].Length - 1 then
|
||||||
|
answer.X <- 0
|
||||||
|
else
|
||||||
|
answer.X <- answer.X + 1
|
||||||
|
| _ -> failwith "noooo"
|
||||||
|
|
||||||
|
if board.[answer.Y].[answer.X] <> 2 then
|
||||||
|
currPos.X <- answer.X
|
||||||
|
currPos.Y <- answer.Y
|
||||||
|
true
|
||||||
|
else
|
||||||
|
false
|
||||||
|
|
||||||
|
let moveDistance (currPos : MutableCoordinate) (direction : Direction) (distance : int) (board : int[][]) : unit =
|
||||||
|
let mutable i = 0
|
||||||
|
let mutable keepGoing = true
|
||||||
|
|
||||||
|
while keepGoing && i < distance do
|
||||||
|
keepGoing <- moveOneStep currPos direction board
|
||||||
|
i <- i + 1
|
||||||
|
|
||||||
|
let inline answer (position : Coordinate) (direction : Direction) =
|
||||||
|
let finalFacing =
|
||||||
|
match direction with
|
||||||
|
| Direction.Right -> 0
|
||||||
|
| Direction.Down -> 1
|
||||||
|
| Direction.Left -> 2
|
||||||
|
| Direction.Up -> 3
|
||||||
|
| _ -> failwith "oh no"
|
||||||
|
|
||||||
|
1000 * (position.Y + 1) + 4 * (position.X + 1) + finalFacing
|
||||||
|
|
||||||
|
let part1 (lines : StringSplitEnumerator) : int =
|
||||||
|
let board, instructions, finalDistance = parse lines
|
||||||
|
|
||||||
|
let position =
|
||||||
|
{
|
||||||
|
MutableCoordinate.Y = 0
|
||||||
|
MutableCoordinate.X = Array.IndexOf (board.[0], 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
let mutable direction = Direction.Right
|
||||||
|
|
||||||
|
for struct (distance, rotation) in instructions do
|
||||||
|
moveDistance position direction distance board
|
||||||
|
|
||||||
|
direction <-
|
||||||
|
match rotation with
|
||||||
|
| Direction.Right -> rotateRight direction
|
||||||
|
| Direction.Left -> rotateLeft direction
|
||||||
|
| _ -> failwith "bad rotation"
|
||||||
|
|
||||||
|
moveDistance position direction finalDistance board
|
||||||
|
|
||||||
|
answer
|
||||||
|
{
|
||||||
|
X = position.X
|
||||||
|
Y = position.Y
|
||||||
|
}
|
||||||
|
direction
|
||||||
|
|
||||||
|
/// If we walk off the given number of face in the given direction, where do we end up?
|
||||||
|
/// Returns an additional "true" if we need to interchange Y and X.
|
||||||
|
let newFaceOnExample
|
||||||
|
(cubeSize : int)
|
||||||
|
(face : int)
|
||||||
|
(direction : Direction)
|
||||||
|
: int * Direction * (struct (int * int) -> struct (int * int))
|
||||||
|
=
|
||||||
|
match face, direction with
|
||||||
|
| 1, Direction.Up -> 2, Direction.Down, (fun (struct (x, y)) -> struct (cubeSize - x - 1, 0))
|
||||||
|
| 1, Direction.Down -> 4, Direction.Down, (fun (struct (x, _)) -> struct (x, 0))
|
||||||
|
| 1, Direction.Left -> 3, Direction.Down, (fun (struct (_, y)) -> struct (y, 0))
|
||||||
|
| 1, Direction.Right -> 6, Direction.Left, (fun (struct (x, y)) -> struct (cubeSize - 1, cubeSize - y - 1))
|
||||||
|
| 2, Direction.Up -> 1, Direction.Down, (fun (struct (x, y)) -> struct (cubeSize - x - 1, 0))
|
||||||
|
| 2, Direction.Down -> 5, Direction.Up, (fun (struct (x, y)) -> struct (cubeSize - x - 1, cubeSize - 1))
|
||||||
|
| 2, Direction.Left -> 6, Direction.Up, (fun (struct (_, y)) -> struct (cubeSize - y - 1, cubeSize - 1))
|
||||||
|
| 2, Direction.Right -> 3, Direction.Right, (fun (struct (x, y)) -> struct (0, y))
|
||||||
|
| 3, Direction.Up -> 1, Direction.Right, (fun (struct (x, y)) -> struct (0, x))
|
||||||
|
| 3, Direction.Down -> 5, Direction.Right, (fun (struct (x, y)) -> struct (0, cubeSize - 1 - y))
|
||||||
|
| 3, Direction.Left -> 2, Direction.Left, (fun (struct (x, y)) -> struct (cubeSize - 1, y))
|
||||||
|
| 3, Direction.Right -> 4, Direction.Right, (fun (struct (x, y)) -> struct (0, y))
|
||||||
|
| 4, Direction.Up -> 1, Direction.Up, (fun (struct (x, _)) -> struct (x, cubeSize - 1))
|
||||||
|
| 4, Direction.Down -> 5, Direction.Down, (fun (struct (x, _)) -> struct (x, 0))
|
||||||
|
| 4, Direction.Left -> 3, Direction.Left, (fun (struct (x, _)) -> struct (x, cubeSize - 1))
|
||||||
|
| 4, Direction.Right -> 6, Direction.Down, (fun (struct (_, y)) -> struct (cubeSize - 1 - y, 0))
|
||||||
|
| 5, Direction.Up -> 4, Direction.Up, (fun (struct (x, y)) -> struct (x, cubeSize - 1))
|
||||||
|
| 5, Direction.Down -> 2, Direction.Up, (fun (struct (x, y)) -> struct (cubeSize - x - 1, cubeSize - 1))
|
||||||
|
| 5, Direction.Left -> 3, Direction.Up, (fun (struct (x, y)) -> struct (cubeSize - y - 1, cubeSize - 1))
|
||||||
|
| 5, Direction.Right -> 6, Direction.Right, (fun (struct (x, y)) -> struct (0, y))
|
||||||
|
| 6, Direction.Up -> 4, Direction.Left, (fun (struct (x, y)) -> struct (cubeSize - 1, cubeSize - x - 1))
|
||||||
|
| 6, Direction.Down -> 2, Direction.Right, (fun (struct (x, y)) -> failwith "TODO")
|
||||||
|
| 6, Direction.Left -> 5, Direction.Left, (fun (struct (x, y)) -> struct (cubeSize - 1, y))
|
||||||
|
| 6, Direction.Right -> 1, Direction.Left, (fun (struct (x, y)) -> failwith "TODO")
|
||||||
|
| _ -> failwith "bad face"
|
||||||
|
|
||||||
|
let inline toArrayElementOnExample (faceSize : int) (face : int) (position : Coordinate) : Coordinate =
|
||||||
|
match face with
|
||||||
|
| 1 ->
|
||||||
|
{
|
||||||
|
X = position.X + 2 * faceSize
|
||||||
|
Y = position.Y
|
||||||
|
}
|
||||||
|
| 2 ->
|
||||||
|
{
|
||||||
|
X = position.X
|
||||||
|
Y = position.Y + faceSize
|
||||||
|
}
|
||||||
|
| 3 ->
|
||||||
|
{
|
||||||
|
X = position.X + faceSize
|
||||||
|
Y = position.Y + faceSize
|
||||||
|
}
|
||||||
|
| 4 ->
|
||||||
|
{
|
||||||
|
X = position.X + 2 * faceSize
|
||||||
|
Y = position.Y + faceSize
|
||||||
|
}
|
||||||
|
| 5 ->
|
||||||
|
{
|
||||||
|
X = position.X + 2 * faceSize
|
||||||
|
Y = position.Y + 2 * faceSize
|
||||||
|
}
|
||||||
|
| 6 ->
|
||||||
|
{
|
||||||
|
X = position.X + 3 * faceSize
|
||||||
|
Y = position.Y + 2 * faceSize
|
||||||
|
}
|
||||||
|
| _ -> failwith "bad face"
|
||||||
|
|
||||||
|
/// Returns false if we got stuck due to a wall.
|
||||||
|
/// The position is referring to the position within the given face.
|
||||||
|
let inline private moveOneStepCube
|
||||||
|
(cubeSize : int)
|
||||||
|
([<InlineIfLambda>] toArrayElement : int -> Coordinate -> Coordinate)
|
||||||
|
([<InlineIfLambda>] newFace : int -> Direction -> int * Direction * (struct (int * int) -> struct (int * int)))
|
||||||
|
(currFace : byref<int>)
|
||||||
|
(currPos : MutableCoordinate)
|
||||||
|
(direction : byref<Direction>)
|
||||||
|
(board : int[][])
|
||||||
|
: bool
|
||||||
|
=
|
||||||
|
// If we do walk off this face, where do we end up?
|
||||||
|
let faceAfterSpill, directionAfterSpill, transformPosition =
|
||||||
|
newFace currFace direction
|
||||||
|
|
||||||
|
let intendedDest, face, newDirection =
|
||||||
|
match direction with
|
||||||
|
| Direction.Up ->
|
||||||
|
if currPos.Y = 0 then
|
||||||
|
let struct (x, y) = transformPosition (struct (currPos.X, currPos.Y))
|
||||||
|
|
||||||
|
{
|
||||||
|
X = x
|
||||||
|
Y = y
|
||||||
|
},
|
||||||
|
faceAfterSpill,
|
||||||
|
directionAfterSpill
|
||||||
|
else
|
||||||
|
{
|
||||||
|
X = currPos.X
|
||||||
|
Y = currPos.Y - 1
|
||||||
|
},
|
||||||
|
currFace,
|
||||||
|
direction
|
||||||
|
| Direction.Down ->
|
||||||
|
if currPos.Y = cubeSize - 1 then
|
||||||
|
let struct (x, y) = transformPosition (struct (currPos.X, currPos.Y))
|
||||||
|
|
||||||
|
{
|
||||||
|
X = x
|
||||||
|
Y = y
|
||||||
|
},
|
||||||
|
faceAfterSpill,
|
||||||
|
directionAfterSpill
|
||||||
|
else
|
||||||
|
{
|
||||||
|
X = currPos.X
|
||||||
|
Y = currPos.Y + 1
|
||||||
|
},
|
||||||
|
currFace,
|
||||||
|
direction
|
||||||
|
| Direction.Left ->
|
||||||
|
if currPos.X = 0 then
|
||||||
|
let struct (x, y) = transformPosition (struct (currPos.X, currPos.Y))
|
||||||
|
|
||||||
|
{
|
||||||
|
X = x
|
||||||
|
Y = y
|
||||||
|
},
|
||||||
|
faceAfterSpill,
|
||||||
|
directionAfterSpill
|
||||||
|
else
|
||||||
|
{
|
||||||
|
X = currPos.X - 1
|
||||||
|
Y = currPos.Y
|
||||||
|
},
|
||||||
|
currFace,
|
||||||
|
direction
|
||||||
|
| Direction.Right ->
|
||||||
|
if currPos.X = cubeSize - 1 then
|
||||||
|
let struct (x, y) = transformPosition (struct (currPos.X, currPos.Y))
|
||||||
|
|
||||||
|
{
|
||||||
|
X = x
|
||||||
|
Y = y
|
||||||
|
},
|
||||||
|
faceAfterSpill,
|
||||||
|
directionAfterSpill
|
||||||
|
else
|
||||||
|
{
|
||||||
|
X = currPos.X + 1
|
||||||
|
Y = currPos.Y
|
||||||
|
},
|
||||||
|
currFace,
|
||||||
|
direction
|
||||||
|
| _ -> failwith "noooo"
|
||||||
|
|
||||||
|
let pos = toArrayElement face intendedDest
|
||||||
|
|
||||||
|
if board.[pos.Y].[pos.X] <> 2 then
|
||||||
|
currPos.X <- intendedDest.X
|
||||||
|
currPos.Y <- intendedDest.Y
|
||||||
|
currFace <- face
|
||||||
|
direction <- newDirection
|
||||||
|
true
|
||||||
|
else
|
||||||
|
false
|
||||||
|
|
||||||
|
let inline moveCubeDistance
|
||||||
|
(cubeSize : int)
|
||||||
|
([<InlineIfLambda>] toArrayElement : int -> Coordinate -> Coordinate)
|
||||||
|
([<InlineIfLambda>] newFace : int -> Direction -> int * Direction * (struct (int * int) -> struct (int * int)))
|
||||||
|
(currFace : byref<int>)
|
||||||
|
(currPos : MutableCoordinate)
|
||||||
|
(direction : byref<Direction>)
|
||||||
|
(distance : int)
|
||||||
|
(board : int[][])
|
||||||
|
: unit
|
||||||
|
=
|
||||||
|
let mutable i = 0
|
||||||
|
let mutable keepGoing = true
|
||||||
|
|
||||||
|
while keepGoing && i < distance do
|
||||||
|
keepGoing <- moveOneStepCube cubeSize toArrayElement newFace &currFace currPos &direction board
|
||||||
|
i <- i + 1
|
||||||
|
|
||||||
|
let part2Example (lines : StringSplitEnumerator) : int =
|
||||||
|
let board, instructions, finalDistance = parse lines
|
||||||
|
let faceSize = 4
|
||||||
|
|
||||||
|
let position =
|
||||||
|
{
|
||||||
|
MutableCoordinate.X = 0
|
||||||
|
MutableCoordinate.Y = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
let mutable direction = Direction.Right
|
||||||
|
let mutable face = 1
|
||||||
|
|
||||||
|
for struct (distance, rotation) in instructions do
|
||||||
|
moveCubeDistance
|
||||||
|
faceSize
|
||||||
|
(toArrayElementOnExample faceSize)
|
||||||
|
(newFaceOnExample faceSize)
|
||||||
|
&face
|
||||||
|
position
|
||||||
|
&direction
|
||||||
|
distance
|
||||||
|
board
|
||||||
|
|
||||||
|
direction <-
|
||||||
|
match rotation with
|
||||||
|
| Direction.Right -> rotateRight direction
|
||||||
|
| Direction.Left -> rotateLeft direction
|
||||||
|
| _ -> failwith "bad rotation"
|
||||||
|
|
||||||
|
moveCubeDistance
|
||||||
|
faceSize
|
||||||
|
(toArrayElementOnExample faceSize)
|
||||||
|
(newFaceOnExample faceSize)
|
||||||
|
&face
|
||||||
|
position
|
||||||
|
&direction
|
||||||
|
finalDistance
|
||||||
|
board
|
||||||
|
|
||||||
|
let faceDimension = board.Length / 3
|
||||||
|
|
||||||
|
let position =
|
||||||
|
toArrayElementOnExample
|
||||||
|
faceDimension
|
||||||
|
face
|
||||||
|
{
|
||||||
|
X = position.X
|
||||||
|
Y = position.Y
|
||||||
|
}
|
||||||
|
|
||||||
|
answer position direction
|
||||||
|
|
||||||
|
// The real thing has shape:
|
||||||
|
// _12
|
||||||
|
// _3_
|
||||||
|
// 45_
|
||||||
|
// 6__
|
||||||
|
|
||||||
|
let inline toArrayElement (faceSize : int) (face : int) (position : Coordinate) : Coordinate =
|
||||||
|
match face with
|
||||||
|
| 1 ->
|
||||||
|
{
|
||||||
|
X = position.X + faceSize
|
||||||
|
Y = position.Y
|
||||||
|
}
|
||||||
|
| 2 ->
|
||||||
|
{
|
||||||
|
X = position.X + 2 * faceSize
|
||||||
|
Y = position.Y
|
||||||
|
}
|
||||||
|
| 3 ->
|
||||||
|
{
|
||||||
|
X = position.X + faceSize
|
||||||
|
Y = position.Y + faceSize
|
||||||
|
}
|
||||||
|
| 4 ->
|
||||||
|
{
|
||||||
|
X = position.X
|
||||||
|
Y = position.Y + 2 * faceSize
|
||||||
|
}
|
||||||
|
| 5 ->
|
||||||
|
{
|
||||||
|
X = position.X + faceSize
|
||||||
|
Y = position.Y + 2 * faceSize
|
||||||
|
}
|
||||||
|
| 6 ->
|
||||||
|
{
|
||||||
|
X = position.X
|
||||||
|
Y = position.Y + 3 * faceSize
|
||||||
|
}
|
||||||
|
| _ -> failwith "bad face"
|
||||||
|
|
||||||
|
let inline newFace
|
||||||
|
(cubeSize : int)
|
||||||
|
(face : int)
|
||||||
|
(direction : Direction)
|
||||||
|
: int * Direction * (struct (int * int) -> struct (int * int))
|
||||||
|
=
|
||||||
|
match face, direction with
|
||||||
|
| 1, Direction.Up -> 6, Direction.Right, (fun (struct (x, y)) -> struct (0, x))
|
||||||
|
| 1, Direction.Down -> 3, Direction.Down, (fun (struct (x, _)) -> struct (x, 0))
|
||||||
|
| 1, Direction.Left -> 4, Direction.Right, (fun (struct (x, y)) -> struct (0, cubeSize - 1 - y))
|
||||||
|
| 1, Direction.Right -> 2, Direction.Right, (fun (struct (x, y)) -> struct (0, y))
|
||||||
|
| 2, Direction.Up -> 6, Direction.Up, (fun (struct (x, y)) -> (x, cubeSize - 1))
|
||||||
|
| 2, Direction.Down -> 3, Direction.Left, (fun (struct (x, y)) -> struct (cubeSize - 1, x))
|
||||||
|
| 2, Direction.Left -> 1, Direction.Left, (fun (struct (_, y)) -> struct (cubeSize - 1, y))
|
||||||
|
| 2, Direction.Right -> 5, Direction.Left, (fun (struct (x, y)) -> struct (cubeSize - 1, cubeSize - 1 - y))
|
||||||
|
| 3, Direction.Up -> 1, Direction.Up, (fun (struct (x, y)) -> struct (x, cubeSize - 1))
|
||||||
|
| 3, Direction.Down -> 5, Direction.Down, (fun (struct (x, y)) -> struct (x, 0))
|
||||||
|
| 3, Direction.Left -> 4, Direction.Down, (fun (struct (x, y)) -> struct (y, 0))
|
||||||
|
| 3, Direction.Right -> 2, Direction.Up, (fun (struct (x, y)) -> struct (y, cubeSize - 1))
|
||||||
|
| 4, Direction.Up -> 3, Direction.Right, (fun (struct (x, _)) -> struct (0, x))
|
||||||
|
| 4, Direction.Down -> 6, Direction.Down, (fun (struct (x, _)) -> struct (x, 0))
|
||||||
|
| 4, Direction.Left -> 1, Direction.Right, (fun (struct (x, y)) -> struct (0, cubeSize - 1 - y))
|
||||||
|
| 4, Direction.Right -> 5, Direction.Right, (fun (struct (_, y)) -> struct (0, y))
|
||||||
|
| 5, Direction.Up -> 3, Direction.Up, (fun (struct (x, y)) -> struct (x, cubeSize - 1))
|
||||||
|
| 5, Direction.Down -> 6, Direction.Left, (fun (struct (x, y)) -> struct (cubeSize - 1, x))
|
||||||
|
| 5, Direction.Left -> 4, Direction.Left, (fun (struct (x, y)) -> struct (cubeSize - 1, y))
|
||||||
|
| 5, Direction.Right -> 2, Direction.Left, (fun (struct (x, y)) -> struct (cubeSize - 1, cubeSize - 1 - y))
|
||||||
|
| 6, Direction.Up -> 4, Direction.Up, (fun (struct (x, y)) -> struct (x, cubeSize - 1))
|
||||||
|
| 6, Direction.Down -> 2, Direction.Down, (fun (struct (x, y)) -> struct (x, 0))
|
||||||
|
| 6, Direction.Left -> 1, Direction.Down, (fun (struct (x, y)) -> struct (y, 0))
|
||||||
|
| 6, Direction.Right -> 5, Direction.Up, (fun (struct (x, y)) -> struct (y, cubeSize - 1))
|
||||||
|
| _ -> failwith "bad face"
|
||||||
|
|
||||||
|
let part2 (lines : StringSplitEnumerator) : int =
|
||||||
|
let board, instructions, finalDistance = parse lines
|
||||||
|
let faceSize = board.[0].Length / 3
|
||||||
|
|
||||||
|
let position =
|
||||||
|
{
|
||||||
|
MutableCoordinate.X = 0
|
||||||
|
MutableCoordinate.Y = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
let mutable direction = Direction.Right
|
||||||
|
let mutable face = 1
|
||||||
|
|
||||||
|
for struct (distance, rotation) in instructions do
|
||||||
|
moveCubeDistance
|
||||||
|
faceSize
|
||||||
|
(toArrayElement faceSize)
|
||||||
|
(newFace faceSize)
|
||||||
|
&face
|
||||||
|
position
|
||||||
|
&direction
|
||||||
|
distance
|
||||||
|
board
|
||||||
|
|
||||||
|
direction <-
|
||||||
|
match rotation with
|
||||||
|
| Direction.Right -> rotateRight direction
|
||||||
|
| Direction.Left -> rotateLeft direction
|
||||||
|
| _ -> failwith "bad rotation"
|
||||||
|
|
||||||
|
moveCubeDistance
|
||||||
|
faceSize
|
||||||
|
(toArrayElement faceSize)
|
||||||
|
(newFace faceSize)
|
||||||
|
&face
|
||||||
|
position
|
||||||
|
&direction
|
||||||
|
finalDistance
|
||||||
|
board
|
||||||
|
|
||||||
|
let position =
|
||||||
|
toArrayElement
|
||||||
|
faceSize
|
||||||
|
face
|
||||||
|
{
|
||||||
|
X = position.X
|
||||||
|
Y = position.Y
|
||||||
|
}
|
||||||
|
|
||||||
|
answer position direction
|
@@ -5,7 +5,7 @@ open System
|
|||||||
[<RequireQualifiedAccess>]
|
[<RequireQualifiedAccess>]
|
||||||
module Day6 =
|
module Day6 =
|
||||||
|
|
||||||
let findDuplicateSorted (a : 'a array) : int ValueOption =
|
let inline findDuplicateSorted< ^a when ^a : equality> (a : 'a array) : int ValueOption =
|
||||||
let mutable i = 0
|
let mutable i = 0
|
||||||
let mutable result = ValueNone
|
let mutable result = ValueNone
|
||||||
|
|
||||||
|
@@ -1,37 +1,38 @@
|
|||||||
namespace AdventOfCode2022
|
namespace AdventOfCode2022
|
||||||
|
|
||||||
open System.Collections.Generic
|
|
||||||
open System
|
open System
|
||||||
|
|
||||||
|
#if DEBUG
|
||||||
|
#else
|
||||||
|
#nowarn "9"
|
||||||
|
#endif
|
||||||
|
|
||||||
[<RequireQualifiedAccess>]
|
[<RequireQualifiedAccess>]
|
||||||
module Day8 =
|
module Day8 =
|
||||||
|
|
||||||
let parse (lines : StringSplitEnumerator) : byte[,] =
|
let parse (lines : StringSplitEnumerator) : byte array * int =
|
||||||
use mutable enum = lines
|
use mutable enum = lines
|
||||||
let output = ResizeArray ()
|
let output = ResizeArray ()
|
||||||
|
let mutable lineCount = 0
|
||||||
|
|
||||||
for line in enum do
|
for line in enum do
|
||||||
let line = line.TrimEnd ()
|
let line = line.TrimEnd ()
|
||||||
|
|
||||||
if not (line.IsWhiteSpace ()) then
|
if not (line.IsWhiteSpace ()) then
|
||||||
let arr = Array.zeroCreate line.Length
|
lineCount <- lineCount + 1
|
||||||
let mutable i = 0
|
|
||||||
|
|
||||||
for c in line do
|
for c in line do
|
||||||
arr.[i] <- byte c - byte '0'
|
output.Add (byte c - byte '0')
|
||||||
i <- i + 1
|
|
||||||
|
|
||||||
output.Add arr
|
output.ToArray (), lineCount
|
||||||
|
|
||||||
Array2D.init output.Count output.[0].Length (fun x y -> output.[x].[y])
|
let isVisible (board : Arr2D<byte>) (x : int) (y : int) : bool =
|
||||||
|
|
||||||
let isVisible (board : byte[,]) (x : int) (y : int) : bool =
|
|
||||||
// From the left?
|
// From the left?
|
||||||
let mutable isVisible = true
|
let mutable isVisible = true
|
||||||
let mutable i = 0
|
let mutable i = 0
|
||||||
|
|
||||||
while i < x && isVisible do
|
while i < x && isVisible do
|
||||||
if board.[y, i] >= board.[y, x] then
|
if Arr2D.get board i y >= Arr2D.get board x y then
|
||||||
isVisible <- false
|
isVisible <- false
|
||||||
|
|
||||||
i <- i + 1
|
i <- i + 1
|
||||||
@@ -42,10 +43,10 @@ module Day8 =
|
|||||||
|
|
||||||
// From the right?
|
// From the right?
|
||||||
let mutable isVisible = true
|
let mutable isVisible = true
|
||||||
let mutable i = board.GetLength 1 - 1
|
let mutable i = board.Height - 1
|
||||||
|
|
||||||
while i > x && isVisible do
|
while i > x && isVisible do
|
||||||
if board.[y, i] >= board.[y, x] then
|
if Arr2D.get board i y >= Arr2D.get board x y then
|
||||||
isVisible <- false
|
isVisible <- false
|
||||||
|
|
||||||
i <- i - 1
|
i <- i - 1
|
||||||
@@ -59,7 +60,7 @@ module Day8 =
|
|||||||
let mutable i = 0
|
let mutable i = 0
|
||||||
|
|
||||||
while i < y && isVisible do
|
while i < y && isVisible do
|
||||||
if board.[i, x] >= board.[y, x] then
|
if Arr2D.get board x i >= Arr2D.get board x y then
|
||||||
isVisible <- false
|
isVisible <- false
|
||||||
|
|
||||||
i <- i + 1
|
i <- i + 1
|
||||||
@@ -70,10 +71,10 @@ module Day8 =
|
|||||||
|
|
||||||
// From the bottom?
|
// From the bottom?
|
||||||
let mutable isVisible = true
|
let mutable isVisible = true
|
||||||
let mutable i = board.GetLength 0 - 1
|
let mutable i = board.Width - 1
|
||||||
|
|
||||||
while i > y && isVisible do
|
while i > y && isVisible do
|
||||||
if board.[i, x] >= board.[y, x] then
|
if Arr2D.get board x i >= Arr2D.get board x y then
|
||||||
isVisible <- false
|
isVisible <- false
|
||||||
|
|
||||||
i <- i - 1
|
i <- i - 1
|
||||||
@@ -81,18 +82,34 @@ module Day8 =
|
|||||||
isVisible
|
isVisible
|
||||||
|
|
||||||
let part1 (lines : StringSplitEnumerator) : int =
|
let part1 (lines : StringSplitEnumerator) : int =
|
||||||
let board = parse lines
|
let board, height = parse lines
|
||||||
|
#if DEBUG
|
||||||
|
let board =
|
||||||
|
{
|
||||||
|
Arr2D.Elements = board
|
||||||
|
Width = board.Length / height
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
use p = fixed board
|
||||||
|
|
||||||
|
let board =
|
||||||
|
{
|
||||||
|
Arr2D.Elements = p
|
||||||
|
Length = board.Length
|
||||||
|
Width = board.Length / height
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
let mutable visibleCount = 0
|
let mutable visibleCount = 0
|
||||||
|
|
||||||
for y = 0 to board.GetLength 0 - 1 do
|
for y = 0 to board.Height - 1 do
|
||||||
for x = 0 to board.GetLength 1 - 1 do
|
for x = 0 to board.Width - 1 do
|
||||||
if isVisible board x y then
|
if isVisible board x y then
|
||||||
visibleCount <- visibleCount + 1
|
visibleCount <- visibleCount + 1
|
||||||
|
|
||||||
visibleCount
|
visibleCount
|
||||||
|
|
||||||
let scenicScore (board : byte[,]) (x : int) (y : int) : int =
|
let scenicScore (board : Arr2D<byte>) (x : int) (y : int) : int =
|
||||||
let mutable scenicCount = 0
|
let mutable scenicCount = 0
|
||||||
|
|
||||||
do
|
do
|
||||||
@@ -100,7 +117,7 @@ module Day8 =
|
|||||||
let mutable i = y - 1
|
let mutable i = y - 1
|
||||||
|
|
||||||
while i >= 0 && isVisible do
|
while i >= 0 && isVisible do
|
||||||
if board.[i, x] >= board.[y, x] then
|
if Arr2D.get board x i >= Arr2D.get board x y then
|
||||||
isVisible <- false
|
isVisible <- false
|
||||||
|
|
||||||
scenicCount <- scenicCount + 1
|
scenicCount <- scenicCount + 1
|
||||||
@@ -112,8 +129,8 @@ module Day8 =
|
|||||||
let mutable i = y + 1
|
let mutable i = y + 1
|
||||||
let mutable subCount = 0
|
let mutable subCount = 0
|
||||||
|
|
||||||
while i < board.GetLength 0 && isVisible do
|
while i < board.Height && isVisible do
|
||||||
if board.[i, x] >= board.[y, x] then
|
if Arr2D.get board x i >= Arr2D.get board x y then
|
||||||
isVisible <- false
|
isVisible <- false
|
||||||
|
|
||||||
subCount <- subCount + 1
|
subCount <- subCount + 1
|
||||||
@@ -128,7 +145,7 @@ module Day8 =
|
|||||||
let mutable subCount = 0
|
let mutable subCount = 0
|
||||||
|
|
||||||
while i >= 0 && isVisible do
|
while i >= 0 && isVisible do
|
||||||
if board.[y, i] >= board.[y, x] then
|
if Arr2D.get board i y >= Arr2D.get board x y then
|
||||||
isVisible <- false
|
isVisible <- false
|
||||||
|
|
||||||
subCount <- subCount + 1
|
subCount <- subCount + 1
|
||||||
@@ -142,8 +159,8 @@ module Day8 =
|
|||||||
let mutable i = x + 1
|
let mutable i = x + 1
|
||||||
let mutable subCount = 0
|
let mutable subCount = 0
|
||||||
|
|
||||||
while i < board.GetLength 1 && isVisible do
|
while i < board.Width && isVisible do
|
||||||
if board.[y, i] >= board.[y, x] then
|
if Arr2D.get board i y >= Arr2D.get board x y then
|
||||||
isVisible <- false
|
isVisible <- false
|
||||||
|
|
||||||
subCount <- subCount + 1
|
subCount <- subCount + 1
|
||||||
@@ -156,11 +173,28 @@ module Day8 =
|
|||||||
|
|
||||||
|
|
||||||
let part2 (lines : StringSplitEnumerator) : int =
|
let part2 (lines : StringSplitEnumerator) : int =
|
||||||
let board = parse lines
|
let board, height = parse lines
|
||||||
|
#if DEBUG
|
||||||
|
let board =
|
||||||
|
{
|
||||||
|
Arr2D.Elements = board
|
||||||
|
Width = board.Length / height
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
use p = fixed board
|
||||||
|
|
||||||
|
let board =
|
||||||
|
{
|
||||||
|
Arr2D.Elements = p
|
||||||
|
Length = board.Length
|
||||||
|
Width = board.Length / height
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
let mutable scenicMax = 0
|
let mutable scenicMax = 0
|
||||||
|
|
||||||
for y = 0 to board.GetLength 0 - 1 do
|
for y = 0 to board.Height - 1 do
|
||||||
for x = 0 to board.GetLength 1 - 1 do
|
for x = 0 to board.Width - 1 do
|
||||||
scenicMax <- max scenicMax (scenicScore board x y)
|
scenicMax <- max scenicMax (scenicScore board x y)
|
||||||
|
|
||||||
scenicMax
|
scenicMax
|
||||||
|
@@ -74,7 +74,7 @@ module Day9 =
|
|||||||
tailVisits.Add (struct (0, 0)) |> ignore
|
tailVisits.Add (struct (0, 0)) |> ignore
|
||||||
|
|
||||||
for direction, distance in directions do
|
for direction, distance in directions do
|
||||||
for _ in 1uy .. distance do
|
for _ = 1 to int distance do
|
||||||
let newHead = newHead (fst knots.[0]) (snd knots.[0]) direction
|
let newHead = newHead (fst knots.[0]) (snd knots.[0]) direction
|
||||||
knots.[0] <- newHead
|
knots.[0] <- newHead
|
||||||
|
|
||||||
|
@@ -10,5 +10,5 @@ Apple M1 Max, 1 CPU, 10 logical and 10 physical cores
|
|||||||
```
|
```
|
||||||
| Method | Day | IsPartOne | Mean | Error | StdDev |
|
| Method | Day | IsPartOne | Mean | Error | StdDev |
|
||||||
|---------- |---- |---------- |---------:|---------:|---------:|
|
|---------- |---- |---------- |---------:|---------:|---------:|
|
||||||
| **Benchmark** | **21** | **False** | **678.3 μs** | **13.00 μs** | **15.48 μs** |
|
| **Benchmark** | **21** | **False** | **654.8 μs** | **12.87 μs** | **13.22 μs** |
|
||||||
| **Benchmark** | **21** | **True** | **612.3 μs** | **9.40 μs** | **8.79 μs** |
|
| **Benchmark** | **21** | **True** | **577.8 μs** | **6.50 μs** | **6.08 μs** |
|
||||||
|
@@ -1,3 +1,3 @@
|
|||||||
Method,Job,AnalyzeLaunchVariance,EvaluateOverhead,MaxAbsoluteError,MaxRelativeError,MinInvokeCount,MinIterationTime,OutlierMode,Affinity,EnvironmentVariables,Jit,Platform,PowerPlanMode,Runtime,AllowVeryLargeObjects,Concurrent,CpuGroups,Force,HeapAffinitizeMask,HeapCount,NoAffinitize,RetainVm,Server,Arguments,BuildConfiguration,Clock,EngineFactory,NuGetReferences,Toolchain,IsMutator,InvocationCount,IterationCount,IterationTime,LaunchCount,MaxIterationCount,MaxWarmupIterationCount,MemoryRandomization,MinIterationCount,MinWarmupIterationCount,RunStrategy,UnrollFactor,WarmupCount,Day,IsPartOne,Mean,Error,StdDev
|
Method,Job,AnalyzeLaunchVariance,EvaluateOverhead,MaxAbsoluteError,MaxRelativeError,MinInvokeCount,MinIterationTime,OutlierMode,Affinity,EnvironmentVariables,Jit,Platform,PowerPlanMode,Runtime,AllowVeryLargeObjects,Concurrent,CpuGroups,Force,HeapAffinitizeMask,HeapCount,NoAffinitize,RetainVm,Server,Arguments,BuildConfiguration,Clock,EngineFactory,NuGetReferences,Toolchain,IsMutator,InvocationCount,IterationCount,IterationTime,LaunchCount,MaxIterationCount,MaxWarmupIterationCount,MemoryRandomization,MinIterationCount,MinWarmupIterationCount,RunStrategy,UnrollFactor,WarmupCount,Day,IsPartOne,Mean,Error,StdDev
|
||||||
Benchmark,DefaultJob,False,Default,Default,Default,Default,Default,Default,0000000000,Empty,RyuJit,Arm64,8c5e7fda-e8bf-4a96-9a85-a6e23a8c635c,.NET 7.0,False,True,False,True,Default,Default,False,False,False,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,16,Default,21,False,678.3 μs,13.00 μs,15.48 μs
|
Benchmark,DefaultJob,False,Default,Default,Default,Default,Default,Default,0000000000,Empty,RyuJit,Arm64,8c5e7fda-e8bf-4a96-9a85-a6e23a8c635c,.NET 7.0,False,True,False,True,Default,Default,False,False,False,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,16,Default,21,False,654.8 μs,12.87 μs,13.22 μs
|
||||||
Benchmark,DefaultJob,False,Default,Default,Default,Default,Default,Default,0000000000,Empty,RyuJit,Arm64,8c5e7fda-e8bf-4a96-9a85-a6e23a8c635c,.NET 7.0,False,True,False,True,Default,Default,False,False,False,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,16,Default,21,True,612.3 μs,9.40 μs,8.79 μs
|
Benchmark,DefaultJob,False,Default,Default,Default,Default,Default,Default,0000000000,Empty,RyuJit,Arm64,8c5e7fda-e8bf-4a96-9a85-a6e23a8c635c,.NET 7.0,False,True,False,True,Default,Default,False,False,False,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,16,Default,21,True,577.8 μs,6.50 μs,6.08 μs
|
||||||
|
|
@@ -2,7 +2,7 @@
|
|||||||
<html lang='en'>
|
<html lang='en'>
|
||||||
<head>
|
<head>
|
||||||
<meta charset='utf-8' />
|
<meta charset='utf-8' />
|
||||||
<title>AdventOfCode2022.App.Benchmark21To25-20221221-100214</title>
|
<title>AdventOfCode2022.App.Benchmark21To25-20221221-110833</title>
|
||||||
|
|
||||||
<style type="text/css">
|
<style type="text/css">
|
||||||
table { border-collapse: collapse; display: block; width: 100%; overflow: auto; }
|
table { border-collapse: collapse; display: block; width: 100%; overflow: auto; }
|
||||||
@@ -24,8 +24,8 @@ Apple M1 Max, 1 CPU, 10 logical and 10 physical cores
|
|||||||
<table>
|
<table>
|
||||||
<thead><tr><th>Method</th><th>Day</th><th>IsPartOne</th><th>Mean</th><th>Error</th><th>StdDev</th>
|
<thead><tr><th>Method</th><th>Day</th><th>IsPartOne</th><th>Mean</th><th>Error</th><th>StdDev</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead><tbody><tr><td>Benchmark</td><td>21</td><td>False</td><td>678.3 μs</td><td>13.00 μs</td><td>15.48 μs</td>
|
</thead><tbody><tr><td>Benchmark</td><td>21</td><td>False</td><td>654.8 μs</td><td>12.87 μs</td><td>13.22 μs</td>
|
||||||
</tr><tr><td>Benchmark</td><td>21</td><td>True</td><td>612.3 μs</td><td>9.40 μs</td><td>8.79 μs</td>
|
</tr><tr><td>Benchmark</td><td>21</td><td>True</td><td>577.8 μs</td><td>6.50 μs</td><td>6.08 μs</td>
|
||||||
</tr></tbody></table>
|
</tr></tbody></table>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
Reference in New Issue
Block a user