diff --git a/.github/workflows/dotnet.yaml b/.github/workflows/dotnet.yaml
index 9f02513..e735ffd 100644
--- a/.github/workflows/dotnet.yaml
+++ b/.github/workflows/dotnet.yaml
@@ -27,6 +27,8 @@ jobs:
run: dotnet build --no-restore
- name: Test
run: dotnet test --no-build --verbosity normal
+ - name: Run app
+ run: dotnet run --project AdventOfCode2022.App/AdventOfCode2022.App.fsproj --no-build
check-format:
runs-on: ubuntu-latest
diff --git a/AdventOfCode2022.App/AdventOfCode2022.App.fsproj b/AdventOfCode2022.App/AdventOfCode2022.App.fsproj
new file mode 100644
index 0000000..7c30c85
--- /dev/null
+++ b/AdventOfCode2022.App/AdventOfCode2022.App.fsproj
@@ -0,0 +1,22 @@
+
+
+
+ Exe
+ net7.0
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/AdventOfCode2022.App/Program.fs b/AdventOfCode2022.App/Program.fs
new file mode 100644
index 0000000..40c3c94
--- /dev/null
+++ b/AdventOfCode2022.App/Program.fs
@@ -0,0 +1,63 @@
+namespace AdventOfCode2022.App
+
+open System.Diagnostics
+open System.IO
+open System.Reflection
+open AdventOfCode2022
+
+module Program =
+ type Dummy =
+ class
+ end
+
+ let readResource (name : string) : string =
+ let asm = Assembly.GetAssembly typeof
+
+ use stream = asm.GetManifestResourceStream (sprintf "AdventOfCode2022.App.%s" name)
+
+ use reader = new StreamReader (stream)
+ reader.ReadToEnd ()
+
+ []
+ let main _ =
+ let days = Array.init 6 (fun day -> readResource $"Day%i{day + 1}.txt")
+
+ let inline day (i : int) = days.[i - 1]
+
+ let time = Stopwatch.StartNew ()
+ time.Restart ()
+
+ do
+ let lines = StringSplitEnumerator.make '\n' (day 1)
+ printfn "%i" (Day1.part1 lines)
+ printfn "%i" (Day1.part2 lines)
+
+ do
+ let lines = StringSplitEnumerator.make '\n' (day 2)
+ printfn "%i" (Day2.part1 lines)
+ printfn "%i" (Day2.part2 lines)
+
+ do
+ let day3 = day 3
+ let lines = StringSplitEnumerator.make '\n' day3
+ printfn "%i" (Day3Efficient.part1 lines)
+ printfn "%i" (Day3Efficient.part2 (day3.Split '\n'))
+
+ do
+ let lines = StringSplitEnumerator.make '\n' (day 4)
+ printfn "%i" (Day4.part1 lines)
+ printfn "%i" (Day4.part2 lines)
+
+ do
+ let lines = StringSplitEnumerator.make '\n' (day 5)
+ printfn "%s" (Day5.part1 lines)
+ printfn "%s" (Day5.part2 lines)
+
+ do
+ let day6 = day 6
+ printfn "%i" (Day6.part1 day6)
+ printfn "%i" (Day6.part2 day6)
+
+ time.Stop ()
+ printfn $"Took %i{time.ElapsedMilliseconds}ms"
+ 0
diff --git a/AdventOfCode2022.Test/AdventOfCode2022.Test.fsproj b/AdventOfCode2022.Test/AdventOfCode2022.Test.fsproj
index 846c41e..30de338 100644
--- a/AdventOfCode2022.Test/AdventOfCode2022.Test.fsproj
+++ b/AdventOfCode2022.Test/AdventOfCode2022.Test.fsproj
@@ -13,11 +13,13 @@
+
+
diff --git a/AdventOfCode2022.Test/Day1.fs b/AdventOfCode2022.Test/Day1.fs
index a26af65..ab961e1 100644
--- a/AdventOfCode2022.Test/Day1.fs
+++ b/AdventOfCode2022.Test/Day1.fs
@@ -1,6 +1,5 @@
namespace AdventOfCode2022.Test
-open System
open AdventOfCode2022
open NUnit.Framework
open FsUnitTyped
@@ -28,18 +27,18 @@ module TestDay1 =
[]
let ``Part 1`` () =
let input = Assembly.readResource "Day1.txt"
- input.Split '\n' |> Day1.part1 |> shouldEqual 66306
+ Day1.part1 (StringSplitEnumerator.make '\n' input) |> shouldEqual 66306
[]
let ``Part 2`` () =
let input = Assembly.readResource "Day1.txt"
- input.Split '\n' |> Day1.part2 |> shouldEqual 195292
+ Day1.part2 (StringSplitEnumerator.make '\n' input) |> shouldEqual 195292
[]
let ``Part 1, given example`` () =
- testInput.Split Environment.NewLine |> Day1.part1 |> shouldEqual 24000
+ Day1.part1 (StringSplitEnumerator.make '\n' testInput) |> shouldEqual 24000
[]
let ``Part 2, given example`` () =
- testInput.Split Environment.NewLine |> Day1.part2 |> shouldEqual 45000
+ Day1.part2 (StringSplitEnumerator.make '\n' testInput) |> shouldEqual 45000
diff --git a/AdventOfCode2022.Test/Day2.fs b/AdventOfCode2022.Test/Day2.fs
index 5ceb019..c4b76f8 100644
--- a/AdventOfCode2022.Test/Day2.fs
+++ b/AdventOfCode2022.Test/Day2.fs
@@ -15,19 +15,19 @@ C Z"""
[]
let ``Part 1, given`` () =
- testInput.Split Environment.NewLine |> Day2.part1 |> shouldEqual 15
+ Day2.part1 (StringSplitEnumerator.make '\n' testInput) |> shouldEqual 15
[]
let ``Part 1`` () =
let input = Assembly.readResource "Day2.txt"
- input.Split '\n' |> Day2.part1 |> shouldEqual 9651
+ Day2.part1 (StringSplitEnumerator.make '\n' input) |> shouldEqual 9651
[]
let ``Part 2, given`` () =
- testInput.Split Environment.NewLine |> Day2.part2 |> shouldEqual 12
+ Day2.part2 (StringSplitEnumerator.make '\n' testInput) |> shouldEqual 12
[]
let ``Part 2`` () =
let input = Assembly.readResource "Day2.txt"
- input.Split '\n' |> Day2.part2 |> shouldEqual 10560
+ Day2.part2 (StringSplitEnumerator.make '\n' input) |> shouldEqual 10560
diff --git a/AdventOfCode2022.Test/Day3.fs b/AdventOfCode2022.Test/Day3.fs
index ec9fee8..46bb333 100644
--- a/AdventOfCode2022.Test/Day3.fs
+++ b/AdventOfCode2022.Test/Day3.fs
@@ -9,8 +9,11 @@ open AdventOfCode2022
[]
type TestDay3 (efficient : bool) =
- let part1 (s : string seq) =
- if efficient then Day3Efficient.part1 s else Day3.part1 s
+ let part1 (s : string) =
+ if efficient then
+ Day3Efficient.part1 (StringSplitEnumerator.make '\n' s)
+ else
+ s.Split '\n' |> Seq.filter (not << String.IsNullOrEmpty) |> Day3.part1
let part2 (s : string seq) =
if efficient then Day3Efficient.part2 s else Day3.part2 s
@@ -23,7 +26,6 @@ PmmdzqPrVvPwwTWBwg
wMqvLMZHhHMvwLHjbvcjnnSBnvTQFn
ttgJtRGJQctTZtZT
CrZsJsPPZsGzwwsLwLmpwMDw"""
- |> fun s -> s.Split System.Environment.NewLine
|> part1
|> shouldEqual 157
@@ -31,10 +33,7 @@ CrZsJsPPZsGzwwsLwLmpwMDw"""
member _.``Part 1`` () =
let input = Assembly.readResource "Day3.txt"
- input.Split '\n'
- |> Seq.filter (not << String.IsNullOrWhiteSpace)
- |> part1
- |> shouldEqual 8018
+ input |> part1 |> shouldEqual 8018
[]
diff --git a/AdventOfCode2022.Test/Day4.fs b/AdventOfCode2022.Test/Day4.fs
index 7cb1ee3..890e64b 100644
--- a/AdventOfCode2022.Test/Day4.fs
+++ b/AdventOfCode2022.Test/Day4.fs
@@ -1,6 +1,5 @@
namespace AdventOfCode2022.Test
-open System
open NUnit.Framework
open FsUnitTyped
open AdventOfCode2022
@@ -18,32 +17,20 @@ module TestDay4 =
[]
let ``Part 1, given`` () =
- testInput
- |> fun s -> s.Split Environment.NewLine
- |> Day4.part1
- |> shouldEqual 2
+ Day4.part1 (StringSplitEnumerator.make '\n' testInput) |> shouldEqual 2
[]
let ``Part 1`` () =
let input = Assembly.readResource "Day4.txt"
- input.Split '\n'
- |> Seq.filter (not << String.IsNullOrWhiteSpace)
- |> Day4.part1
- |> shouldEqual 433
+ Day4.part1 (StringSplitEnumerator.make '\n' input) |> shouldEqual 433
[]
let ``Part 2, given`` () =
- testInput
- |> fun s -> s.Split Environment.NewLine
- |> Day4.part2
- |> shouldEqual 4
+ Day4.part2 (StringSplitEnumerator.make '\n' testInput) |> shouldEqual 4
[]
let ``Part 2`` () =
let input = Assembly.readResource "Day4.txt"
- input.Split '\n'
- |> Seq.filter (not << String.IsNullOrWhiteSpace)
- |> Day4.part2
- |> shouldEqual 852
+ Day4.part2 (StringSplitEnumerator.make '\n' input) |> shouldEqual 852
diff --git a/AdventOfCode2022.Test/Day6.fs b/AdventOfCode2022.Test/Day6.fs
new file mode 100644
index 0000000..cbc3166
--- /dev/null
+++ b/AdventOfCode2022.Test/Day6.fs
@@ -0,0 +1,45 @@
+namespace AdventOfCode2022.Test
+
+open System
+open NUnit.Framework
+open FsUnitTyped
+open AdventOfCode2022
+
+[]
+module TestDay6 =
+
+ let testInput1 =
+ [
+ "mjqjpqmgbljsphdztnvjfqwrcgsmlb", 7
+ "bvwbjplbgvbhsrlpgdmjqwftvncz", 5
+ "nppdvjthqldpwncqszvftbrmjlhg", 6
+ "nznrnfrfntjfmvfwmzdfjlvtqnbhcprsg", 10
+ "zcfzfwzzqfrljwzlrfnpqdbhtmscgvjw", 11
+ ]
+ |> List.map TestCaseData
+
+ []
+ let ``Part 1, given`` (input : string, output : int) = Day6.part1 input |> shouldEqual output
+
+ []
+ let ``Part 1`` () =
+ let input = Assembly.readResource "Day6.txt"
+
+ Day6.part1 (input.TrimEnd ()) |> shouldEqual 1544
+
+ let part2Data =
+ [
+ "bvwbjplbgvbhsrlpgdmjqwftvncz", 23
+ "nppdvjthqldpwncqszvftbrmjlhg", 23
+ "nznrnfrfntjfmvfwmzdfjlvtqnbhcprsg", 29
+ "zcfzfwzzqfrljwzlrfnpqdbhtmscgvjw", 26
+ ]
+ |> List.map TestCaseData
+
+ []
+ let ``Part 2, given`` (input : string, output : int) = Day6.part2 input |> shouldEqual output
+
+ []
+ let ``Part 2`` () =
+ let input = Assembly.readResource "Day6.txt"
+ Day6.part2 input |> shouldEqual 2145
diff --git a/AdventOfCode2022.Test/Inputs/Day6.txt b/AdventOfCode2022.Test/Inputs/Day6.txt
new file mode 100644
index 0000000..38d36ba
--- /dev/null
+++ b/AdventOfCode2022.Test/Inputs/Day6.txt
@@ -0,0 +1 @@
+mgwwjddqzqdqsstctjjsdjsdsrsfsmfsfwwltwlwhwnhhlffzddgffwlffbsfshfshhgvvdrrltlzlnzznrrnrsnnhgnnfjnnvpnnbjjnwwrcwrrhlhvlhhmzmqzqrqtqmqpmpwwmssgsrgrgtgmtgmtgtdtvdvmvsvsbvsbvbtthmmftmmdnmddcrcvcrrfjfhhfjhffjllcpllmcctjtrttwmtwmwffrlrqlqzzpddsqdqqgjqgjgngwnncjnnvsnswwbzbtzzflzzqsqbsbvbmbnnjpnpnnpfpmpmnpmmjljtltssqnsqslstswtwswwjddvmmzlzqlzqzqjjlttmtrtbtmtgmtmsttrctrrsqrqvvrzrcrhhlnhllbfbtthrhdhllmwlmlgglgsgmgsmszzprpwpfprfftffpssjzjgzjzddqfqmmwqwvwlvlqqtbtwwrwttmsmppbmmpcmctcnnhssnjncnlcnctcjjrzrwrfwfcwffczztrtsrtstlsssljssmvssjzssrqqrcqqwlqwlwffsflssrrzhzzhrzzdgdppspwplpqptttvddggzszccrrnzzwwdwjddrvvwggpvgpvvhdhqddffrnngcncjcjlcchrrftrrjccrcrqqgcglcgcscmmlzmmtcmcffwfcfrcrggdmggdvvnrvnnphnngzzpdpgpspqqgrrnffmfpmffmgfmmjmzztlljlggljjcnnrqnqpnqndnffnwwbpwpjwjjlslmsmtmtjttsvsggrmmdpmmcjjswsqqwfwwrwffczfzggqvggdlldhllsdsfdsdhhmmzmjjmpjpddsccqrrjhjlhjjcnnpwnnffjwwcsszrrnmnsmnnjbnndwnnnhnwwjtwtlwtwqqbnqnbnqqfjfdjdbbwbqwqpqggbcbhhtrtqrrddpdwdlwdddzvzwvvdfdpdcdvdtdpttwwdzdzmdmqmzmnzmnmhmwmjwwshhcqcpcvvzgzdggnjnnhwnhhswwvccqrqlqggcngnmggmffblbglltlstshhrjjlvlppsqslljtjtgglvltvlvmllhrhdrrmqrmqmjjdcjjppqwwllvsvsrszslsvvghvvhmmfbfvfpfmmvdvppwggtrrjvvsbbzffbmffpqqqhnhncclzczwcwpwssrprfrsrbsbnbvnnwzwqqpsqsspmssztssstrtcczsznzvvpvttnssdjdhjddngdgvvmsszbzsbsmbbgsbgsgmmhwhghrhjhphshchgglmlvlhlbhlldwdggdsscvcbcssfbbvggvwwtstltrrwttjdtdvttlsttfhfmhhcbclbcbffqqslshlldhdqhhjwwlffrbrdbrrgcrrfmffbhhlslrslrslrlsrsnsnvvqfqnnfdfmfmttmcmcrrcmmmjttjvtvvjbjqjnnbtbnblbtlblplgltlqltlztzvvtdvvtpvvwdwfflbflfrrhbrbbmjmcjmccztzwwjzwwzwdzdnnwcclbllqgghjhlhthwrdglrmcpbmtrnrdtvjrpmzqmljzzrtpzsrhnjrsdmpnsgdhvqchcfqjqdncjqfnscwjqvszpzzfhpjljmvsqnjzmrsgsbzlvrddtdmwbwwgprlvdfflrpztdzrhtmlzrrtdmpmcprqzzwlnmfjvsrltfjgcnnfllnzmbjcbthvbffczsspmczrpgpdjmvrvfmprfmnqdcnfwwvgdrwvrbtlqmhrrjvtrmmgrlprtnzdlszgbtbwztdrmpmlfblshzcnsczlblgwzrpnlccwhmcqhssmpznbdnnqgzzmjprjttdjhmjbmgqvzblsjwmplzsthrswhsdbvtqgrfzmbpqtpqgqdqcvzlgjrtvrhvzgmcmrwdmfpdvjddsmmsnvrdgnsbsdzcbprbqchqcgnwmfsrmqtrcdhdtzztbvmpblftwqlmlmmjcjhhjlgnnhljnncvbnjhgbjrltlwscswgvqmcnssbcdrtbgnhgmpmvjwtrbrbrdbdqfrncvhdstwztwcpbjrjwzmdlwvlvmsrhghjwjnjstbcqjqtjrgcvhzjdhdgbgdlhvjmztwvhgzzggwwhhhzvtrldchztmwfjvnqnvhnwpfvzzvnlvsccmvsngzgtnttssmdmhwzlhtpnfhczsdfnrstbwvwpqmslcvpvhfzttzhsgzpbhqdtswshljpncznjhzmgvvbcllmzprhrvwljwcjpcdqmwbzvsdcgtmwnrhswsgqhwpwhbjpnhnpjvgsqcjltzrqvqfflcdcvpwnznvtqbfbtlpmtdgbbwdwncqsqnbtgfdzzqzzvjnwmzdmlgstmnjwznjqghglvmwjzlqrnddcqhgndlhlbmqdhrqgrjqztnhpzssnwmrqclmwpgbvfrvgqqvtthznsqwgndjrprbgrhcvhpzbfhdmgnhsrqjvjstbtmnltsbjfzczvjqnhtldqclsflbhvvlzjwrqqgbgpwqwpfjctqpzdqwcfstmwbzgrgrtzngljjnvtggrqcbgjwtqsdgwmfjqppnzgfsfdmlctztbhnntnntdlvrsdvnllvmpggjzspqfhzwrttwzpqrnqjhmpjnmrzrpnqzshcqgctbtflqflcrzpmnphgbbghhwzplljwngbtffwmrwggdztvtfgwldlswqvjptvbfvnbpglhgrdgcfmvrslqldmwjqvjpvwgpjddvglllvpqwvbchqsmjrncgvgmqbsbcwfbsbpqcqzjfpcdzszgmvqgqjlflpfzbsrhsrzrdbpssrjbcfhvztftlzqpsglpwhbscgwdlbgghzsbwznnbgnnsgjghmmpmmrmqmdhnflgvgprqfcbpzbcpjscvnpfrmtvzsbflmffvcfsvdsggzdqtppcjzphcqwrqtrczqmwcdmdqndzmhdpnfqsbndnvjlzrsjzmpcrfgjwccsdtzvslccwhlvzjwjgvwpsnsggmqgsjfbwmjstsgnqmtjhljvfnflnngdrqvscwlqqdsglhghczhjdvgrjcqblmncdbjvsbwgptgpvvzhcjgjnvttrgzrjnqlvfbrmpzdcbbnnrqptpzpssznbsrstdphbgdrsnrhcjwwgsncdzvqfnmnvqcmcgdgjdbqjzdrvvbvhjdfcqndmqwscmsvppclzrhgbldqtwctbdhpbbwfvwpcpsvddmrhqbhlrrmrblnmqqqbwvcwwbwprlmhtdncmjhmjgphmrrhcdrqgmcrzwsznqzpngbtsvjgglrddhjflbrhvqwmmhmqzhphwnvqwzczdvqjsnlhfqbcgddtwgnlcgbfqmzfpqmnbpvfhdhjlnwtrlmggtbfnfvmqrzjvjjvffctsrwgfcpghhnzqmwtlsfhjrvqpwqhngrhpswslsvtgnbvbmwsfwmpntfsfpshrjzvghhpvnlbmnrhltfpmqdwzfhztvhlmbnmhnbvdzbbtczvwbvwtvjghhjjrtgbrqrhmbgvssstdwztdmdsqtctghjhsnpslqttdlvndmjfnmdzwrblfjqcwptfttvlcgsvwcbmfzbdlmrtchgqlfspwznbzfjthjtfwshqgfsfdsmzsmpptzschlzjshvfwtmpszvrvlggbrgpcnqwndhjjprztdfddblhfljbvttfvhchhdfsftrhccrbncmhwpcpwfqthngcqptmvsmpcswdrdlcbqvvhwmcqqwbzlblrgfcrrndwdvlvnpjvwchzjzmgrqhzzmgqqdsdflpclpdtlhvhcthzjfbvjvzsnbvwfsnglvbnwnbgrqwpbgclhjhztttbjwvmlmmgmzncbwswncqhmcfjfnwnpbrmchhpgwngrfwgdfdqmblwlghdjvdhjftdblrtcvvgbvpmbjhfwgpmghqbqrcpgfvhtvqtlbjdblggcpjzlrhpbsqwntfhbhwwszpdlsgbpfqhvrjrhsldcgvqhqmwdfcrcmhrvvwvbrfsrrcvwzhqqvgltlnhwhdrhrdqsvmdzjwgmqdsccwhcgwltfhdfqpsltjccwsttmrc
diff --git a/AdventOfCode2022.sln b/AdventOfCode2022.sln
index 5723522..0439762 100644
--- a/AdventOfCode2022.sln
+++ b/AdventOfCode2022.sln
@@ -4,6 +4,8 @@ Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "AdventOfCode2022", "AdventO
EndProject
Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "AdventOfCode2022.Test", "AdventOfCode2022.Test\AdventOfCode2022.Test.fsproj", "{F22BC060-E7D0-44EE-95F1-0CEFFD8D46E1}"
EndProject
+Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "AdventOfCode2022.App", "AdventOfCode2022.App\AdventOfCode2022.App.fsproj", "{D6E55366-EEEC-4016-9E0B-62549FE04ADC}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -18,5 +20,9 @@ Global
{F22BC060-E7D0-44EE-95F1-0CEFFD8D46E1}.Debug|Any CPU.Build.0 = Debug|Any CPU
{F22BC060-E7D0-44EE-95F1-0CEFFD8D46E1}.Release|Any CPU.ActiveCfg = Release|Any CPU
{F22BC060-E7D0-44EE-95F1-0CEFFD8D46E1}.Release|Any CPU.Build.0 = Release|Any CPU
+ {D6E55366-EEEC-4016-9E0B-62549FE04ADC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {D6E55366-EEEC-4016-9E0B-62549FE04ADC}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {D6E55366-EEEC-4016-9E0B-62549FE04ADC}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {D6E55366-EEEC-4016-9E0B-62549FE04ADC}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
EndGlobal
diff --git a/AdventOfCode2022/AdventOfCode2022.fsproj b/AdventOfCode2022/AdventOfCode2022.fsproj
index 4626d63..49ff19c 100644
--- a/AdventOfCode2022/AdventOfCode2022.fsproj
+++ b/AdventOfCode2022/AdventOfCode2022.fsproj
@@ -14,6 +14,7 @@
+
diff --git a/AdventOfCode2022/Day1.fs b/AdventOfCode2022/Day1.fs
index b860d93..2036470 100644
--- a/AdventOfCode2022/Day1.fs
+++ b/AdventOfCode2022/Day1.fs
@@ -1,34 +1,44 @@
namespace AdventOfCode2022
open System
+open System.Collections.Generic
[]
module Day1 =
- let counts (lines : string seq) : int list =
- ((0, []), lines)
- ||> Seq.fold (fun (acc, counts) line ->
- if String.IsNullOrWhiteSpace line then
- 0, (acc :: counts)
+ let counts (lines : byref) : int IReadOnlyList =
+ let counts = ResizeArray ()
+ let mutable acc = 0
+
+ for line in lines do
+ if line.IsWhiteSpace () then
+ counts.Add acc
+ acc <- 0
else
- acc + int line, counts
- )
- |> snd
+ acc <- acc + Int32.Parse line
+
+ if acc <> 0 then
+ counts.Add acc
+
+ counts
/// Expects a trailing newline (as is present in the given input data).
- let part1 (lines : string seq) : int = lines |> counts |> List.max
+ let part1 (lines : StringSplitEnumerator) : int =
+ let mutable lines = lines
+ counts &lines |> Seq.max
/// I wanted to save cloning the entire seq, so here is some bonus efficiency.
- let maxThree (inputs : int list) : struct (int * int * int) =
+ let maxThree (inputs : int IReadOnlyList) : struct (int * int * int) =
((struct (Int32.MinValue, Int32.MinValue, Int32.MinValue)), inputs)
- ||> List.fold (fun (struct (max1, max2, max3) as maxes) input ->
+ ||> Seq.fold (fun (struct (max1, max2, max3) as maxes) input ->
if input <= max3 then maxes
elif input <= max2 then struct (max1, max2, input)
elif input <= max1 then struct (max1, input, max2)
else struct (input, max1, max2)
)
- let part2 (lines : string seq) : int =
- let struct (a, b, c) = lines |> counts |> maxThree
+ let part2 (lines : StringSplitEnumerator) : int =
+ let mutable lines = lines
+ let struct (a, b, c) = counts &lines |> maxThree
a + b + c
diff --git a/AdventOfCode2022/Day2.fs b/AdventOfCode2022/Day2.fs
index 3bdcda0..6efe790 100644
--- a/AdventOfCode2022/Day2.fs
+++ b/AdventOfCode2022/Day2.fs
@@ -43,46 +43,54 @@ module RockPaperScissors =
[]
module Day2 =
- let part1 (lines : string seq) : int =
- lines
- |> Seq.filter (not << String.IsNullOrWhiteSpace)
- |> Seq.map (fun s ->
- let s = s.Trim ()
+ let part1 (lines : StringSplitEnumerator) : int =
+ let mutable sum = 0
- if s.Length <> 3 || s.[1] <> ' ' then
- failwithf $"Bad format of string: %s{s}"
+ for line in lines do
+ if not (line.IsWhiteSpace ()) then
+ let line = line.Trim ()
- RockPaperScissors.parse s.[0], RockPaperScissors.parse s.[2]
- )
- |> Seq.map (fun (opponent, self) -> RockPaperScissors.outcome self opponent + RockPaperScissors.shapeScore self)
- |> Seq.sum
+ if line.Length <> 3 || line.[1] <> ' ' then
+ failwithf $"Bad format of string: %s{line.ToString ()}"
+ let opponent = RockPaperScissors.parse line.[0]
+ let self = RockPaperScissors.parse line.[2]
- let part2 (lines : string seq) : int =
- lines
- |> Seq.filter (not << String.IsNullOrWhiteSpace)
- |> Seq.map (fun s ->
- let s = s.Trim ()
+ sum <-
+ sum
+ + RockPaperScissors.outcome self opponent
+ + RockPaperScissors.shapeScore self
- if s.Length <> 3 || s.[1] <> ' ' then
- failwithf $"Bad format of string: %s{s}"
+ sum
- let move = RockPaperScissors.parse s.[0]
+ let part2 (lines : StringSplitEnumerator) : int =
+ let mutable sum = 0
- let myMove =
- match Char.ToLower s.[2] with
- | 'x' ->
- // Need to lose
- RockPaperScissors.wouldBeBeaten move
- | 'y' ->
- // Need to draw
- move
- | 'z' ->
- // Need to win
- RockPaperScissors.wouldBeat move
- | c -> failwithf $"Unexpected strategy: %c{c}"
+ for line in lines do
+ if not (line.IsWhiteSpace ()) then
+ let line = line.Trim ()
- move, myMove
- )
- |> Seq.map (fun (opponent, self) -> RockPaperScissors.outcome self opponent + RockPaperScissors.shapeScore self)
- |> Seq.sum
+ if line.Length <> 3 || line.[1] <> ' ' then
+ failwithf $"Bad format of string: %s{line.ToString ()}"
+
+ let opponent = RockPaperScissors.parse line.[0]
+
+ let self =
+ match Char.ToLower line.[2] with
+ | 'x' ->
+ // Need to lose
+ RockPaperScissors.wouldBeBeaten opponent
+ | 'y' ->
+ // Need to draw
+ opponent
+ | 'z' ->
+ // Need to win
+ RockPaperScissors.wouldBeat opponent
+ | c -> failwithf $"Unexpected strategy: %c{c}"
+
+ sum <-
+ sum
+ + RockPaperScissors.outcome self opponent
+ + RockPaperScissors.shapeScore self
+
+ sum
diff --git a/AdventOfCode2022/Day3.fs b/AdventOfCode2022/Day3.fs
index 1b08f16..ae062c5 100644
--- a/AdventOfCode2022/Day3.fs
+++ b/AdventOfCode2022/Day3.fs
@@ -1,5 +1,7 @@
namespace AdventOfCode2022
+open System
+
[]
type Priority
diff --git a/AdventOfCode2022/Day3Efficient.fs b/AdventOfCode2022/Day3Efficient.fs
index 8d127e9..13a9db8 100644
--- a/AdventOfCode2022/Day3Efficient.fs
+++ b/AdventOfCode2022/Day3Efficient.fs
@@ -68,18 +68,20 @@ module Day3Efficient =
else
go set s (i + 1)
- let part1 (lines : string seq) : int =
- lines
- |> Seq.map (fun s ->
- let s = s.AsSpan().Trim ()
+ let part1 (lines : StringSplitEnumerator) : int =
+ let mutable sum = 0
+
+ for s in lines do
+ let s = s.Trim ()
let set = CharSet.ofSpan (s.Slice (0, s.Length / 2))
- go set (s.Slice (s.Length / 2)) 0
- )
- |> Seq.sum
+ sum <- sum + go set (s.Slice (s.Length / 2)) 0
+
+ sum
let part2 (lines : string seq) : int =
lines
+ |> Seq.filter (not << String.IsNullOrEmpty)
|> Seq.chunkBySize 3
|> Seq.map (fun strArr ->
strArr
diff --git a/AdventOfCode2022/Day4.fs b/AdventOfCode2022/Day4.fs
index 501921b..03991ef 100644
--- a/AdventOfCode2022/Day4.fs
+++ b/AdventOfCode2022/Day4.fs
@@ -22,15 +22,24 @@ module Day4 =
let secondElf2 = secondElf.Slice (secondDashIndex + 1)
(Int32.Parse firstElf1, Int32.Parse firstElf2), (Int32.Parse secondElf1, Int32.Parse secondElf2)
- let part1 (lines : string seq) : int =
- lines
- |> Seq.map (fun s -> parse (s.AsSpan ()))
- |> Seq.filter (fun (firstElf, secondElf) -> fullyContains firstElf secondElf || fullyContains secondElf firstElf
- )
- |> Seq.length
+ let part1 (lines : StringSplitEnumerator) : int =
+ let mutable count = 0
- let part2 (lines : string seq) : int =
- lines
- |> Seq.map (fun s -> parse (s.AsSpan ()))
- |> Seq.filter (fun (firstElf, secondElf) -> overlaps firstElf secondElf)
- |> Seq.length
+ for line in lines do
+ let firstElf, secondElf = parse line
+
+ if fullyContains firstElf secondElf || fullyContains secondElf firstElf then
+ count <- count + 1
+
+ count
+
+ let part2 (lines : StringSplitEnumerator) : int =
+ let mutable count = 0
+
+ for line in lines do
+ let firstElf, secondElf = parse line
+
+ if overlaps firstElf secondElf then
+ count <- count + 1
+
+ count
diff --git a/AdventOfCode2022/Day6.fs b/AdventOfCode2022/Day6.fs
new file mode 100644
index 0000000..6168753
--- /dev/null
+++ b/AdventOfCode2022/Day6.fs
@@ -0,0 +1,31 @@
+namespace AdventOfCode2022
+
+open System
+
+[]
+module Day6 =
+
+ let findDuplicateSorted (a : 'a array) : int ValueOption =
+ let mutable i = 0
+ let mutable result = ValueNone
+
+ while result.IsNone && i + 1 < a.Length do
+ if a.[i] = a.[i + 1] then
+ result <- ValueSome i
+
+ i <- i + 1
+
+ result
+
+ let rec private go (count : int) (s : ReadOnlySpan) (i : int) =
+ let fourChars = s.Slice (i - count + 1, count)
+ let arr = fourChars.ToArray ()
+ Array.sortInPlace arr
+
+ match findDuplicateSorted arr with
+ | ValueSome _ -> go count s (i + 1)
+ | ValueNone -> i + 1
+
+ let part1 (line : string) : int = go 4 (line.AsSpan ()) 3
+
+ let part2 (line : string) : int = go 14 (line.AsSpan ()) 13