Add day 3
This commit is contained in:
@@ -0,0 +1,13 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Include="Arr2D.fs" />
|
||||
<Compile Include="Day3.fs" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
102
AdventOfCode2023.FSharp/AdventOfCode2023.FSharp.Lib/Arr2D.fs
Normal file
102
AdventOfCode2023.FSharp/AdventOfCode2023.FSharp.Lib/Arr2D.fs
Normal file
@@ -0,0 +1,102 @@
|
||||
namespace AdventOfCode2023
|
||||
|
||||
#if DEBUG
|
||||
#else
|
||||
#nowarn "9"
|
||||
#endif
|
||||
|
||||
open Microsoft.FSharp.NativeInterop
|
||||
|
||||
[<Struct>]
|
||||
#if DEBUG
|
||||
type Arr2D<'a> =
|
||||
{
|
||||
Elements : 'a array
|
||||
Width : int
|
||||
}
|
||||
|
||||
member this.Height = this.Elements.Length / this.Width
|
||||
#else
|
||||
type Arr2D<'a when 'a : unmanaged> =
|
||||
{
|
||||
Elements : nativeptr<'a>
|
||||
Length : int
|
||||
Width : int
|
||||
}
|
||||
|
||||
member this.Height = this.Length / this.Width
|
||||
#endif
|
||||
|
||||
[<RequireQualifiedAccess>]
|
||||
module Arr2D =
|
||||
|
||||
/// It's faster to iterate forward over the first argument, `x`.
|
||||
let inline get (arr : Arr2D<'a>) (x : int) (y : int) : 'a =
|
||||
#if DEBUG
|
||||
arr.Elements.[y * arr.Width + x]
|
||||
#else
|
||||
NativePtr.get arr.Elements (y * arr.Width + x)
|
||||
#endif
|
||||
|
||||
let inline set (arr : Arr2D<'a>) (x : int) (y : int) (newVal : 'a) : unit =
|
||||
#if DEBUG
|
||||
arr.Elements.[y * arr.Width + x] <- newVal
|
||||
#else
|
||||
NativePtr.write (NativePtr.add arr.Elements (y * arr.Width + x)) newVal
|
||||
#endif
|
||||
|
||||
#if DEBUG
|
||||
let create (width : int) (height : int) (value : 'a) : Arr2D<'a> =
|
||||
let arr = Array.create (width * height) value
|
||||
|
||||
{
|
||||
Width = width
|
||||
Elements = arr
|
||||
}
|
||||
#else
|
||||
/// The input array must be at least of size width * height
|
||||
let create (arr : nativeptr<'a>) (width : int) (height : int) (value : 'a) : Arr2D<'a> =
|
||||
{
|
||||
Width = width
|
||||
Elements = arr
|
||||
Length = width * height
|
||||
}
|
||||
#endif
|
||||
|
||||
[<RequiresExplicitTypeArguments>]
|
||||
#if DEBUG
|
||||
let zeroCreate<'a when 'a : unmanaged> (width : int) (height : int) : Arr2D<'a> =
|
||||
{
|
||||
Elements = Array.zeroCreate (width * height)
|
||||
Width = width
|
||||
}
|
||||
#else
|
||||
let zeroCreate<'a when 'a : unmanaged> (elts : nativeptr<'a>) (width : int) (height : int) : Arr2D<'a> =
|
||||
{
|
||||
Elements = elts
|
||||
Width = width
|
||||
Length = width * height
|
||||
}
|
||||
#endif
|
||||
|
||||
/// The closure is given x and then y.
|
||||
#if DEBUG
|
||||
let inline init (width : int) (height : int) (f : int -> int -> 'a) : Arr2D<'a> =
|
||||
let result = zeroCreate<'a> width height
|
||||
#else
|
||||
let inline init (arr : nativeptr<'a>) (width : int) (height : int) (f : int -> int -> 'a) : Arr2D<'a> =
|
||||
let result = zeroCreate<'a> arr width height
|
||||
#endif
|
||||
|
||||
for y = 0 to height - 1 do
|
||||
for x = 0 to width - 1 do
|
||||
set result x y (f x y)
|
||||
|
||||
result
|
||||
|
||||
let inline clear (a : Arr2D<'a>) : unit =
|
||||
#if DEBUG
|
||||
System.Array.Clear a.Elements
|
||||
#else
|
||||
NativePtr.initBlock a.Elements 0uy (uint32 sizeof<'a> * uint32 a.Length)
|
||||
#endif
|
133
AdventOfCode2023.FSharp/AdventOfCode2023.FSharp.Lib/Day3.fs
Normal file
133
AdventOfCode2023.FSharp/AdventOfCode2023.FSharp.Lib/Day3.fs
Normal file
@@ -0,0 +1,133 @@
|
||||
namespace AdventOfCode2023
|
||||
|
||||
open System.Collections.Generic
|
||||
|
||||
[<RequireQualifiedAccess>]
|
||||
module Day3 =
|
||||
let inline private isSymbol (i : byte) =
|
||||
i > 200uy
|
||||
|
||||
let inline private isGear (i : byte) =
|
||||
i = 255uy
|
||||
|
||||
/// Returns the parsed board as a buffer, the length of the buffer (there may be garbage at the end), and
|
||||
/// the number of lines the resulting 2D array has.
|
||||
let parse (fileContents : byte[]) =
|
||||
let mutable lineCount = 0
|
||||
let mutable len = 0
|
||||
let resultArr = Array.zeroCreate fileContents.Length
|
||||
for b in fileContents do
|
||||
if b = byte '.' then
|
||||
resultArr.[len] <- 100uy
|
||||
len <- len + 1
|
||||
elif b = byte '*' then
|
||||
resultArr.[len] <- 255uy
|
||||
len <- len + 1
|
||||
elif byte '0' <= b && b <= byte '9' then
|
||||
resultArr.[len] <- b - byte '0'
|
||||
len <- len + 1
|
||||
elif b = 10uy then
|
||||
lineCount <- lineCount + 1
|
||||
else
|
||||
resultArr.[len] <- 254uy
|
||||
len <- len + 1
|
||||
|
||||
resultArr, len, lineCount
|
||||
|
||||
let part1 (contents : Arr2D<byte>) =
|
||||
let lineLength = contents.Width
|
||||
|
||||
let isNearSymbol (row : int) (numStart : int) (curCol : int) : bool =
|
||||
let mutable isNearSymbol = false
|
||||
if row > 0 then
|
||||
for col = max (numStart - 1) 0 to min curCol (lineLength - 1) do
|
||||
if isSymbol (Arr2D.get contents col (row - 1)) then
|
||||
isNearSymbol <- true
|
||||
if row < contents.Height - 1 then
|
||||
for col = max (numStart - 1) 0 to min curCol (lineLength - 1) do
|
||||
if isSymbol (Arr2D.get contents col (row + 1)) then
|
||||
isNearSymbol <- true
|
||||
if (numStart > 0 && isSymbol (Arr2D.get contents (numStart - 1) row)) || (curCol < lineLength && isSymbol (Arr2D.get contents curCol row)) then
|
||||
isNearSymbol <- true
|
||||
isNearSymbol
|
||||
|
||||
let mutable total = 0
|
||||
for row = 0 to contents.Height - 1 do
|
||||
let mutable currNum = 0
|
||||
let mutable numStart = -1
|
||||
for col = 0 to lineLength - 1 do
|
||||
if Arr2D.get contents col row < 10uy then
|
||||
if numStart = -1 then
|
||||
numStart <- col
|
||||
currNum <- currNum * 10 + int (Arr2D.get contents col row)
|
||||
elif numStart > -1 then
|
||||
if isNearSymbol row numStart col then
|
||||
total <- total + currNum
|
||||
currNum <- 0
|
||||
numStart <- -1
|
||||
|
||||
if numStart >= 0 then
|
||||
if isNearSymbol row numStart lineLength then
|
||||
total <- total + currNum
|
||||
currNum <- 0
|
||||
numStart <- -1
|
||||
|
||||
total
|
||||
|
||||
let part2 (contents : Arr2D<byte>) =
|
||||
let lineLength = contents.Width
|
||||
|
||||
let isNearGear (row : int) (numStart : int) (curCol : int) : (int * int) IReadOnlyList =
|
||||
let gearsNear = ResizeArray ()
|
||||
if row > 0 then
|
||||
for col = max (numStart - 1) 0 to min curCol (lineLength - 1) do
|
||||
if isGear (Arr2D.get contents col (row - 1)) then
|
||||
gearsNear.Add (row - 1, col)
|
||||
if row < lineLength - 1 then
|
||||
for col = max (numStart - 1) 0 to min curCol (lineLength - 1) do
|
||||
if isGear (Arr2D.get contents col (row + 1)) then
|
||||
gearsNear.Add (row + 1, col)
|
||||
if (numStart > 0 && isGear (Arr2D.get contents (numStart - 1) row)) then
|
||||
gearsNear.Add (row, numStart - 1)
|
||||
if (curCol < lineLength && isGear (Arr2D.get contents curCol row)) then
|
||||
gearsNear.Add (row, curCol)
|
||||
gearsNear
|
||||
|
||||
let gears = Dictionary<int * int, ResizeArray<int>> ()
|
||||
let addGear (gearPos : int * int) (num : int) =
|
||||
match gears.TryGetValue gearPos with
|
||||
| false, _ ->
|
||||
let arr = ResizeArray ()
|
||||
arr.Add num
|
||||
gears.Add (gearPos, arr)
|
||||
| true, arr when arr.Count < 3 ->
|
||||
arr.Add num
|
||||
| _ -> ()
|
||||
|
||||
for row = 0 to contents.Height - 1 do
|
||||
let mutable currNum = 0
|
||||
let mutable numStart = -1
|
||||
for col = 0 to lineLength - 1 do
|
||||
if Arr2D.get contents col row < 10uy then
|
||||
if numStart = -1 then
|
||||
numStart <- col
|
||||
currNum <- currNum * 10 + int (Arr2D.get contents col row)
|
||||
elif numStart > -1 then
|
||||
for gearPos in isNearGear row numStart col do
|
||||
addGear gearPos currNum
|
||||
currNum <- 0
|
||||
numStart <- -1
|
||||
|
||||
if numStart >= 0 then
|
||||
for gearPos in isNearGear row numStart lineLength do
|
||||
addGear gearPos currNum
|
||||
currNum <- 0
|
||||
numStart <- -1
|
||||
|
||||
let mutable answer = 0
|
||||
for KeyValue(_gearPos, gears) in gears do
|
||||
if gears.Count = 2 then
|
||||
answer <- answer + gears.[0] * gears.[1]
|
||||
|
||||
answer
|
||||
|
Reference in New Issue
Block a user