Compare commits

...

3 Commits

Author SHA1 Message Date
4bb3a94fb2 add quest 3 2025-12-01 14:45:14 +01:00
94ff88dcba update gitignore 2025-12-01 14:45:00 +01:00
31daf11e94 quest 2 complete 2025-11-06 23:10:40 +01:00
11 changed files with 280 additions and 4 deletions

View File

@@ -1,4 +1,64 @@
bin
obj
.idea
*.DotSettings*
*.DotSettings*
bin/*
obj/*
## A streamlined .gitignore for modern .NET projects
## including temporary files, build results, and
## files generated by popular .NET tools. If you are
## developing with Visual Studio, the VS .gitignore
## https://github.com/github/gitignore/blob/main/VisualStudio.gitignore
## has more thorough IDE-specific entries.
##
## Get latest from https://github.com/github/gitignore/blob/main/Dotnet.gitignore
# Build results
[Dd]ebug/
[Dd]ebugPublic/
[Rr]elease/
[Rr]eleases/
x64/
x86/
[Ww][Ii][Nn]32/
[Aa][Rr][Mm]/
[Aa][Rr][Mm]64/
bld/
[Bb]in/
[Oo]bj/
[Ll]og/
[Ll]ogs/
# .NET Core
project.lock.json
project.fragment.lock.json
artifacts/
# ASP.NET Scaffolding
ScaffoldingReadMe.txt
# NuGet Packages
*.nupkg
# NuGet Symbol Packages
*.snupkg
# dotenv environment variables file
.env
# Others
~$*
*~
CodeCoverage/
# MSBuild Binary and Structured Log
*.binlog
# MSTest test Results
[Tt]est[Rr]esult*/
[Bb]uild[Ll]og.*
# NUnit
*.VisualState.xml
TestResult.xml
nunit-*.xml

View File

@@ -19,9 +19,39 @@
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="Inputs\Quest02\Q02_P01.txt">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="Inputs\Quest02\Q02_P02.txt">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="Inputs\Quest02\Q02_P03.txt">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="Inputs\Quest03\Q03_P01.txt">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="Inputs\Quest03\Q03_P02.txt">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="Inputs\Quest03\Q03_P03.txt">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Compile Include="Helpers.fs" />
<Compile Include="Quest01.fs" />
<Compile Include="Quest02.fs" />
<Compile Include="Quest03.fs" />
<Compile Include="Program.fs"/>
</ItemGroup>
<ItemGroup>
<PackageReference Include="FSharp.Collections.ParallelSeq" Version="1.2.0" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1 @@
A=[-3284,68783]

View File

@@ -0,0 +1 @@
A=[-3284,68783]

View File

@@ -0,0 +1 @@
8,55,7,42,40,45,33,31,64,60,49,66,83,78,33,23,72,15,35,11,84,30,44,66,20,66,88,7,3,51,85,54,38,88,2,37,2,56,47,40,82,79,51,18,81,69,46,52,56,5,82,73,15,76,13,11,31,43,50,89,79,85,11,44,26,6,12,49,82,28,66,36,66,22,44,39,2,39,83,15,63,82,10,73,20,64,17,25,43,72,54,47,30,15,46,87,85,17,57,6

View File

@@ -0,0 +1 @@
88,59,145,183,26,132,49,153,120,180,134,184,132,6,29,57,137,105,166,61,105,49,10,55,149,145,165,88,56,140,78,78,167,84,82,22,21,185,63,38,65,55,140,27,109,104,156,101,156,7,145,30,127,88,145,44,113,142,14,60,77,92,147,76,74,189,104,186,100,175,118,104,94,182,7,52,110,12,132,18,123,161,148,174,150,18,66,107,179,81,178,26,136,23,92,95,10,10,34,4,134,138,107,12,27,26,76,77,31,44,113,17,54,31,71,22,63,172,145,65,138,47,119,56,50,40,162,150,56,85,65,27,4,172,113,26,59,104,86,158,67,93,134,47,178,115,3,7,24,70,53,159,170,183,165,129,92,36,104,110,120,8,2,133,60,118,181,70,132,67,180,133,185,111,107,93,10,19,154,185,29,144,79,3,14,5,15,132,179,18,77,140,68,20,109,43,36,115,77,83,49,80,189,120,6,152,16,98,144,171,83,88,165,6,52,157,102,119,158,127,138,11,48,142,21,159,55,173,45,176,9,141,109,44,36,166,143,144,138,134,86,129,106,80,41,100,56,143,125,73,94,86,51,137,29,75,107,117,110,145,161,70,180,26,45,146,123,150,28,68,6,148,40,84,134,121,113,29,148,19,174,140,147,147,94,98,18,149,59,156,22,83,40,145,180,86,44,3,118,26

File diff suppressed because one or more lines are too long

View File

@@ -5,9 +5,10 @@ open EveryBodyCodes2025
let main argv =
try
printfn $"{Quest01.part1()}"
printfn $"{Quest01.part2()}"
printfn $"{Quest01.part3()}"
printfn $"{Quest02.part1()}"
//Quest02.test1
printfn $"{Quest02.part2()}"
printfn $"{Quest02.part3()}"
with exn ->
printfn $"{exn}"
0

View File

