mirror of
https://github.com/Smaug123/AdventOfCode2022
synced 2025-10-05 01:28:39 +00:00
Day 6 and standalone app (#7)
This commit is contained in:
2
.github/workflows/dotnet.yaml
vendored
2
.github/workflows/dotnet.yaml
vendored
@@ -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
|
||||
|
22
AdventOfCode2022.App/AdventOfCode2022.App.fsproj
Normal file
22
AdventOfCode2022.App/AdventOfCode2022.App.fsproj
Normal file
@@ -0,0 +1,22 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net7.0</TargetFramework>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Include="Program.fs" />
|
||||
<EmbeddedResource Include="..\AdventOfCode2022.Test\Inputs\Day1.txt" />
|
||||
<EmbeddedResource Include="..\AdventOfCode2022.Test\Inputs\Day2.txt" />
|
||||
<EmbeddedResource Include="..\AdventOfCode2022.Test\Inputs\Day3.txt" />
|
||||
<EmbeddedResource Include="..\AdventOfCode2022.Test\Inputs\Day4.txt" />
|
||||
<EmbeddedResource Include="..\AdventOfCode2022.Test\Inputs\Day5.txt" />
|
||||
<EmbeddedResource Include="..\AdventOfCode2022.Test\Inputs\Day6.txt" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\AdventOfCode2022\AdventOfCode2022.fsproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
63
AdventOfCode2022.App/Program.fs
Normal file
63
AdventOfCode2022.App/Program.fs
Normal file
@@ -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<Dummy>
|
||||
|
||||
use stream = asm.GetManifestResourceStream (sprintf "AdventOfCode2022.App.%s" name)
|
||||
|
||||
use reader = new StreamReader (stream)
|
||||
reader.ReadToEnd ()
|
||||
|
||||
[<EntryPoint>]
|
||||
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
|
@@ -13,11 +13,13 @@
|
||||
<Compile Include="Day3.fs" />
|
||||
<Compile Include="Day4.fs" />
|
||||
<Compile Include="Day5.fs" />
|
||||
<Compile Include="Day6.fs" />
|
||||
<EmbeddedResource Include="Inputs\Day1.txt" />
|
||||
<EmbeddedResource Include="Inputs\Day2.txt" />
|
||||
<EmbeddedResource Include="Inputs\Day3.txt" />
|
||||
<EmbeddedResource Include="Inputs\Day4.txt" />
|
||||
<EmbeddedResource Include="Inputs\Day5.txt" />
|
||||
<EmbeddedResource Include="Inputs\Day6.txt" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
@@ -1,6 +1,5 @@
|
||||
namespace AdventOfCode2022.Test
|
||||
|
||||
open System
|
||||
open AdventOfCode2022
|
||||
open NUnit.Framework
|
||||
open FsUnitTyped
|
||||
@@ -28,18 +27,18 @@ module TestDay1 =
|
||||
[<Test>]
|
||||
let ``Part 1`` () =
|
||||
let input = Assembly.readResource "Day1.txt"
|
||||
input.Split '\n' |> Day1.part1 |> shouldEqual 66306
|
||||
Day1.part1 (StringSplitEnumerator.make '\n' input) |> shouldEqual 66306
|
||||
|
||||
[<Test>]
|
||||
let ``Part 2`` () =
|
||||
let input = Assembly.readResource "Day1.txt"
|
||||
input.Split '\n' |> Day1.part2 |> shouldEqual 195292
|
||||
Day1.part2 (StringSplitEnumerator.make '\n' input) |> shouldEqual 195292
|
||||
|
||||
[<Test>]
|
||||
let ``Part 1, given example`` () =
|
||||
testInput.Split Environment.NewLine |> Day1.part1 |> shouldEqual 24000
|
||||
Day1.part1 (StringSplitEnumerator.make '\n' testInput) |> shouldEqual 24000
|
||||
|
||||
|
||||
[<Test>]
|
||||
let ``Part 2, given example`` () =
|
||||
testInput.Split Environment.NewLine |> Day1.part2 |> shouldEqual 45000
|
||||
Day1.part2 (StringSplitEnumerator.make '\n' testInput) |> shouldEqual 45000
|
||||
|
@@ -15,19 +15,19 @@ C Z"""
|
||||
|
||||
[<Test>]
|
||||
let ``Part 1, given`` () =
|
||||
testInput.Split Environment.NewLine |> Day2.part1 |> shouldEqual 15
|
||||
Day2.part1 (StringSplitEnumerator.make '\n' testInput) |> shouldEqual 15
|
||||
|
||||
[<Test>]
|
||||
let ``Part 1`` () =
|
||||
let input = Assembly.readResource "Day2.txt"
|
||||
input.Split '\n' |> Day2.part1 |> shouldEqual 9651
|
||||
Day2.part1 (StringSplitEnumerator.make '\n' input) |> shouldEqual 9651
|
||||
|
||||
|
||||
[<Test>]
|
||||
let ``Part 2, given`` () =
|
||||
testInput.Split Environment.NewLine |> Day2.part2 |> shouldEqual 12
|
||||
Day2.part2 (StringSplitEnumerator.make '\n' testInput) |> shouldEqual 12
|
||||
|
||||
[<Test>]
|
||||
let ``Part 2`` () =
|
||||
let input = Assembly.readResource "Day2.txt"
|
||||
input.Split '\n' |> Day2.part2 |> shouldEqual 10560
|
||||
Day2.part2 (StringSplitEnumerator.make '\n' input) |> shouldEqual 10560
|
||||
|
@@ -9,8 +9,11 @@ open AdventOfCode2022
|
||||
[<TestFixture true>]
|
||||
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<Priority>
|
||||
|
||||
@@ -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<Priority>
|
||||
input |> part1 |> shouldEqual 8018<Priority>
|
||||
|
||||
|
||||
[<Test>]
|
||||
|
@@ -1,6 +1,5 @@
|
||||
namespace AdventOfCode2022.Test
|
||||
|
||||
open System
|
||||
open NUnit.Framework
|
||||
open FsUnitTyped
|
||||
open AdventOfCode2022
|
||||
@@ -18,32 +17,20 @@ module TestDay4 =
|
||||
|
||||
[<Test>]
|
||||
let ``Part 1, given`` () =
|
||||
testInput
|
||||
|> fun s -> s.Split Environment.NewLine
|
||||
|> Day4.part1
|
||||
|> shouldEqual 2
|
||||
Day4.part1 (StringSplitEnumerator.make '\n' testInput) |> shouldEqual 2
|
||||
|
||||
[<Test>]
|
||||
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
|
||||
|
||||
[<Test>]
|
||||
let ``Part 2, given`` () =
|
||||
testInput
|
||||
|> fun s -> s.Split Environment.NewLine
|
||||
|> Day4.part2
|
||||
|> shouldEqual 4
|
||||
Day4.part2 (StringSplitEnumerator.make '\n' testInput) |> shouldEqual 4
|
||||
|
||||
[<Test>]
|
||||
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
|
||||
|
45
AdventOfCode2022.Test/Day6.fs
Normal file
45
AdventOfCode2022.Test/Day6.fs
Normal file
@@ -0,0 +1,45 @@
|
||||
namespace AdventOfCode2022.Test
|
||||
|
||||
open System
|
||||
open NUnit.Framework
|
||||
open FsUnitTyped
|
||||
open AdventOfCode2022
|
||||
|
||||
[<TestFixture>]
|
||||
module TestDay6 =
|
||||
|
||||
let testInput1 =
|
||||
[
|
||||
"mjqjpqmgbljsphdztnvjfqwrcgsmlb", 7
|
||||
"bvwbjplbgvbhsrlpgdmjqwftvncz", 5
|
||||
"nppdvjthqldpwncqszvftbrmjlhg", 6
|
||||
"nznrnfrfntjfmvfwmzdfjlvtqnbhcprsg", 10
|
||||
"zcfzfwzzqfrljwzlrfnpqdbhtmscgvjw", 11
|
||||
]
|
||||
|> List.map TestCaseData
|
||||
|
||||
[<TestCaseSource(nameof (testInput1))>]
|
||||
let ``Part 1, given`` (input : string, output : int) = Day6.part1 input |> shouldEqual output
|
||||
|
||||
[<Test>]
|
||||
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
|
||||
|
||||
[<TestCaseSource(nameof (part2Data))>]
|
||||
let ``Part 2, given`` (input : string, output : int) = Day6.part2 input |> shouldEqual output
|
||||
|
||||
[<Test>]
|
||||
let ``Part 2`` () =
|
||||
let input = Assembly.readResource "Day6.txt"
|
||||
Day6.part2 input |> shouldEqual 2145
|
1
AdventOfCode2022.Test/Inputs/Day6.txt
Normal file
1
AdventOfCode2022.Test/Inputs/Day6.txt
Normal file
@@ -0,0 +1 @@
|
||||
mgwwjddqzqdqsstctjjsdjsdsrsfsmfsfwwltwlwhwnhhlffzddgffwlffbsfshfshhgvvdrrltlzlnzznrrnrsnnhgnnfjnnvpnnbjjnwwrcwrrhlhvlhhmzmqzqrqtqmqpmpwwmssgsrgrgtgmtgmtgtdtvdvmvsvsbvsbvbtthmmftmmdnmddcrcvcrrfjfhhfjhffjllcpllmcctjtrttwmtwmwffrlrqlqzzpddsqdqqgjqgjgngwnncjnnvsnswwbzbtzzflzzqsqbsbvbmbnnjpnpnnpfpmpmnpmmjljtltssqnsqslstswtwswwjddvmmzlzqlzqzqjjlttmtrtbtmtgmtmsttrctrrsqrqvvrzrcrhhlnhllbfbtthrhdhllmwlmlgglgsgmgsmszzprpwpfprfftffpssjzjgzjzddqfqmmwqwvwlvlqqtbtwwrwttmsmppbmmpcmctcnnhssnjncnlcnctcjjrzrwrfwfcwffczztrtsrtstlsssljssmvssjzssrqqrcqqwlqwlwffsflssrrzhzzhrzzdgdppspwplpqptttvddggzszccrrnzzwwdwjddrvvwggpvgpvvhdhqddffrnngcncjcjlcchrrftrrjccrcrqqgcglcgcscmmlzmmtcmcffwfcfrcrggdmggdvvnrvnnphnngzzpdpgpspqqgrrnffmfpmffmgfmmjmzztlljlggljjcnnrqnqpnqndnffnwwbpwpjwjjlslmsmtmtjttsvsggrmmdpmmcjjswsqqwfwwrwffczfzggqvggdlldhllsdsfdsdhhmmzmjjmpjpddsccqrrjhjlhjjcnnpwnnffjwwcsszrrnmnsmnnjbnndwnnnhnwwjtwtlwtwqqbnqnbnqqfjfdjdbbwbqwqpqggbcbhhtrtqrrddpdwdlwdddzvzwvvdfdpdcdvdtdpttwwdzdzmdmqmzmnzmnmhmwmjwwshhcqcpcvvzgzdggnjnnhwnhhswwvccqrqlqggcngnmggmffblbglltlstshhrjjlvlppsqslljtjtgglvltvlvmllhrhdrrmqrmqmjjdcjjppqwwllvsvsrszslsvvghvvhmmfbfvfpfmmvdvppwggtrrjvvsbbzffbmffpqqqhnhncclzczwcwpwssrprfrsrbsbnbvnnwzwqqpsqsspmssztssstrtcczsznzvvpvttnssdjdhjddngdgvvmsszbzsbsmbbgsbgsgmmhwhghrhjhphshchgglmlvlhlbhlldwdggdsscvcbcssfbbvggvwwtstltrrwttjdtdvttlsttfhfmhhcbclbcbffqqslshlldhdqhhjwwlffrbrdbrrgcrrfmffbhhlslrslrslrlsrsnsnvvqfqnnfdfmfmttmcmcrrcmmmjttjvtvvjbjqjnnbtbnblbtlblplgltlqltlztzvvtdvvtpvvwdwfflbflfrrhbrbbmjmcjmccztzwwjzwwzwdzdnnwcclbllqgghjhlhthwrdglrmcpbmtrnrdtvjrpmzqmljzzrtpzsrhnjrsdmpnsgdhvqchcfqjqdncjqfnscwjqvszpzzfhpjljmvsqnjzmrsgsbzlvrddtdmwbwwgprlvdfflrpztdzrhtmlzrrtdmpmcprqzzwlnmfjvsrltfjgcnnfllnzmbjcbthvbffczsspmczrpgpdjmvrvfmprfmnqdcnfwwvgdrwvrbtlqmhrrjvtrmmgrlprtnzdlszgbtbwztdrmpmlfblshzcnsczlblgwzrpnlccwhmcqhssmpznbdnnqgzzmjprjttdjhmjbmgqvzblsjwmplzsthrswhsdbvtqgrfzmbpqtpqgqdqcvzlgjrtvrhvzgmcmrwdmfpdvjddsmmsnvrdgnsbsdzcbprbqchqcgnwmfsrmqtrcdhdtzztbvmpblftwqlmlmmjcjhhjlgnnhljnncvbnjhgbjrltlwscswgvqmcnssbcdrtbgnhgmpmvjwtrbrbrdbdqfrncvhdstwztwcpbjrjwzmdlwvlvmsrhghjwjnjstbcqjqtjrgcvhzjdhdgbgdlhvjmztwvhgzzggwwhhhzvtrldchztmwfjvnqnvhnwpfvzzvnlvsccmvsngzgtnttssmdmhwzlhtpnfhczsdfnrstbwvwpqmslcvpvhfzttzhsgzpbhqdtswshljpncznjhzmgvvbcllmzprhrvwljwcjpcdqmwbzvsdcgtmwnrhswsgqhwpwhbjpnhnpjvgsqcjltzrqvqfflcdcvpwnznvtqbfbtlpmtdgbbwdwncqsqnbtgfdzzqzzvjnwmzdmlgstmnjwznjqghglvmwjzlqrnddcqhgndlhlbmqdhrqgrjqztnhpzssnwmrqclmwpgbvfrvgqqvtthznsqwgndjrprbgrhcvhpzbfhdmgnhsrqjvjstbtmnltsbjfzczvjqnhtldqclsflbhvvlzjwrqqgbgpwqwpfjctqpzdqwcfstmwbzgrgrtzngljjnvtggrqcbgjwtqsdgwmfjqppnzgfsfdmlctztbhnntnntdlvrsdvnllvmpggjzspqfhzwrttwzpqrnqjhmpjnmrzrpnqzshcqgctbtflqflcrzpmnphgbbghhwzplljwngbtffwmrwggdztvtfgwldlswqvjptvbfvnbpglhgrdgcfmvrslqldmwjqvjpvwgpjddvglllvpqwvbchqsmjrncgvgmqbsbcwfbsbpqcqzjfpcdzszgmvqgqjlflpfzbsrhsrzrdbpssrjbcfhvztftlzqpsglpwhbscgwdlbgghzsbwznnbgnnsgjghmmpmmrmqmdhnflgvgprqfcbpzbcpjscvnpfrmtvzsbflmffvcfsvdsggzdqtppcjzphcqwrqtrczqmwcdmdqndzmhdpnfqsbndnvjlzrsjzmpcrfgjwccsdtzvslccwhlvzjwjgvwpsnsggmqgsjfbwmjstsgnqmtjhljvfnflnngdrqvscwlqqdsglhghczhjdvgrjcqblmncdbjvsbwgptgpvvzhcjgjnvttrgzrjnqlvfbrmpzdcbbnnrqptpzpssznbsrstdphbgdrsnrhcjwwgsncdzvqfnmnvqcmcgdgjdbqjzdrvvbvhjdfcqndmqwscmsvppclzrhgbldqtwctbdhpbbwfvwpcpsvddmrhqbhlrrmrblnmqqqbwvcwwbwprlmhtdncmjhmjgphmrrhcdrqgmcrzwsznqzpngbtsvjgglrddhjflbrhvqwmmhmqzhphwnvqwzczdvqjsnlhfqbcgddtwgnlcgbfqmzfpqmnbpvfhdhjlnwtrlmggtbfnfvmqrzjvjjvffctsrwgfcpghhnzqmwtlsfhjrvqpwqhngrhpswslsvtgnbvbmwsfwmpntfsfpshrjzvghhpvnlbmnrhltfpmqdwzfhztvhlmbnmhnbvdzbbtczvwbvwtvjghhjjrtgbrqrhmbgvssstdwztdmdsqtctghjhsnpslqttdlvndmjfnmdzwrblfjqcwptfttvlcgsvwcbmfzbdlmrtchgqlfspwznbzfjthjtfwshqgfsfdsmzsmpptzschlzjshvfwtmpszvrvlggbrgpcnqwndhjjprztdfddblhfljbvttfvhchhdfsftrhccrbncmhwpcpwfqthngcqptmvsmpcswdrdlcbqvvhwmcqqwbzlblrgfcrrndwdvlvnpjvwchzjzmgrqhzzmgqqdsdflpclpdtlhvhcthzjfbvjvzsnbvwfsnglvbnwnbgrqwpbgclhjhztttbjwvmlmmgmzncbwswncqhmcfjfnwnpbrmchhpgwngrfwgdfdqmblwlghdjvdhjftdblrtcvvgbvpmbjhfwgpmghqbqrcpgfvhtvqtlbjdblggcpjzlrhpbsqwntfhbhwwszpdlsgbpfqhvrjrhsldcgvqhqmwdfcrcmhrvvwvbrfsrrcvwzhqqvgltlnhwhdrhrdqsvmdzjwgmqdsccwhcgwltfhdfqpsltjccwsttmrc
|
@@ -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
|
||||
|
@@ -14,6 +14,7 @@
|
||||
<Compile Include="Day3Efficient.fs" />
|
||||
<Compile Include="Day4.fs" />
|
||||
<Compile Include="Day5.fs" />
|
||||
<Compile Include="Day6.fs" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
@@ -1,34 +1,44 @@
|
||||
namespace AdventOfCode2022
|
||||
|
||||
open System
|
||||
open System.Collections.Generic
|
||||
|
||||
[<RequireQualifiedAccess>]
|
||||
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<StringSplitEnumerator>) : 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
|
||||
|
@@ -43,46 +43,54 @@ module RockPaperScissors =
|
||||
[<RequireQualifiedAccess>]
|
||||
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
|
||||
|
@@ -1,5 +1,7 @@
|
||||
namespace AdventOfCode2022
|
||||
|
||||
open System
|
||||
|
||||
[<Measure>]
|
||||
type Priority
|
||||
|
||||
|
@@ -68,18 +68,20 @@ module Day3Efficient =
|
||||
else
|
||||
go set s (i + 1)
|
||||
|
||||
let part1 (lines : string seq) : int<Priority> =
|
||||
lines
|
||||
|> Seq.map (fun s ->
|
||||
let s = s.AsSpan().Trim ()
|
||||
let part1 (lines : StringSplitEnumerator) : int<Priority> =
|
||||
let mutable sum = 0<Priority>
|
||||
|
||||
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<Priority> =
|
||||
lines
|
||||
|> Seq.filter (not << String.IsNullOrEmpty)
|
||||
|> Seq.chunkBySize 3
|
||||
|> Seq.map (fun strArr ->
|
||||
strArr
|
||||
|
@@ -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
|
||||
|
31
AdventOfCode2022/Day6.fs
Normal file
31
AdventOfCode2022/Day6.fs
Normal file
@@ -0,0 +1,31 @@
|
||||
namespace AdventOfCode2022
|
||||
|
||||
open System
|
||||
|
||||
[<RequireQualifiedAccess>]
|
||||
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<char>) (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
|
Reference in New Issue
Block a user