Speed up day 7

This commit is contained in:
Smaug123
2023-12-07 22:05:49 +00:00
parent 2fbdf2c362
commit aa79d212fc
4 changed files with 89 additions and 74 deletions

View File

@@ -1,9 +1,12 @@
namespace AdventOfCode2023 namespace AdventOfCode2023
open System open System
open System.Globalization
[<RequireQualifiedAccess>] [<RequireQualifiedAccess>]
module Day2 = module Day2 =
let inline parseInt (s : ReadOnlySpan<char>) : int =
Int32.Parse (s, NumberStyles.None, CultureInfo.InvariantCulture)
let part1 (s : string) = let part1 (s : string) =
use lines = StringSplitEnumerator.make '\n' s use lines = StringSplitEnumerator.make '\n' s
@@ -18,20 +21,20 @@ module Day2 =
while isOk && words.MoveNext () do while isOk && words.MoveNext () do
match words.Current.[0] with match words.Current.[0] with
| 'b' -> | 'b' ->
if Int32.Parse prevWord > 14 then if parseInt prevWord > 14 then
isOk <- false isOk <- false
| 'r' -> | 'r' ->
if Int32.Parse prevWord > 12 then if parseInt prevWord > 12 then
isOk <- false isOk <- false
| 'g' -> | 'g' ->
if Int32.Parse prevWord > 13 then if parseInt prevWord > 13 then
isOk <- false isOk <- false
| _ -> () | _ -> ()
prevWord <- words.Current prevWord <- words.Current
if isOk then if isOk then
answer <- answer + Int32.Parse (line.Slice (5, line.IndexOf ':' - 5)) answer <- answer + parseInt (line.Slice (5, line.IndexOf ':' - 5))
answer answer
@@ -49,9 +52,9 @@ module Day2 =
while words.MoveNext () do while words.MoveNext () do
match words.Current.[0] with match words.Current.[0] with
| 'b' -> blues <- max blues (Int32.Parse prevWord) | 'b' -> blues <- max blues (parseInt prevWord)
| 'r' -> reds <- max reds (Int32.Parse prevWord) | 'r' -> reds <- max reds (parseInt prevWord)
| 'g' -> greens <- max greens (Int32.Parse prevWord) | 'g' -> greens <- max greens (parseInt prevWord)
| _ -> () | _ -> ()
prevWord <- words.Current prevWord <- words.Current

View File

