Day 6 and standalone app (#7)

This commit is contained in:
Patrick Stevens
2022-12-06 08:25:16 +00:00
committed by GitHub
parent 0a498ac7d4
commit ef903b33a9
18 changed files with 288 additions and 99 deletions

View File

@@ -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

View 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>

View 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

View File

@@ -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>

View File

@@ -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

View File

@@ -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

View File

@@ -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>]

View File

@@ -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

View 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

View File

@@ -0,0 +1 @@
mgwwjddqzqdqsstctjjsdjsdsrsfsmfsfwwltwlwhwnhhlffzddgffwlffbsfshfshhgvvdrrltlzlnzznrrnrsnnhgnnfjnnvpnnbjjnwwrcwrrhlhvlhhmzmqzqrqtqmqpmpwwmssgsrgrgtgmtgmtgtdtvdvmvsvsbvsbvbtthmmftmmdnmddcrcvcrrfjfhhfjhffjllcpllmcctjtrttwmtwmwffrlrqlqzzpddsqdqqgjqgjgngwnncjnnvsnswwbzbtzzflzzqsqbsbvbmbnnjpnpnnpfpmpmnpmmjljtltssqnsqslstswtwswwjddvmmzlzqlzqzqjjlttmtrtbtmtgmtmsttrctrrsqrqvvrzrcrhhlnhllbfbtthrhdhllmwlmlgglgsgmgsmszzprpwpfprfftffpssjzjgzjzddqfqmmwqwvwlvlqqtbtwwrwttmsmppbmmpcmctcnnhssnjncnlcnctcjjrzrwrfwfcwffczztrtsrtstlsssljssmvssjzssrqqrcqqwlqwlwffsflssrrzhzzhrzzdgdppspwplpqptttvddggzszccrrnzzwwdwjddrvvwggpvgpvvhdhqddffrnngcncjcjlcchrrftrrjccrcrqqgcglcgcscmmlzmmtcmcffwfcfrcrggdmggdvvnrvnnphnngzzpdpgpspqqgrrnffmfpmffmgfmmjmzztlljlggljjcnnrqnqpnqndnffnwwbpwpjwjjlslmsmtmtjttsvsggrmmdpmmcjjswsqqwfwwrwffczfzggqvggdlldhllsdsfdsdhhmmzmjjmpjpddsccqrrjhjlhjjcnnpwnnffjwwcsszrrnmnsmnnjbnndwnnnhnwwjtwtlwtwqqbnqnbnqqfjfdjdbbwbqwqpqggbcbhhtrtqrrddpdwdlwdddzvzwvvdfdpdcdvdtdpttwwdzdzmdmqmzmnzmnmhmwmjwwshhcqcpcvvzgzdggnjnnhwnhhswwvccqrqlqggcngnmggmffblbglltlstshhrjjlvlppsqslljtjtgglvltvlvmllhrhdrrmqrmqmjjdcjjppqwwllvsvsrszslsvvghvvhmmfbfvfpfmmvdvppwggtrrjvvsbbzffbmffpqqqhnhncclzczwcwpwssrprfrsrbsbnbvnnwzwqqpsqsspmssztssstrtcczsznzvvpvttnssdjdhjddngdgvvmsszbzsbsmbbgsbgsgmmhwhghrhjhphshchgglmlvlhlbhlldwdggdsscvcbcssfbbvggvwwtstltrrwttjdtdvttlsttfhfmhhcbclbcbffqqslshlldhdqhhjwwlffrbrdbrrgcrrfmffbhhlslrslrslrlsrsnsnvvqfqnnfdfmfmttmcmcrrcmmmjttjvtvvjbjqjnnbtbnblbtlblplgltlqltlztzvvtdvvtpvvwdwfflbflfrrhbrbbmjmcjmccztzwwjzwwzwdzdnnwcclbllqgghjhlhthwrdglrmcpbmtrnrdtvjrpmzqmljzzrtpzsrhnjrsdmpnsgdhvqchcfqjqdncjqfnscwjqvszpzzfhpjljmvsqnjzmrsgsbzlvrddtdmwbwwgprlvdfflrpztdzrhtmlzrrtdmpmcprqzzwlnmfjvsrltfjgcnnfllnzmbjcbthvbffczsspmczrpgpdjmvrvfmprfmnqdcnfwwvgdrwvrbtlqmhrrjvtrmmgrlprtnzdlszgbtbwztdrmpmlfblshzcnsczlblgwzrpnlccwhmcqhssmpznbdnnqgzzmjprjttdjhmjbmgqvzblsjwmplzsthrswhsdbvtqgrfzmbpqtpqgqdqcvzlgjrtvrhvzgmcmrwdmfpdvjddsmmsnvrdgnsbsdzcbprbqchqcgnwmfsrmqtrcdhdtzztbvmpblftwqlmlmmjcjhhjlgnnhljnncvbnjhgbjrltlwscswgvqmcnssbcdrtbgnhgmpmvjwtrbrbrdbdqfrncvhdstwztwcpbjrjwzmdlwvlvmsrhghjwjnjstbcqjqtjrgcvhzjdhdgbgdlhvjmztwvhgzzggwwhhhzvtrldchztmwfjvnqnvhnwpfvzzvnlvsccmvsngzgtnttssmdmhwzlhtpnfhczsdfnrstbwvwpqmslcvpvhfzttzhsgzpbhqdtswshljpncznjhzmgvvbcllmzprhrvwljwcjpcdqmwbzvsdcgtmwnrhswsgqhwpwhbjpnhnpjvgsqcjltzrqvqfflcdcvpwnznvtqbfbtlpmtdgbbwdwncqsqnbtgfdzzqzzvjnwmzdmlgstmnjwznjqghglvmwjzlqrnddcqhgndlhlbmqdhrqgrjqztnhpzssnwmrqclmwpgbvfrvgqqvtthznsqwgndjrprbgrhcvhpzbfhdmgnhsrqjvjstbtmnltsbjfzczvjqnhtldqclsflbhvvlzjwrqqgbgpwqwpfjctqpzdqwcfstmwbzgrgrtzngljjnvtggrqcbgjwtqsdgwmfjqppnzgfsfdmlctztbhnntnntdlvrsdvnllvmpggjzspqfhzwrttwzpqrnqjhmpjnmrzrpnqzshcqgctbtflqflcrzpmnphgbbghhwzplljwngbtffwmrwggdztvtfgwldlswqvjptvbfvnbpglhgrdgcfmvrslqldmwjqvjpvwgpjddvglllvpqwvbchqsmjrncgvgmqbsbcwfbsbpqcqzjfpcdzszgmvqgqjlflpfzbsrhsrzrdbpssrjbcfhvztftlzqpsglpwhbscgwdlbgghzsbwznnbgnnsgjghmmpmmrmqmdhnflgvgprqfcbpzbcpjscvnpfrmtvzsbflmffvcfsvdsggzdqtppcjzphcqwrqtrczqmwcdmdqndzmhdpnfqsbndnvjlzrsjzmpcrfgjwccsdtzvslccwhlvzjwjgvwpsnsggmqgsjfbwmjstsgnqmtjhljvfnflnngdrqvscwlqqdsglhghczhjdvgrjcqblmncdbjvsbwgptgpvvzhcjgjnvttrgzrjnqlvfbrmpzdcbbnnrqptpzpssznbsrstdphbgdrsnrhcjwwgsncdzvqfnmnvqcmcgdgjdbqjzdrvvbvhjdfcqndmqwscmsvppclzrhgbldqtwctbdhpbbwfvwpcpsvddmrhqbhlrrmrblnmqqqbwvcwwbwprlmhtdncmjhmjgphmrrhcdrqgmcrzwsznqzpngbtsvjgglrddhjflbrhvqwmmhmqzhphwnvqwzczdvqjsnlhfqbcgddtwgnlcgbfqmzfpqmnbpvfhdhjlnwtrlmggtbfnfvmqrzjvjjvffctsrwgfcpghhnzqmwtlsfhjrvqpwqhngrhpswslsvtgnbvbmwsfwmpntfsfpshrjzvghhpvnlbmnrhltfpmqdwzfhztvhlmbnmhnbvdzbbtczvwbvwtvjghhjjrtgbrqrhmbgvssstdwztdmdsqtctghjhsnpslqttdlvndmjfnmdzwrblfjqcwptfttvlcgsvwcbmfzbdlmrtchgqlfspwznbzfjthjtfwshqgfsfdsmzsmpptzschlzjshvfwtmpszvrvlggbrgpcnqwndhjjprztdfddblhfljbvttfvhchhdfsftrhccrbncmhwpcpwfqthngcqptmvsmpcswdrdlcbqvvhwmcqqwbzlblrgfcrrndwdvlvnpjvwchzjzmgrqhzzmgqqdsdflpclpdtlhvhcthzjfbvjvzsnbvwfsnglvbnwnbgrqwpbgclhjhztttbjwvmlmmgmzncbwswncqhmcfjfnwnpbrmchhpgwngrfwgdfdqmblwlghdjvdhjftdblrtcvvgbvpmbjhfwgpmghqbqrcpgfvhtvqtlbjdblggcpjzlrhpbsqwntfhbhwwszpdlsgbpfqhvrjrhsldcgvqhqmwdfcrcmhrvvwvbrfsrrcvwzhqqvgltlnhwhdrhrdqsvmdzjwgmqdsccwhcgwltfhdfqpsltjccwsttmrc

View File

@@ -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

View File

@@ -14,6 +14,7 @@
<Compile Include="Day3Efficient.fs" />
<Compile Include="Day4.fs" />
<Compile Include="Day5.fs" />
<Compile Include="Day6.fs" />
</ItemGroup>
</Project>

View File

@@ -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

View File

@@ -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

View File

@@ -1,5 +1,7 @@
namespace AdventOfCode2022
open System
[<Measure>]
type Priority

View File

@@ -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

View File

@@ -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
View 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