@@ -0,0 +1,66 @@
module EveryBodyCodes2025.Quest02
open System.IO
open System.Text.RegularExpressions
open FSharp.Collections.ParallelSeq
open Checked
[<Struct>]
type ComplexNumber =
{X: int64; Y: int64}
static member (+) (a: ComplexNumber, b: ComplexNumber) = {X = a.X + b.X; Y = a.Y + b.Y }
static member (*) (a: ComplexNumber, b: ComplexNumber) = { X = ( a.X * b.X ) - (a.Y * b.Y); Y = (a.X * b.Y) + (a.Y * b.X) }
static member (/) (a: ComplexNumber, b: ComplexNumber) = { X = a.X / b.X; Y = a.Y / b.Y }
override this.ToString() = $"[{this.X},{this.Y}]"
let parseInput file =
File.ReadAllLines file
|> fun lines ->
let reg = Regex(@"A=\[(-?\d+),(-?\d+)\]")
let res = reg.Match(lines[0])
match res.Success with
| true ->
let x = int64 res.Groups[1].Value
let y = int64 res.Groups[2].Value
{X = x; Y = y}
| false -> failwith "failed to parse"
let part1 () =
parseInput "Inputs/Quest02/Q02_P01.txt"
|> fun a ->
[1..3]
|> List.fold (fun acc _ -> (acc * acc) / { X = 10; Y = 10 } + a ) {X = 0; Y = 0}
let cycle p =
let rec iterate current iteration =
if iteration = 100 then Some current
else
let next = (current * current) / {X = 100_000; Y = 100_000 } + p
if abs(next.X) > 1_000_000 || abs(next.Y) > 1_000_000 then
None
else iterate next (iteration + 1)
iterate { X = 0; Y = 0 } 0
let part2 () =
parseInput "Inputs/Quest02/Q02_P02.txt"
|> fun a ->
seq {
for y in 0..100 do
for x in 0..100 do
yield {X = a.X + (int64 x * 10L); Y = a.Y + (int64 y * 10L)}
}
|> PSeq.choose cycle
|> PSeq.distinct
|> PSeq.length
let part3 () =
parseInput "Inputs/Quest02/Q02_P03.txt"
|> fun a ->
seq {
for y in 0..1000 do
for x in 0..1000 do
yield {X = a.X + (int64 x); Y = a.Y + (int64 y)}
}
|> PSeq.choose cycle
|> PSeq.length

View File

@@ -0,0 +1,113 @@
module EveryBodyCodes2025.Quest03
open System.Collections.Generic
open System.IO
open System.Linq
open System
open System.Runtime.CompilerServices
type Crate = int
// sorted set because only one item can be in at a time. The SortedSet is unnecessary here since the inputs are already sorted
type CrateSet = SortedSet<Crate>
let inline newCrateSet crate =
let cs = CrateSet()
cs.Add(crate) |> ignore
cs
type Extensions() =
[<Extension>]
static member inline SmallestCrate (crates:CrateSet) : Crate option = match crates.Min with | 0 -> None | x -> Some x
[<Extension>]
static member inline LargestCrate (crates:CrateSet) : Crate option = match crates.Max with | 0 -> None | x -> Some x
/// take a sorted input (not verified) and prioritize insertion into the first found list.
/// This results in cascading to the "next best fit", but this approach relies on sorted inputs.
let packEfficiently allCrates =
allCrates
|> Seq.fold (fun sortedCrates next ->
// find the first crate set that can hold the next item and put it in there
match sortedCrates with
| [] -> [newCrateSet next]
| items ->
match List.tryFind (fun (i:CrateSet) ->
match i.SmallestCrate() with
| Some c when c > next -> true
| _ -> false) items with
| None ->
let cs = newCrateSet next
items@[cs] // appending to the end is less efficient for linked lists, but ensures that the first one gets the best goodies
| Some crates ->
if not (crates.Add(next)) then failwith "failed to add" // really wrong if this happens
items
) []
let parseInput file =
File.ReadLines(file)
|> Enumerable.First
|> _.Split(",")
|> Array.map Int32.Parse
let part1Test() =
"10,5,1,10,3,8,5,2,2"
|> _.Split(",")
|> Array.map Int32.Parse
|> Enumerable.OrderDescending
|> packEfficiently
|> _.Max(_.Sum())
let part1 () =
parseInput "Inputs/Quest03/Q03_P01.txt"
|> Enumerable.OrderDescending
|> packEfficiently
|> _.Max(_.Sum())
// Part 2 I thought would be better to invert the sorting (asc vs desc) to part 1. It also adds an add filter to 20 items.
let part2Impl allCrates =
allCrates
|> Seq.fold (fun sortedCrates next ->
//smallest set of max size - sort ascending, add up until there are 20 items, then it is not eligible
match sortedCrates with
| [] ->
let cs = CrateSet()
cs.Add(next) |> ignore
[cs]
| items ->
match List.tryFind (fun (i:CrateSet) ->
if i.Count >= 20 then false
else
match i.LargestCrate() with
| Some c when c < next -> true
| _ -> false) items with
| None ->
let cs = CrateSet()
match cs.Add(next) with | true -> () | false -> failwith "failed to add"
items@[cs]
| Some crates ->
match crates.Add(next) with | true -> () | false -> failwith "failed to add"
items
) []
let part2Test() =
"4,51,13,64,57,51,82,57,16,88,89,48,32,49,49,2,84,65,49,43,9,13,2,3,75,72,63,48,61,14,40,77"
|> _.Split(",")
|> Array.map Int32.Parse
|> Enumerable.Order
|> part2Impl
|> List.filter (fun x -> x.Count = 20)
|> _.Min(_.Sum())
let part2() =
parseInput "Inputs/Quest03/Q03_P02.txt"
|> Enumerable.Order
|> part2Impl
|> List.filter (fun x -> x.Count = 20)
|> _.Min(_.Sum())
let part3() =
parseInput "Inputs/Quest03/Q03_P03.txt"
|> Enumerable.OrderDescending
|> packEfficiently
|> _.Count()