Day 19 (#19)
Can't be bothered to get it faster Co-authored-by: Smaug123 <patrick+github@patrickstevens.co.uk> Reviewed-on: #19
This commit is contained in:
@@ -5,10 +5,15 @@
|
||||
|
||||
<IsPackable>false</IsPackable>
|
||||
<IsTestProject>true</IsTestProject>
|
||||
|
||||
<EnableStaticNativeInstrumentation>False</EnableStaticNativeInstrumentation>
|
||||
<EnableDynamicNativeInstrumentation>False</EnableDynamicNativeInstrumentation>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Include="Util.fs"/>
|
||||
<Compile Include="TestIntervalSet.fs" />
|
||||
<Compile Include="TestList.fs" />
|
||||
<Compile Include="TestDay1.fs"/>
|
||||
<Compile Include="TestDay2.fs"/>
|
||||
<Compile Include="TestDay3.fs"/>
|
||||
@@ -25,6 +30,7 @@
|
||||
<Compile Include="TestDay14.fs" />
|
||||
<Compile Include="TestDay15.fs" />
|
||||
<Compile Include="TestDay16.fs" />
|
||||
<Compile Include="TestDay19.fs" />
|
||||
<EmbeddedResource Include="samples\day1.txt"/>
|
||||
<EmbeddedResource Include="samples\day1part1.txt"/>
|
||||
<EmbeddedResource Include="samples\day2.txt"/>
|
||||
@@ -44,11 +50,14 @@
|
||||
<EmbeddedResource Include="samples\day14.txt" />
|
||||
<EmbeddedResource Include="samples\day15.txt" />
|
||||
<EmbeddedResource Include="samples\day16.txt" />
|
||||
<EmbeddedResource Include="samples\day19.txt" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="FsCheck" Version="2.16.6" />
|
||||
<PackageReference Include="FsUnit" Version="5.6.1"/>
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.6.0"/>
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.8.0"/>
|
||||
<PackageReference Include="Microsoft.CodeCoverage" Version="17.8.0"/>
|
||||
<PackageReference Include="NUnit3TestAdapter" Version="4.2.1"/>
|
||||
<PackageReference Include="NUnit.Analyzers" Version="3.6.1"/>
|
||||
<PackageReference Include="coverlet.collector" Version="6.0.0"/>
|
||||
|
55
AdventOfCode2023.FSharp/Test/TestDay19.fs
Normal file
55
AdventOfCode2023.FSharp/Test/TestDay19.fs
Normal file
@@ -0,0 +1,55 @@
|
||||
namespace AdventOfCode2023.Test
|
||||
|
||||
open AdventOfCode2023
|
||||
open NUnit.Framework
|
||||
open FsUnitTyped
|
||||
open System.IO
|
||||
|
||||
[<TestFixture>]
|
||||
module TestDay19 =
|
||||
[<Test>]
|
||||
let sample = Assembly.getEmbeddedResource typeof<Dummy>.Assembly "day19.txt"
|
||||
|
||||
[<Test>]
|
||||
let part1Sample () =
|
||||
use mutable s = StringSplitEnumerator.make '\n' sample
|
||||
let workflows = Day19.readWorkflows &s
|
||||
Day19.part1 workflows &s |> shouldEqual 19114
|
||||
|
||||
[<Test>]
|
||||
let part2Sample () =
|
||||
use mutable s = StringSplitEnumerator.make '\n' sample
|
||||
let workflows = Day19.readWorkflows &s
|
||||
Day19.part2 workflows &s |> shouldEqual 167409079868000uL
|
||||
|
||||
[<Test>]
|
||||
let part1Actual () =
|
||||
let s =
|
||||
try
|
||||
File.ReadAllText (Path.Combine (__SOURCE_DIRECTORY__, "../../inputs/day19.txt"))
|
||||
with
|
||||
| :? DirectoryNotFoundException
|
||||
| :? FileNotFoundException ->
|
||||
Assert.Inconclusive ()
|
||||
failwith "unreachable"
|
||||
|
||||
use mutable s = StringSplitEnumerator.make '\n' s
|
||||
let workflows = Day19.readWorkflows &s
|
||||
|
||||
Day19.part1 workflows &s |> shouldEqual 368964
|
||||
|
||||
[<Test>]
|
||||
let part2Actual () =
|
||||
let s =
|
||||
try
|
||||
File.ReadAllText (Path.Combine (__SOURCE_DIRECTORY__, "../../inputs/day19.txt"))
|
||||
with
|
||||
| :? DirectoryNotFoundException
|
||||
| :? FileNotFoundException ->
|
||||
Assert.Inconclusive ()
|
||||
failwith "unreachable"
|
||||
|
||||
use mutable s = StringSplitEnumerator.make '\n' s
|
||||
let workflows = Day19.readWorkflows &s
|
||||
|
||||
Day19.part2 workflows &s |> shouldEqual 127675188176682uL
|
86
AdventOfCode2023.FSharp/Test/TestIntervalSet.fs
Normal file
86
AdventOfCode2023.FSharp/Test/TestIntervalSet.fs
Normal file
@@ -0,0 +1,86 @@
|
||||
namespace AdventOfCode2023.Test
|
||||
|
||||
open System.Threading
|
||||
open AdventOfCode2023
|
||||
open NUnit.Framework
|
||||
open FsUnitTyped
|
||||
open FsCheck
|
||||
|
||||
[<TestFixture>]
|
||||
module TestIntervalSet =
|
||||
|
||||
/// Normalises e.g. (5, 3) to (3, 5) too.
|
||||
let toIntervalSet (model : (int * int) list) =
|
||||
(IntervalSet.empty, model)
|
||||
||> List.fold (fun intervals (x1, x2) -> IntervalSet.add (min x1 x2) (max x1 x2) intervals)
|
||||
|
||||
let modelContains (x : int) (model : (int * int) list) =
|
||||
model
|
||||
|> List.exists (fun (x1, x2) ->
|
||||
let x1, x2 = min x1 x2, max x1 x2
|
||||
x1 <= x && x <= x2
|
||||
)
|
||||
|
||||
[<Test>]
|
||||
let ``IntervalSet add works`` () =
|
||||
let property (pos : int ref) (neg : int ref) (x : int) (xs : (int * int) list) =
|
||||
let intervals = toIntervalSet xs
|
||||
|
||||
let actual = IntervalSet.contains x intervals
|
||||
let expected = modelContains x xs
|
||||
|
||||
if actual then
|
||||
Interlocked.Increment pos |> ignore
|
||||
else
|
||||
Interlocked.Increment neg |> ignore
|
||||
|
||||
expected = actual
|
||||
|
||||
let pos = ref 0
|
||||
let neg = ref 0
|
||||
|
||||
Check.One (
|
||||
{ Config.Default with
|
||||
MaxTest = 1000
|
||||
},
|
||||
property pos neg
|
||||
)
|
||||
|
||||
printfn "Fraction of positive cases: %f" ((float pos.Value) / (float pos.Value + float neg.Value))
|
||||
|
||||
[<Test>]
|
||||
let ``Intersection works`` () =
|
||||
let property
|
||||
(pos : int ref)
|
||||
(neg : int ref)
|
||||
(trials : int list)
|
||||
(xsModel : (int * int) list)
|
||||
(ysModel : (int * int) list)
|
||||
=
|
||||
let xs = toIntervalSet xsModel
|
||||
let ys = toIntervalSet ysModel
|
||||
|
||||
let intervals = IntervalSet.intersection xs ys
|
||||
|
||||
for x in trials do
|
||||
let actual = IntervalSet.contains x intervals
|
||||
let expected = modelContains x xsModel && modelContains x ysModel
|
||||
|
||||
expected |> shouldEqual actual
|
||||
|
||||
if actual then
|
||||
Interlocked.Increment pos |> ignore
|
||||
else
|
||||
Interlocked.Increment neg |> ignore
|
||||
|
||||
let pos = ref 0
|
||||
let neg = ref 0
|
||||
|
||||
Check.One (
|
||||
{ Config.Default with
|
||||
MaxTest = 1000
|
||||
},
|
||||
property pos neg
|
||||
)
|
||||
|
||||
printfn "Fraction of positive cases: %f" ((float pos.Value) / (float pos.Value + float neg.Value))
|
20
AdventOfCode2023.FSharp/Test/TestList.fs
Normal file
20
AdventOfCode2023.FSharp/Test/TestList.fs
Normal file
@@ -0,0 +1,20 @@
|
||||
namespace Test
|
||||
|
||||
open NUnit.Framework
|
||||
open FsUnitTyped
|
||||
open FsCheck
|
||||
open AdventOfCode2023
|
||||
|
||||
[<TestFixture>]
|
||||
module TestList =
|
||||
|
||||
[<Test>]
|
||||
let ``n-tuples have the right length`` () =
|
||||
let property (n : int) (xs : char list) =
|
||||
let n = min (abs n) 6
|
||||
let xs = xs |> List.take (min 10 xs.Length)
|
||||
let tuples = List.nTuples n xs
|
||||
tuples |> List.forall (fun i -> i.Length = n)
|
||||
|
||||
property 1 [ 'v' ] |> shouldEqual true
|
||||
Check.QuickThrowOnFailure property
|
17
AdventOfCode2023.FSharp/Test/samples/day19.txt
Normal file
17
AdventOfCode2023.FSharp/Test/samples/day19.txt
Normal file
@@ -0,0 +1,17 @@
|
||||
px{a<2006:qkq,m>2090:A,rfg}
|
||||
pv{a>1716:R,A}
|
||||
lnx{m>1548:A,A}
|
||||
rfg{s<537:gd,x>2440:R,A}
|
||||
qs{s>3448:A,lnx}
|
||||
qkq{x<1416:A,crn}
|
||||
crn{x>2662:A,R}
|
||||
in{s<1351:px,qqz}
|
||||
qqz{s>2770:qs,m<1801:hdj,R}
|
||||
gd{a>3333:R,R}
|
||||
hdj{m>838:A,pv}
|
||||
|
||||
{x=787,m=2655,a=1222,s=2876}
|
||||
{x=1679,m=44,a=2067,s=496}
|
||||
{x=2036,m=264,a=79,s=2244}
|
||||
{x=2461,m=1339,a=466,s=291}
|
||||
{x=2127,m=1623,a=2188,s=1013}
|
Reference in New Issue
Block a user