Compare commits
1 Commits
minimal
...
c8c1cdc950
Author | SHA1 | Date | |
---|---|---|---|
c8c1cdc950 |
@@ -3,9 +3,16 @@ steps:
|
|||||||
image: nixos/nix
|
image: nixos/nix
|
||||||
commands:
|
commands:
|
||||||
- echo 'experimental-features = flakes nix-command' >> /etc/nix/nix.conf
|
- echo 'experimental-features = flakes nix-command' >> /etc/nix/nix.conf
|
||||||
- nix develop --command dotnet --info
|
# Lint
|
||||||
- nix develop --command dotnet publish AdventOfCode2023.FSharp/AdventOfCode2023.FSharp/AdventOfCode2023.FSharp.fsproj --configuration Release
|
- "nix flake check"
|
||||||
- nix develop --command sh -c "$(find . -type f -name AdventOfCode2023.FSharp | grep Release | grep publish) AdventOfCode2023.FSharp/Test/samples"
|
# Test
|
||||||
|
- nix develop --command dotnet test AdventOfCode2023.FSharp
|
||||||
|
- nix develop --command dotnet test AdventOfCode2023.FSharp --configuration Release
|
||||||
|
- nix develop --command alejandra --check .
|
||||||
|
- nix develop --command dotnet tool restore
|
||||||
|
- nix develop --command dotnet fantomas --check .
|
||||||
|
# - nix develop --command dotnet publish AdventOfCode2023.FSharp/AdventOfCode2023.FSharp/AdventOfCode2023.FSharp.fsproj --configuration Release
|
||||||
|
# - nix develop --command sh -c "$(find . -type f -name AdventOfCode2023.FSharp | grep Release | grep publish) AdventOfCode2023.FSharp/Test/samples"
|
||||||
|
|
||||||
when:
|
when:
|
||||||
- event: "push"
|
- event: "push"
|
||||||
|
@@ -11,6 +11,7 @@
|
|||||||
<Compile Include="Day1.fs" />
|
<Compile Include="Day1.fs" />
|
||||||
<Compile Include="Day2.fs" />
|
<Compile Include="Day2.fs" />
|
||||||
<Compile Include="Day3.fs" />
|
<Compile Include="Day3.fs" />
|
||||||
|
<Compile Include="Day4.fs" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
97
AdventOfCode2023.FSharp/AdventOfCode2023.FSharp.Lib/Day4.fs
Normal file
97
AdventOfCode2023.FSharp/AdventOfCode2023.FSharp.Lib/Day4.fs
Normal file
@@ -0,0 +1,97 @@
|
|||||||
|
namespace AdventOfCode2023
|
||||||
|
|
||||||
|
open System
|
||||||
|
open System.Collections.Generic
|
||||||
|
|
||||||
|
[<RequireQualifiedAccess>]
|
||||||
|
module Day4 =
|
||||||
|
|
||||||
|
let part1 (s : string) =
|
||||||
|
use lines = StringSplitEnumerator.make '\n' s
|
||||||
|
let mutable total = 0
|
||||||
|
let winningNumbers = HashSet ()
|
||||||
|
|
||||||
|
for line in lines do
|
||||||
|
if not (line.IsWhiteSpace ()) then
|
||||||
|
let mutable accumulatingWinning = true
|
||||||
|
winningNumbers.Clear ()
|
||||||
|
use mutable split = StringSplitEnumerator.make' ' ' line
|
||||||
|
StringSplitEnumerator.chomp "Card" &split
|
||||||
|
|
||||||
|
while split.Current.IsEmpty || split.Current.[split.Current.Length - 1] <> ':' do
|
||||||
|
split.MoveNext () |> ignore
|
||||||
|
|
||||||
|
split.MoveNext () |> ignore
|
||||||
|
|
||||||
|
while accumulatingWinning do
|
||||||
|
while split.Current.IsEmpty do
|
||||||
|
split.MoveNext () |> ignore
|
||||||
|
|
||||||
|
if split.Current.[0] = '|' then
|
||||||
|
accumulatingWinning <- false
|
||||||
|
else
|
||||||
|
winningNumbers.Add (Int32.Parse split.Current) |> ignore
|
||||||
|
split.MoveNext () |> ignore
|
||||||
|
|
||||||
|
let mutable answer = 0
|
||||||
|
|
||||||
|
while split.MoveNext () do
|
||||||
|
if not split.Current.IsEmpty then
|
||||||
|
let n = Int32.Parse split.Current
|
||||||
|
|
||||||
|
if winningNumbers.Contains n then
|
||||||
|
answer <- answer + 1
|
||||||
|
|
||||||
|
if answer > 0 then
|
||||||
|
total <- total + (1 <<< (answer - 1))
|
||||||
|
|
||||||
|
total
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
let part2 (s : string) =
|
||||||
|
use lines = StringSplitEnumerator.make '\n' s
|
||||||
|
let mutable total = 0
|
||||||
|
let winningNumbers = HashSet ()
|
||||||
|
let winners = ResizeArray ()
|
||||||
|
|
||||||
|
for line in lines do
|
||||||
|
if not (line.IsWhiteSpace ()) then
|
||||||
|
let mutable accumulatingWinning = true
|
||||||
|
winningNumbers.Clear ()
|
||||||
|
use mutable split = StringSplitEnumerator.make' ' ' line
|
||||||
|
StringSplitEnumerator.chomp "Card" &split
|
||||||
|
|
||||||
|
while split.Current.IsEmpty || split.Current.[split.Current.Length - 1] <> ':' do
|
||||||
|
split.MoveNext () |> ignore
|
||||||
|
|
||||||
|
split.MoveNext () |> ignore
|
||||||
|
|
||||||
|
while accumulatingWinning do
|
||||||
|
while split.Current.IsEmpty do
|
||||||
|
split.MoveNext () |> ignore
|
||||||
|
|
||||||
|
if split.Current.[0] = '|' then
|
||||||
|
accumulatingWinning <- false
|
||||||
|
else
|
||||||
|
winningNumbers.Add (Int32.Parse split.Current) |> ignore
|
||||||
|
split.MoveNext () |> ignore
|
||||||
|
|
||||||
|
let mutable answer = 0
|
||||||
|
|
||||||
|
while split.MoveNext () do
|
||||||
|
if not split.Current.IsEmpty then
|
||||||
|
let n = Int32.Parse split.Current
|
||||||
|
|
||||||
|
if winningNumbers.Contains n then
|
||||||
|
answer <- answer + 1
|
||||||
|
|
||||||
|
winners.Add answer
|
||||||
|
|
||||||
|
let ans = Array.create winners.Count 1
|
||||||
|
|
||||||
|
for i = 0 to winners.Count - 1 do
|
||||||
|
for j = i + 1 to winners.[i] + i do
|
||||||
|
ans.[j] <- ans.[j] + ans.[i]
|
||||||
|
|
||||||
|
ans |> Array.sum
|
@@ -1,12 +1,28 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<OutputType>Exe</OutputType>
|
<OutputType>Exe</OutputType>
|
||||||
<TargetFramework>net8.0</TargetFramework>
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
<PublishAot>true</PublishAot>
|
<PublishAot>true</PublishAot>
|
||||||
|
<InvariantGlobalization>true</InvariantGlobalization>
|
||||||
|
<UseSystemResourceKeys>true</UseSystemResourceKeys>
|
||||||
|
|
||||||
|
<IlcOptimizationPreference>Speed</IlcOptimizationPreference>
|
||||||
|
<IlcGenerateStackTraceData>false</IlcGenerateStackTraceData>
|
||||||
|
|
||||||
|
<DebuggerSupport>false</DebuggerSupport>
|
||||||
|
<EnableUnsafeBinaryFormatterSerialization>false</EnableUnsafeBinaryFormatterSerialization>
|
||||||
|
<EventSourceSupport>false</EventSourceSupport>
|
||||||
|
<HttpActivityPropagationSupport>false</HttpActivityPropagationSupport>
|
||||||
|
<MetadataUpdaterSupport>false</MetadataUpdaterSupport>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Compile Include="Program.fs"/>
|
<Compile Include="Program.fs"/>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\AdventOfCode2023.FSharp.Lib\AdventOfCode2023.FSharp.Lib.fsproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
@@ -1,7 +1,108 @@
|
|||||||
namespace AdventOfCode2023
|
namespace AdventOfCode2023
|
||||||
|
|
||||||
|
#if DEBUG
|
||||||
|
#else
|
||||||
|
#nowarn "9"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
open System
|
||||||
|
open System.Diagnostics
|
||||||
|
open System.IO
|
||||||
|
|
||||||
module Program =
|
module Program =
|
||||||
|
|
||||||
|
let inline toUs (ticks : int64) =
|
||||||
|
1_000_000.0 * float ticks / float Stopwatch.Frequency
|
||||||
|
|
||||||
[<EntryPoint>]
|
[<EntryPoint>]
|
||||||
let main argv =
|
let main argv =
|
||||||
|
let endToEnd = Stopwatch.StartNew ()
|
||||||
|
endToEnd.Restart ()
|
||||||
|
|
||||||
|
let dir = DirectoryInfo argv.[0]
|
||||||
|
|
||||||
|
let sw = Stopwatch.StartNew ()
|
||||||
|
|
||||||
|
do
|
||||||
|
sw.Restart ()
|
||||||
|
let input = Path.Combine (dir.FullName, "day1.txt") |> File.ReadAllText
|
||||||
|
let part1 = Day1.part1 input
|
||||||
|
sw.Stop ()
|
||||||
|
Console.WriteLine (part1.ToString ())
|
||||||
|
Console.Error.WriteLine ((1_000.0 * float sw.ElapsedTicks / float Stopwatch.Frequency).ToString () + "ms")
|
||||||
|
sw.Restart ()
|
||||||
|
let part2 = Day1.part2 input
|
||||||
|
sw.Stop ()
|
||||||
|
Console.WriteLine (part2.ToString ())
|
||||||
|
Console.Error.WriteLine ((1_000.0 * float sw.ElapsedTicks / float Stopwatch.Frequency).ToString () + "ms")
|
||||||
|
|
||||||
|
do
|
||||||
|
let input = Path.Combine (dir.FullName, "day2.txt") |> File.ReadAllText
|
||||||
|
sw.Restart ()
|
||||||
|
let part1 = Day2.part1 input
|
||||||
|
sw.Stop ()
|
||||||
|
Console.WriteLine (part1.ToString ())
|
||||||
|
Console.Error.WriteLine ((1_000.0 * float sw.ElapsedTicks / float Stopwatch.Frequency).ToString () + "ms")
|
||||||
|
sw.Restart ()
|
||||||
|
let part2 = Day2.part2 input
|
||||||
|
sw.Stop ()
|
||||||
|
Console.WriteLine (part2.ToString ())
|
||||||
|
Console.Error.WriteLine ((1_000.0 * float sw.ElapsedTicks / float Stopwatch.Frequency).ToString () + "ms")
|
||||||
|
|
||||||
|
do
|
||||||
|
let input = Path.Combine (dir.FullName, "day3.txt") |> File.ReadAllBytes
|
||||||
|
|
||||||
|
sw.Restart ()
|
||||||
|
let resultArr, len, lineCount = Day3.parse input
|
||||||
|
sw.Stop ()
|
||||||
|
|
||||||
|
Console.Error.WriteLine (
|
||||||
|
(1_000.0 * float sw.ElapsedTicks / float Stopwatch.Frequency).ToString ()
|
||||||
|
+ "ms parse"
|
||||||
|
)
|
||||||
|
#if DEBUG
|
||||||
|
let contents =
|
||||||
|
{
|
||||||
|
Elements = Array.take len resultArr
|
||||||
|
Width = len / lineCount
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
use ptr = fixed resultArr
|
||||||
|
|
||||||
|
let contents =
|
||||||
|
{
|
||||||
|
Elements = ptr
|
||||||
|
Length = len
|
||||||
|
Width = len / lineCount
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
let part1 = Day3.part1 contents
|
||||||
|
sw.Stop ()
|
||||||
|
Console.WriteLine (part1.ToString ())
|
||||||
|
Console.Error.WriteLine ((1_000.0 * float sw.ElapsedTicks / float Stopwatch.Frequency).ToString () + "ms")
|
||||||
|
sw.Restart ()
|
||||||
|
let part2 = Day3.part2 contents
|
||||||
|
Console.WriteLine (part2.ToString ())
|
||||||
|
Console.Error.WriteLine ((1_000.0 * float sw.ElapsedTicks / float Stopwatch.Frequency).ToString () + "ms")
|
||||||
|
|
||||||
|
do
|
||||||
|
let input = Path.Combine (dir.FullName, "day4.txt") |> File.ReadAllText
|
||||||
|
sw.Restart ()
|
||||||
|
let part1 = Day4.part1 input
|
||||||
|
sw.Stop ()
|
||||||
|
Console.WriteLine (part1.ToString ())
|
||||||
|
Console.Error.WriteLine ((1_000.0 * float sw.ElapsedTicks / float Stopwatch.Frequency).ToString () + "ms")
|
||||||
|
sw.Restart ()
|
||||||
|
let part2 = Day4.part2 input
|
||||||
|
sw.Stop ()
|
||||||
|
Console.WriteLine (part2.ToString ())
|
||||||
|
Console.Error.WriteLine ((1_000.0 * float sw.ElapsedTicks / float Stopwatch.Frequency).ToString () + "ms")
|
||||||
|
|
||||||
|
endToEnd.Stop ()
|
||||||
|
|
||||||
|
Console.Error.WriteLine (
|
||||||
|
(1_000.0 * float endToEnd.ElapsedTicks / float Stopwatch.Frequency).ToString ()
|
||||||
|
+ "ms total"
|
||||||
|
)
|
||||||
|
|
||||||
0
|
0
|
||||||
|
@@ -12,10 +12,12 @@
|
|||||||
<Compile Include="TestDay1.fs" />
|
<Compile Include="TestDay1.fs" />
|
||||||
<Compile Include="TestDay2.fs" />
|
<Compile Include="TestDay2.fs" />
|
||||||
<Compile Include="TestDay3.fs" />
|
<Compile Include="TestDay3.fs" />
|
||||||
|
<Compile Include="TestDay4.fs" />
|
||||||
<EmbeddedResource Include="samples\day1.txt" />
|
<EmbeddedResource Include="samples\day1.txt" />
|
||||||
<EmbeddedResource Include="samples\day1part1.txt" />
|
<EmbeddedResource Include="samples\day1part1.txt" />
|
||||||
<EmbeddedResource Include="samples\day2.txt" />
|
<EmbeddedResource Include="samples\day2.txt" />
|
||||||
<EmbeddedResource Include="samples\day3.txt" />
|
<EmbeddedResource Include="samples\day3.txt" />
|
||||||
|
<EmbeddedResource Include="samples\day4.txt" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
43
AdventOfCode2023.FSharp/Test/TestDay4.fs
Normal file
43
AdventOfCode2023.FSharp/Test/TestDay4.fs
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
namespace AdventOfCode2023.Test
|
||||||
|
|
||||||
|
open AdventOfCode2023
|
||||||
|
open NUnit.Framework
|
||||||
|
open FsUnitTyped
|
||||||
|
open System.IO
|
||||||
|
|
||||||
|
[<TestFixture>]
|
||||||
|
module TestDay4 =
|
||||||
|
|
||||||
|
let sample = Assembly.getEmbeddedResource typeof<Dummy>.Assembly "day4.txt"
|
||||||
|
|
||||||
|
[<Test>]
|
||||||
|
let part1Sample () = sample |> Day4.part1 |> shouldEqual 13
|
||||||
|
|
||||||
|
[<Test>]
|
||||||
|
let part2Sample () = sample |> Day4.part2 |> shouldEqual 30
|
||||||
|
|
||||||
|
[<Test>]
|
||||||
|
let part1Actual () =
|
||||||
|
let s =
|
||||||
|
try
|
||||||
|
File.ReadAllText (Path.Combine (__SOURCE_DIRECTORY__, "../../inputs/day4.txt"))
|
||||||
|
with
|
||||||
|
| :? DirectoryNotFoundException
|
||||||
|
| :? FileNotFoundException ->
|
||||||
|
Assert.Inconclusive ()
|
||||||
|
failwith "unreachable"
|
||||||
|
|
||||||
|
Day4.part1 s |> shouldEqual 27454
|
||||||
|
|
||||||
|
[<Test>]
|
||||||
|
let part2Actual () =
|
||||||
|
let s =
|
||||||
|
try
|
||||||
|
File.ReadAllText (Path.Combine (__SOURCE_DIRECTORY__, "../../inputs/day4.txt"))
|
||||||
|
with
|
||||||
|
| :? DirectoryNotFoundException
|
||||||
|
| :? FileNotFoundException ->
|
||||||
|
Assert.Inconclusive ()
|
||||||
|
failwith "unreachable"
|
||||||
|
|
||||||
|
Day4.part2 s |> shouldEqual 6857330
|
6
AdventOfCode2023.FSharp/Test/samples/day4.txt
Normal file
6
AdventOfCode2023.FSharp/Test/samples/day4.txt
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
Card 1: 41 48 83 86 17 | 83 86 6 31 17 9 48 53
|
||||||
|
Card 2: 13 32 20 16 61 | 61 30 68 82 17 32 24 19
|
||||||
|
Card 3: 1 21 53 59 44 | 69 82 63 72 16 21 14 1
|
||||||
|
Card 4: 41 92 73 84 69 | 59 84 76 51 58 5 54 83
|
||||||
|
Card 5: 87 83 26 28 32 | 88 30 70 12 93 22 82 36
|
||||||
|
Card 6: 31 18 13 56 72 | 74 77 10 23 35 67 36 11
|
Reference in New Issue
Block a user