diff --git a/AdventOfCode2023.FSharp/AdventOfCode2023.FSharp.Lib/Day2.fs b/AdventOfCode2023.FSharp/AdventOfCode2023.FSharp.Lib/Day2.fs index 4ff87e8..41ea30d 100644 --- a/AdventOfCode2023.FSharp/AdventOfCode2023.FSharp.Lib/Day2.fs +++ b/AdventOfCode2023.FSharp/AdventOfCode2023.FSharp.Lib/Day2.fs @@ -1,9 +1,12 @@ namespace AdventOfCode2023 open System +open System.Globalization [] module Day2 = + let inline parseInt (s : ReadOnlySpan) : 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 diff --git a/AdventOfCode2023.FSharp/AdventOfCode2023.FSharp.Lib/Day7.fs b/AdventOfCode2023.FSharp/AdventOfCode2023.FSharp.Lib/Day7.fs index ef8a5bd..b169802 100644 --- a/AdventOfCode2023.FSharp/AdventOfCode2023.FSharp.Lib/Day7.fs +++ b/AdventOfCode2023.FSharp/AdventOfCode2023.FSharp.Lib/Day7.fs @@ -1,16 +1,16 @@ namespace AdventOfCode2023 open System -open System.Collections.Generic +open System.Globalization 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 = { @@ -44,12 +44,35 @@ module Day7 = if not isAdded then tallies.Add (newNum, 1) - let inline parseHand - (tallyBuffer : ResizeArray<_>) - (adjustJoker : bool) - (s : ReadOnlySpan) - : Hand * HandContents - = + type RankedHand = uint64 + + [] + let fifteen = 15uL + + [] + let fifteenFive = fifteen * fifteen * fifteen * fifteen * fifteen + + [] + let fifteenFour = fifteen * fifteen * fifteen * fifteen + + [] + let fifteenThree = fifteen * fifteen * fifteen + + [] + 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) : RankedHand = let contents = { First = toByte adjustJoker s.[0] @@ -135,9 +158,15 @@ module Day7 = else Hand.High - hand, contents + toInt hand contents - let parse (adjustJoker : bool) (s : string) : ResizeArray = + 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 = use mutable lines = StringSplitEnumerator.make '\n' s let result = ResizeArray () let tallies = ResizeArray 5 @@ -146,59 +175,36 @@ module Day7 = 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 = + UInt64.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 = - { 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] * (uint64 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] * (uint64 i + 1uL) answer diff --git a/AdventOfCode2023.FSharp/AdventOfCode2023.FSharp/Program.fs b/AdventOfCode2023.FSharp/AdventOfCode2023.FSharp/Program.fs index 254e137..608c7f9 100644 --- a/AdventOfCode2023.FSharp/AdventOfCode2023.FSharp/Program.fs +++ b/AdventOfCode2023.FSharp/AdventOfCode2023.FSharp/Program.fs @@ -23,11 +23,17 @@ module Program = let sw = Stopwatch.StartNew () - printfn "=====Day 1=====" + Console.WriteLine "=====Day 1=====" do 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 sw.Stop () Console.WriteLine (part1.ToString ()) @@ -39,7 +45,7 @@ module Program = Console.WriteLine (part2.ToString ()) Console.Error.WriteLine ((1_000.0 * float sw.ElapsedTicks / float Stopwatch.Frequency).ToString () + "ms") - printfn "=====Day 2=====" + Console.WriteLine "=====Day 2=====" do let input = Path.Combine (dir.FullName, "day2.txt") |> File.ReadAllText @@ -54,7 +60,7 @@ module Program = Console.WriteLine (part2.ToString ()) Console.Error.WriteLine ((1_000.0 * float sw.ElapsedTicks / float Stopwatch.Frequency).ToString () + "ms") - printfn "=====Day 3=====" + Console.WriteLine "=====Day 3=====" do let input = Path.Combine (dir.FullName, "day3.txt") |> File.ReadAllBytes @@ -92,7 +98,7 @@ module Program = Console.WriteLine (part2.ToString ()) Console.Error.WriteLine ((1_000.0 * float sw.ElapsedTicks / float Stopwatch.Frequency).ToString () + "ms") - printfn "=====Day 4=====" + Console.WriteLine "=====Day 4=====" do let input = Path.Combine (dir.FullName, "day4.txt") |> File.ReadAllText @@ -107,7 +113,7 @@ module Program = Console.WriteLine (part2.ToString ()) Console.Error.WriteLine ((1_000.0 * float sw.ElapsedTicks / float Stopwatch.Frequency).ToString () + "ms") - printfn "=====Day 5=====" + Console.WriteLine "=====Day 5=====" do let input = Path.Combine (dir.FullName, "day5.txt") |> File.ReadAllText @@ -122,7 +128,7 @@ module Program = Console.WriteLine (part2.ToString ()) Console.Error.WriteLine ((1_000.0 * float sw.ElapsedTicks / float Stopwatch.Frequency).ToString () + "ms") - printfn "=====Day 6=====" + Console.WriteLine "=====Day 6=====" do let input = Path.Combine (dir.FullName, "day6.txt") |> File.ReadAllText @@ -137,7 +143,7 @@ module Program = Console.WriteLine (part2.ToString ()) Console.Error.WriteLine ((1_000.0 * float sw.ElapsedTicks / float Stopwatch.Frequency).ToString () + "ms") - printfn "=====Day 7=====" + Console.WriteLine "=====Day 7=====" do let input = Path.Combine (dir.FullName, "day7.txt") |> File.ReadAllText diff --git a/AdventOfCode2023.FSharp/Test/TestDay7.fs b/AdventOfCode2023.FSharp/Test/TestDay7.fs index ebade5c..de2d4e6 100644 --- a/AdventOfCode2023.FSharp/Test/TestDay7.fs +++ b/AdventOfCode2023.FSharp/Test/TestDay7.fs @@ -13,11 +13,11 @@ module TestDay7 = [] let part1Sample () = - sample |> Day7.part1 |> shouldEqual 6440 + sample |> Day7.part1 |> shouldEqual 6440uL [] let part2Sample () = - sample |> Day7.part2 |> shouldEqual 5905 + sample |> Day7.part2 |> shouldEqual 5905uL [] let part1Actual () = @@ -30,7 +30,7 @@ module TestDay7 = Assert.Inconclusive () failwith "unreachable" - Day7.part1 s |> shouldEqual 250058342 + Day7.part1 s |> shouldEqual 250058342uL [] let part2Actual () = @@ -43,4 +43,4 @@ module TestDay7 = Assert.Inconclusive () failwith "unreachable" - Day7.part2 s |> shouldEqual 250506580 + Day7.part2 s |> shouldEqual 250506580uL