@@ -1,16 +1,16 @@
namespace AdventOfCode2023 namespace AdventOfCode2023
open System open System
open System.Collections.Generic open System.Globalization
type Hand = type Hand =
| Five = 10 | Five = 6
| Four = 9 | Four = 5
| FullHouse = 8 | FullHouse = 4
| Three = 7 | Three = 3
| TwoPairs = 6 | TwoPairs = 2
| Pair = 5 | Pair = 1
| High = 4 | High = 0
type HandContents = type HandContents =
{ {
@@ -44,12 +44,35 @@ module Day7 =
if not isAdded then if not isAdded then
tallies.Add (newNum, 1) tallies.Add (newNum, 1)
let inline parseHand type RankedHand = uint64
(tallyBuffer : ResizeArray<_>)
(adjustJoker : bool) [<Literal>]
(s : ReadOnlySpan<char>) let fifteen = 15uL
: Hand * HandContents
= [<Literal>]
let fifteenFive = fifteen * fifteen * fifteen * fifteen * fifteen
[<Literal>]
let fifteenFour = fifteen * fifteen * fifteen * fifteen
[<Literal>]
let fifteenThree = fifteen * fifteen * fifteen
[<Literal>]
let fifteenTwo = fifteen * fifteen
let inline toInt (hand : Hand) (contents : HandContents) : RankedHand =
// match hand with
// | Hand.Five -> UInt32.MaxValue - 15ul + uint32 contents.First
// | _ ->
uint64 hand * fifteenFive
+ uint64 contents.First * fifteenFour
+ uint64 contents.Second * fifteenThree
+ uint64 contents.Third * fifteenTwo
+ uint64 contents.Fourth * fifteen
+ uint64 contents.Fifth
let inline parseHand (tallyBuffer : ResizeArray<_>) (adjustJoker : bool) (s : ReadOnlySpan<char>) : RankedHand =
let contents = let contents =
{ {
First = toByte adjustJoker s.[0] First = toByte adjustJoker s.[0]
@@ -135,9 +158,15 @@ module Day7 =
else else
Hand.High Hand.High
hand, contents toInt hand contents
let parse (adjustJoker : bool) (s : string) : ResizeArray<Hand * HandContents * int> = type RankedHandAndBid = uint64
let inline toRankedHandAndBid (r : RankedHand) (bid : uint64) : RankedHandAndBid = 1001uL * r + bid
let inline getBid (r : RankedHandAndBid) : uint64 = uint64 (r % 1001uL)
let parse (adjustJoker : bool) (s : string) : ResizeArray<RankedHandAndBid> =
use mutable lines = StringSplitEnumerator.make '\n' s use mutable lines = StringSplitEnumerator.make '\n' s
let result = ResizeArray () let result = ResizeArray ()
let tallies = ResizeArray 5 let tallies = ResizeArray 5
@@ -146,59 +175,36 @@ module Day7 =
if not lines.Current.IsEmpty then if not lines.Current.IsEmpty then
use mutable line = StringSplitEnumerator.make' ' ' lines.Current use mutable line = StringSplitEnumerator.make' ' ' lines.Current
line.MoveNext () |> ignore line.MoveNext () |> ignore
let hand, contents = parseHand tallies adjustJoker line.Current let rankedHand = parseHand tallies adjustJoker line.Current
line.MoveNext () |> ignore line.MoveNext () |> ignore
let bid = Int32.Parse line.Current
result.Add (hand, contents, bid) let bid =
UInt64.Parse (line.Current, NumberStyles.Integer, CultureInfo.InvariantCulture)
result.Add (toRankedHandAndBid rankedHand bid)
result result
let compArrBasic (a : HandContents) (b : HandContents) = let part1 (s : string) =
if a.First > b.First then 1 let arr = parse false s
elif a.First < b.First then -1
elif a.Second > b.Second then 1
elif a.Second < b.Second then -1
elif a.Third > b.Third then 1
elif a.Third < b.Third then -1
elif a.Fourth > b.Fourth then 1
elif a.Fourth < b.Fourth then -1
elif a.Fifth > b.Fifth then 1
elif a.Fifth < b.Fifth then -1
else 0
let compBasic : IComparer<Hand * HandContents * int> = arr.Sort ()
{ new IComparer<_> with
member _.Compare ((aHand, aContents, _), (bHand, bContents, _)) =
match compare aHand bHand with
| 0 -> compArrBasic aContents bContents
| x -> x
}
let part1 (s : string) : int = let mutable answer = 0uL
let parsed = parse false s
parsed.Sort compBasic for i = 0 to arr.Count - 1 do
answer <- answer + getBid arr.[i] * (uint64 i + 1uL)
let mutable answer = 0
let mutable pos = 1
for _, _, bid in parsed do
answer <- answer + bid * pos
pos <- pos + 1
answer answer
let part2 (s : string) = let part2 (s : string) =
let parsed = parse true s let arr = parse true s
parsed.Sort compBasic arr.Sort ()
let mutable answer = 0 let mutable answer = 0uL
let mutable pos = 1
for _, _, bid in parsed do for i = 0 to arr.Count - 1 do
answer <- answer + bid * pos answer <- answer + getBid arr.[i] * (uint64 i + 1uL)
pos <- pos + 1
answer answer

View File

@@ -23,11 +23,17 @@ module Program =
let sw = Stopwatch.StartNew () let sw = Stopwatch.StartNew ()
printfn "=====Day 1=====" Console.WriteLine "=====Day 1====="
do do
sw.Restart () sw.Restart ()
let input = Path.Combine (dir.FullName, "day1part1.txt") |> File.ReadAllText
let input =
try
Path.Combine (dir.FullName, "day1part1.txt") |> File.ReadAllText
with :? FileNotFoundException ->
Path.Combine (dir.FullName, "day1.txt") |> File.ReadAllText
let part1 = Day1.part1 input let part1 = Day1.part1 input
sw.Stop () sw.Stop ()
Console.WriteLine (part1.ToString ()) Console.WriteLine (part1.ToString ())
@@ -39,7 +45,7 @@ module Program =
Console.WriteLine (part2.ToString ()) Console.WriteLine (part2.ToString ())
Console.Error.WriteLine ((1_000.0 * float sw.ElapsedTicks / float Stopwatch.Frequency).ToString () + "ms") Console.Error.WriteLine ((1_000.0 * float sw.ElapsedTicks / float Stopwatch.Frequency).ToString () + "ms")
printfn "=====Day 2=====" Console.WriteLine "=====Day 2====="
do do
let input = Path.Combine (dir.FullName, "day2.txt") |> File.ReadAllText let input = Path.Combine (dir.FullName, "day2.txt") |> File.ReadAllText
@@ -54,7 +60,7 @@ module Program =
Console.WriteLine (part2.ToString ()) Console.WriteLine (part2.ToString ())
Console.Error.WriteLine ((1_000.0 * float sw.ElapsedTicks / float Stopwatch.Frequency).ToString () + "ms") Console.Error.WriteLine ((1_000.0 * float sw.ElapsedTicks / float Stopwatch.Frequency).ToString () + "ms")
printfn "=====Day 3=====" Console.WriteLine "=====Day 3====="
do do
let input = Path.Combine (dir.FullName, "day3.txt") |> File.ReadAllBytes let input = Path.Combine (dir.FullName, "day3.txt") |> File.ReadAllBytes
@@ -92,7 +98,7 @@ module Program =
Console.WriteLine (part2.ToString ()) Console.WriteLine (part2.ToString ())
Console.Error.WriteLine ((1_000.0 * float sw.ElapsedTicks / float Stopwatch.Frequency).ToString () + "ms") Console.Error.WriteLine ((1_000.0 * float sw.ElapsedTicks / float Stopwatch.Frequency).ToString () + "ms")
printfn "=====Day 4=====" Console.WriteLine "=====Day 4====="
do do
let input = Path.Combine (dir.FullName, "day4.txt") |> File.ReadAllText let input = Path.Combine (dir.FullName, "day4.txt") |> File.ReadAllText
@@ -107,7 +113,7 @@ module Program =
Console.WriteLine (part2.ToString ()) Console.WriteLine (part2.ToString ())
Console.Error.WriteLine ((1_000.0 * float sw.ElapsedTicks / float Stopwatch.Frequency).ToString () + "ms") Console.Error.WriteLine ((1_000.0 * float sw.ElapsedTicks / float Stopwatch.Frequency).ToString () + "ms")
printfn "=====Day 5=====" Console.WriteLine "=====Day 5====="
do do
let input = Path.Combine (dir.FullName, "day5.txt") |> File.ReadAllText let input = Path.Combine (dir.FullName, "day5.txt") |> File.ReadAllText
@@ -122,7 +128,7 @@ module Program =
Console.WriteLine (part2.ToString ()) Console.WriteLine (part2.ToString ())
Console.Error.WriteLine ((1_000.0 * float sw.ElapsedTicks / float Stopwatch.Frequency).ToString () + "ms") Console.Error.WriteLine ((1_000.0 * float sw.ElapsedTicks / float Stopwatch.Frequency).ToString () + "ms")
printfn "=====Day 6=====" Console.WriteLine "=====Day 6====="
do do
let input = Path.Combine (dir.FullName, "day6.txt") |> File.ReadAllText let input = Path.Combine (dir.FullName, "day6.txt") |> File.ReadAllText
@@ -137,7 +143,7 @@ module Program =
Console.WriteLine (part2.ToString ()) Console.WriteLine (part2.ToString ())
Console.Error.WriteLine ((1_000.0 * float sw.ElapsedTicks / float Stopwatch.Frequency).ToString () + "ms") Console.Error.WriteLine ((1_000.0 * float sw.ElapsedTicks / float Stopwatch.Frequency).ToString () + "ms")
printfn "=====Day 7=====" Console.WriteLine "=====Day 7====="
do do
let input = Path.Combine (dir.FullName, "day7.txt") |> File.ReadAllText let input = Path.Combine (dir.FullName, "day7.txt") |> File.ReadAllText

View File

@@ -13,11 +13,11 @@ module TestDay7 =
[<Test>] [<Test>]
let part1Sample () = let part1Sample () =
sample |> Day7.part1 |> shouldEqual 6440 sample |> Day7.part1 |> shouldEqual 6440uL
[<Test>] [<Test>]
let part2Sample () = let part2Sample () =
sample |> Day7.part2 |> shouldEqual 5905 sample |> Day7.part2 |> shouldEqual 5905uL
[<Test>] [<Test>]
let part1Actual () = let part1Actual () =
@@ -30,7 +30,7 @@ module TestDay7 =
Assert.Inconclusive () Assert.Inconclusive ()
failwith "unreachable" failwith "unreachable"
Day7.part1 s |> shouldEqual 250058342 Day7.part1 s |> shouldEqual 250058342uL
[<Test>] [<Test>]
let part2Actual () = let part2Actual () =
@@ -43,4 +43,4 @@ module TestDay7 =
Assert.Inconclusive () Assert.Inconclusive ()
failwith "unreachable" failwith "unreachable"
Day7.part2 s |> shouldEqual 250506580 Day7.part2 s |> shouldEqual 250506580uL