Speed up day 7
This commit is contained in:
@@ -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
|
||||||
|
@@ -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
|
||||||
|
@@ -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
|
||||||
|
@@ -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
|
||||||
|
Reference in New Issue
Block a user