Speed up day 7 a bit (#7)
I'm going mad, why am I doing this Co-authored-by: Smaug123 <patrick+github@patrickstevens.co.uk> Reviewed-on: #7
This commit is contained in:
@@ -7,6 +7,7 @@
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Include="Arr2D.fs" />
|
||||
<Compile Include="ResizeArray.fs" />
|
||||
<Compile Include="EfficientString.fs" />
|
||||
<Compile Include="Day1.fs" />
|
||||
<Compile Include="Day2.fs" />
|
||||
|
@@ -1,9 +1,12 @@
|
||||
namespace AdventOfCode2023
|
||||
|
||||
open System
|
||||
open System.Globalization
|
||||
|
||||
[<RequireQualifiedAccess>]
|
||||
module Day2 =
|
||||
let inline parseInt (s : ReadOnlySpan<char>) : int =
|
||||
Int32.Parse (s, NumberStyles.None, CultureInfo.InvariantCulture)
|
||||
|
||||
let part1 (s : string) =
|
||||
use lines = StringSplitEnumerator.make '\n' s
|
||||
@@ -18,20 +21,20 @@ module Day2 =
|
||||
while isOk && words.MoveNext () do
|
||||
match words.Current.[0] with
|
||||
| 'b' ->
|
||||
if Int32.Parse prevWord > 14 then
|
||||
if parseInt prevWord > 14 then
|
||||
isOk <- false
|
||||
| 'r' ->
|
||||
if Int32.Parse prevWord > 12 then
|
||||
if parseInt prevWord > 12 then
|
||||
isOk <- false
|
||||
| 'g' ->
|
||||
if Int32.Parse prevWord > 13 then
|
||||
if parseInt prevWord > 13 then
|
||||
isOk <- false
|
||||
| _ -> ()
|
||||
|
||||
prevWord <- words.Current
|
||||
|
||||
if isOk then
|
||||
answer <- answer + Int32.Parse (line.Slice (5, line.IndexOf ':' - 5))
|
||||
answer <- answer + parseInt (line.Slice (5, line.IndexOf ':' - 5))
|
||||
|
||||
answer
|
||||
|
||||
@@ -49,9 +52,9 @@ module Day2 =
|
||||
|
||||
while words.MoveNext () do
|
||||
match words.Current.[0] with
|
||||
| 'b' -> blues <- max blues (Int32.Parse prevWord)
|
||||
| 'r' -> reds <- max reds (Int32.Parse prevWord)
|
||||
| 'g' -> greens <- max greens (Int32.Parse prevWord)
|
||||
| 'b' -> blues <- max blues (parseInt prevWord)
|
||||
| 'r' -> reds <- max reds (parseInt prevWord)
|
||||
| 'g' -> greens <- max greens (parseInt prevWord)
|
||||
| _ -> ()
|
||||
|
||||
prevWord <- words.Current
|
||||
|
@@ -1,16 +1,17 @@
|
||||
namespace AdventOfCode2023
|
||||
|
||||
open System
|
||||
open System.Collections.Generic
|
||||
open System.Globalization
|
||||
open AdventOfCode2023.ResizeArray
|
||||
|
||||
type Hand =
|
||||
| Five = 10
|
||||
| Four = 9
|
||||
| FullHouse = 8
|
||||
| Three = 7
|
||||
| TwoPairs = 6
|
||||
| Pair = 5
|
||||
| High = 4
|
||||
| Five = 6
|
||||
| Four = 5
|
||||
| FullHouse = 4
|
||||
| Three = 3
|
||||
| TwoPairs = 2
|
||||
| Pair = 1
|
||||
| High = 0
|
||||
|
||||
type HandContents =
|
||||
{
|
||||
@@ -24,13 +25,16 @@ type HandContents =
|
||||
[<RequireQualifiedAccess>]
|
||||
module Day7 =
|
||||
|
||||
[<Literal>]
|
||||
let joker = 0uy
|
||||
|
||||
let inline toByte (adjustJoker : bool) (c : char) : byte =
|
||||
if c <= '9' then byte c - byte '0'
|
||||
elif c = 'T' then 10uy
|
||||
elif c = 'J' then (if adjustJoker then 1uy else 11uy)
|
||||
elif c = 'Q' then 12uy
|
||||
elif c = 'K' then 13uy
|
||||
elif c = 'A' then 14uy
|
||||
if c <= '9' then byte c - byte '1'
|
||||
elif c = 'T' then 9uy
|
||||
elif c = 'J' then (if adjustJoker then joker else 10uy)
|
||||
elif c = 'Q' then 11uy
|
||||
elif c = 'K' then 12uy
|
||||
elif c = 'A' then 13uy
|
||||
else failwithf "could not parse: %c" c
|
||||
|
||||
let inline private updateState (tallies : ResizeArray<_>) newNum =
|
||||
@@ -44,12 +48,32 @@ module Day7 =
|
||||
if not isAdded then
|
||||
tallies.Add (newNum, 1)
|
||||
|
||||
let inline parseHand
|
||||
(tallyBuffer : ResizeArray<_>)
|
||||
(adjustJoker : bool)
|
||||
(s : ReadOnlySpan<char>)
|
||||
: Hand * HandContents
|
||||
=
|
||||
type RankedHand = uint32
|
||||
|
||||
[<Literal>]
|
||||
let fourteen = 14ul
|
||||
|
||||
[<Literal>]
|
||||
let fourteenFive = fourteen * fourteen * fourteen * fourteen * fourteen
|
||||
|
||||
[<Literal>]
|
||||
let fourteenFour = fourteen * fourteen * fourteen * fourteen
|
||||
|
||||
[<Literal>]
|
||||
let fourteenThree = fourteen * fourteen * fourteen
|
||||
|
||||
[<Literal>]
|
||||
let fourteenTwo = fourteen * fourteen
|
||||
|
||||
let toInt (hand : Hand) (contents : HandContents) : RankedHand =
|
||||
uint32 hand * fourteenFive
|
||||
+ uint32 contents.First * fourteenFour
|
||||
+ uint32 contents.Second * fourteenThree
|
||||
+ uint32 contents.Third * fourteenTwo
|
||||
+ uint32 contents.Fourth * fourteen
|
||||
+ uint32 contents.Fifth
|
||||
|
||||
let parseHand (tallyBuffer : ResizeArray<_>) (adjustJoker : bool) (s : ReadOnlySpan<char>) : RankedHand =
|
||||
let contents =
|
||||
{
|
||||
First = toByte adjustJoker s.[0]
|
||||
@@ -70,17 +94,18 @@ module Day7 =
|
||||
if not adjustJoker then
|
||||
0, -1
|
||||
else
|
||||
let mutable count = 0
|
||||
let mutable jokerPos = -1
|
||||
let mutable jokerCount = 0
|
||||
let mutable jokerPos = 0
|
||||
|
||||
for i = 0 to tallyBuffer.Count - 1 do
|
||||
let card, tally = tallyBuffer.[i]
|
||||
while jokerPos < tallyBuffer.Count && jokerCount = 0 do
|
||||
let card, tally = tallyBuffer.[jokerPos]
|
||||
|
||||
if card = 1uy then
|
||||
count <- tally
|
||||
jokerPos <- i
|
||||
if card = joker then
|
||||
jokerCount <- tally
|
||||
else
|
||||
jokerPos <- jokerPos + 1
|
||||
|
||||
count, jokerPos
|
||||
jokerCount, jokerPos
|
||||
|
||||
let hand =
|
||||
if jokerCount > 0 then
|
||||
@@ -135,70 +160,56 @@ module Day7 =
|
||||
else
|
||||
Hand.High
|
||||
|
||||
hand, contents
|
||||
toInt hand contents
|
||||
|
||||
let parse (adjustJoker : bool) (s : string) : ResizeArray<Hand * HandContents * int> =
|
||||
type RankedHandAndBid = uint32
|
||||
|
||||
[<Literal>]
|
||||
let bidSeparator = 1001ul
|
||||
|
||||
let inline toRankedHandAndBid (r : RankedHand) (bid : uint32) : RankedHandAndBid = bidSeparator * r + bid
|
||||
|
||||
let inline getBid (r : RankedHandAndBid) : uint32 = uint32 (r % bidSeparator)
|
||||
|
||||
let parse (adjustJoker : bool) (s : string) : ResizeArray<RankedHandAndBid> =
|
||||
use mutable lines = StringSplitEnumerator.make '\n' s
|
||||
let result = ResizeArray ()
|
||||
let tallies = ResizeArray 5
|
||||
let result = ResizeArray.create 4
|
||||
let tallies = ResizeArray.create 5
|
||||
|
||||
while lines.MoveNext () do
|
||||
if not lines.Current.IsEmpty then
|
||||
use mutable line = StringSplitEnumerator.make' ' ' lines.Current
|
||||
line.MoveNext () |> ignore
|
||||
let hand, contents = parseHand tallies adjustJoker line.Current
|
||||
let rankedHand = parseHand tallies adjustJoker line.Current
|
||||
line.MoveNext () |> ignore
|
||||
let bid = Int32.Parse line.Current
|
||||
|
||||
result.Add (hand, contents, bid)
|
||||
let bid =
|
||||
UInt32.Parse (line.Current, NumberStyles.Integer, CultureInfo.InvariantCulture)
|
||||
|
||||
result.Add (toRankedHandAndBid rankedHand bid)
|
||||
|
||||
result
|
||||
|
||||
let compArrBasic (a : HandContents) (b : HandContents) =
|
||||
if a.First > b.First then 1
|
||||
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 part1 (s : string) =
|
||||
let arr = parse false s
|
||||
|
||||
let compBasic : IComparer<Hand * HandContents * int> =
|
||||
{ new IComparer<_> with
|
||||
member _.Compare ((aHand, aContents, _), (bHand, bContents, _)) =
|
||||
match compare aHand bHand with
|
||||
| 0 -> compArrBasic aContents bContents
|
||||
| x -> x
|
||||
}
|
||||
arr.Sort ()
|
||||
|
||||
let part1 (s : string) : int =
|
||||
let parsed = parse false s
|
||||
let mutable answer = 0ul
|
||||
|
||||
parsed.Sort compBasic
|
||||
|
||||
let mutable answer = 0
|
||||
let mutable pos = 1
|
||||
|
||||
for _, _, bid in parsed do
|
||||
answer <- answer + bid * pos
|
||||
pos <- pos + 1
|
||||
for i = 0 to arr.Count - 1 do
|
||||
answer <- answer + getBid arr.[i] * (uint32 i + 1ul)
|
||||
|
||||
answer
|
||||
|
||||
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 pos = 1
|
||||
let mutable answer = 0ul
|
||||
|
||||
for _, _, bid in parsed do
|
||||
answer <- answer + bid * pos
|
||||
pos <- pos + 1
|
||||
for i = 0 to arr.Count - 1 do
|
||||
answer <- answer + getBid arr.[i] * (uint32 i + 1ul)
|
||||
|
||||
answer
|
||||
|
@@ -0,0 +1,40 @@
|
||||
namespace AdventOfCode2023.ResizeArray
|
||||
|
||||
open System
|
||||
|
||||
type ResizeArray<'T> =
|
||||
private
|
||||
{
|
||||
mutable Array : 'T array
|
||||
mutable Length : int
|
||||
}
|
||||
|
||||
member this.Count = this.Length
|
||||
member this.Clear () = this.Length <- 0
|
||||
|
||||
member this.Add (t : 'T) =
|
||||
if this.Length < this.Array.Length then
|
||||
this.Array.[this.Length] <- t
|
||||
else
|
||||
let newLength = this.Length * 2
|
||||
let newArray = Array.zeroCreate<'T> newLength
|
||||
Array.blit this.Array 0 newArray 0 this.Length
|
||||
newArray.[this.Length] <- t
|
||||
this.Array <- newArray
|
||||
|
||||
this.Length <- this.Length + 1
|
||||
|
||||
member this.Item
|
||||
with get (i : int) = this.Array.[i]
|
||||
and set (i : int) (t : 'T) = this.Array.[i] <- t
|
||||
|
||||
member this.Sort () =
|
||||
Span(this.Array).Slice(0, this.Count).Sort ()
|
||||
|
||||
[<RequireQualifiedAccess>]
|
||||
module ResizeArray =
|
||||
let create<'T> (capacity : int) =
|
||||
{
|
||||
Array = Array.zeroCreate<'T> capacity
|
||||
Length = 0
|
||||
}
|
Reference in New Issue
Block a user