Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# To get started with Dependabot version updates, you'll need to specify which
# package ecosystems to update and where the package manifests are located.
# Please see the documentation for all configuration options:
# https://docs.github.com/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file

version: 2
updates:
- package-ecosystem: "dotnet-sdk" # See documentation for possible values
directory: "/" # Location of package manifests
schedule:
interval: "weekly"
2 changes: 1 addition & 1 deletion .github/workflows/dotnet.yml
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ jobs:
uses: actions/cache/save@v4
if: always()
with:
key: session-${{ hashFiles('.adventofcode.session') }}-${{ hashFiles('**/inputs/**') }}
key: session-${{ hashFiles('.adventofcode.session') }}-test
path:
'**/inputs/**'

Expand Down
69 changes: 69 additions & 0 deletions 2025/fsharp/Day06.fs
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
namespace AdventOfCode.FSharp.Y2025

// Day 6: Trash Compactor
module Day06 =
open AdventOfCode.FSharp.Util

let parseOps (opLine: byte[]) =
let mutable ops = []

for i = 0 to opLine.Length - 1 do
if opLine[i] <> ' 'B then
ops <- opLine[i] :: ops

ops |> List.rev |> Array.ofList

let parseInputPart1 (lines: byte array array) =
let operands =
lines |> Array.take (lines.Length - 1) |> Array.map parseInts |> Array.transpose

let ops = lines |> Array.last |> parseOps

Array.zip operands ops

let inline arraySplit<'T when 'T: equality> (splitValue: 'T) (a: 'T[]) =
let mutable chunk = []
let mutable result = []

for x in a do
if x = splitValue then
if chunk <> [] then
result <- (chunk |> Array.ofList) :: result

chunk <- []
else
chunk <- x :: chunk

if chunk <> [] then
result <- (chunk |> Array.ofList) :: result

result |> Array.ofList


let parseInputPart2 (lines: byte array array) =
let operands =
lines
|> Array.take (lines.Length - 1)
|> Array.transpose
|> Array.map (fun input -> parseIntToAny input 0 |> snd)
|> arraySplit 0

let ops = lines |> Array.last |> parseOps |> Array.rev

Array.zip operands ops

let doMathHomework homework =
homework
|> Array.map (fun (values, op) ->
match op with
| '+'B -> values |> Array.sum |> int64
| '*'B -> values |> Array.map int64 |> Array.reduce (fun a b -> a * b)
| _ -> failwith "invalid operation")
|> Array.sum

let run (input: byte array) (output: int -> string -> unit) =
let lines = input |> bsplit '\n'B

lines |> parseInputPart1 |> doMathHomework |> string |> output 1

lines |> parseInputPart2 |> doMathHomework |> string |> output 2
36 changes: 36 additions & 0 deletions 2025/fsharp/Day07.fs
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
namespace AdventOfCode.FSharp.Y2025

// Day 7: Laboratories
module Day07 =
open AdventOfCode.FSharp.Util
open Checked

let analyzeManifold (lines: byte[][]) =
let mutable beams = Array.zeroCreate lines[0].Length
let mutable next = beams |> Array.copy
let mutable zero = beams |> Array.copy

let mutable splitCount = 0

for line in lines do
for index = 0 to line.Length - 1 do
match line[index] with
| 'S'B -> next[index] <- 1L
| '^'B when beams[index] > 0 ->
splitCount <- splitCount + 1
next[index - 1] <- next[index - 1] + beams[index]
next[index + 1] <- next[index + 1] + beams[index]
next[index] <- 0L
| _ -> next[index] <- next[index] + beams[index]

Array.blit next 0 beams 0 beams.Length
Array.blit zero 0 next 0 next.Length

splitCount, beams |> Array.sum

let run (input: byte array) (output: int -> string -> unit) =
let manifold = input |> bsplit '\n'B

let part1, part2 = manifold |> analyzeManifold
part1 |> string |> output 1
part2 |> string |> output 2
11 changes: 8 additions & 3 deletions Common/AdventOfCode.Cli.SourceGenerator/CalendarGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -209,7 +209,12 @@ private static (string dayDefinition, string runMethod) GenerateDayDefinition(So
throw new NotSupportedException();
}

var dayDefinition = $"new Solution(Year: {year}, Day: {day}, Name: \"{name}\", Run: {runMethodName}),";
var dayDefinition = $$"""
new Solution
{
Year = {{year}}, Day = {{day}}, Name = "{{name}}", Run = {{runMethodName}},
},
""";

return (dayDefinition, runMethod);
}
Expand Down Expand Up @@ -241,10 +246,10 @@ internal static class Calendar
{
public static readonly Solution[] Days =
[
{{dayDefinitions}}
{{dayDefinitions}}
];

{{runMethods}}
{{runMethods}}
}
""";
}
Expand Down
41 changes: 39 additions & 2 deletions Common/AdventOfCode.Cli/App.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
using System.CommandLine;
using System.Reflection;
using System.Security.Cryptography.X509Certificates;
using System.Text.Json;
using System.Text.Json.Serialization;

using BenchmarkDotNet.Running;

Expand Down Expand Up @@ -35,13 +37,15 @@ internal static async Task<int> RunCommand(IEnumerable<Solution> solutions, Inpu

var output = await NorthPole.RunAsync(solution, options);

var (result, actual) = output.PartOutputs[0];
var result = output.PartOutputs[0].Result;
var actual = output.PartOutputs[0].ResultText;

AnsiConsole.MarkupLineInterpolated($" {output.ElapsedMs,8:0.000} {1,4} {result,7} {actual}");

for (var part = 1; part < output.PartOutputs.Length; ++part)
{
(result, actual) = output.PartOutputs[part];
result = output.PartOutputs[part].Result;
actual = output.PartOutputs[part].ResultText;

AnsiConsole.MarkupLineInterpolated($"{string.Empty,29} {part + 1,4} {result,7} {actual}");
}
Expand Down Expand Up @@ -104,12 +108,24 @@ bool IsAllOk(SolutionOutputs output)
return output.PartOutputs.All(p => p.Result == ResultType.Ok);
}

var runTimestamp = DateTime.UtcNow;


foreach (var day in selected.GroupBy(s => (s.Year, s.Day)).OrderBy(g => g.Key))
{
var fastestMs = double.PositiveInfinity;
var slowestMs = double.NegativeInfinity;
var success = false;

var latestResult = new LatestSolutionFile();
var (InformationVersion, BuildConfiguration) = NorthPole.GetBuildInformation();
var fullResult = new SolutionFile
{
InformationVersion = InformationVersion,
BuildConfiguration = BuildConfiguration,
Timestamp = runTimestamp
};

foreach (var solution in day)
{
var output = await NorthPole.RunAsync(solution, options);
Expand All @@ -134,13 +150,34 @@ bool IsAllOk(SolutionOutputs output)
fastestMs = Math.Min(fastestMs, output.ElapsedMs);
slowestMs = Math.Max(slowestMs, output.ElapsedMs);
}

fullResult.Solutions.Add(output);
latestResult.Solutions.Add(new LatestSolutionOutputs
{
Year = output.Year,
Day = output.Day,
Name = output.Name,
PartOutputs = output.PartOutputs
.Select((value, index) => (value, index))
.ToDictionary(k => k.index + 1, v => v.value)
});
}

if (success)
{
fastestTotalMs += fastestMs;
slowestTotalMs += slowestMs;
}

var latestResultJson = JsonSerializer.Serialize(
latestResult, SourceGenerationContext.Default.LatestSolutionFile);
var latestJsonPath = NorthPole.GetCachePath(FileType.LatestResultJson, day.Key.Year, day.Key.Day);
File.WriteAllText(latestJsonPath, latestResultJson);

var timestampResultJson = JsonSerializer.Serialize(
fullResult, SourceGenerationContext.Default.SolutionFile);
var timestampJsonPath = NorthPole.GetCachePath(FileType.TimestampResultJson, day.Key.Year, day.Key.Day, null, runTimestamp);
File.WriteAllText(timestampJsonPath, timestampResultJson);
}

var byFastestTime = outputs
Expand Down
19 changes: 8 additions & 11 deletions Common/AdventOfCode.Cli/FileType.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,16 @@ namespace AdventOfCode.Cli;
public enum FileType
{
HtmlPage = 0,
Input = 1,
Output = 2,
Official = 4,
Example = 8,
Other = 16,

OfficialInput = Official | Input,
ExampleInput = Example | Input,
OtherInput = Other | Input,
OfficialInput = 1,
ExampleInput = 3,
OtherInput = 5,

OfficialOutput = Official | Output,
ExampleOutput = Example | Output,
OtherOutput = Other | Output
OfficialOutput = 2,
ExampleOutput = 4,
OtherOutput = 6,
LatestResultJson = 100,
TimestampResultJson = 101,
}

public enum InputType
Expand Down
50 changes: 47 additions & 3 deletions Common/AdventOfCode.Cli/Model.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
using System.ComponentModel.DataAnnotations;
using System.Text.Json.Serialization;

namespace AdventOfCode.Cli;

public class InvalidSessionFileException : Exception
Expand All @@ -9,11 +12,52 @@ public InvalidSessionFileException(string message) : base(message) { }

public delegate void SolveThunk(byte[] input, Action<int, string> output);

public record Solution(int Year, int Day, string Name, SolveThunk Run)
public record Solution
{
public required int Year { get; init; }
public required int Day { get; init; }
public required string Name { get; init; }
public required SolveThunk Run { get; init; }
public override string ToString() => $"{Year}:{Day}";
}

public record PartOutput(ResultType Result, string? ResultText);
public record PartOutput
{
public required ResultType Result { get; init; }
public required string? ResultText { get; init; }
}

public record SolutionOutputs
{
public required int Year { get; init; }
public required int Day { get; init; }
public required string Name { get; init; }
public required PartOutput[] PartOutputs { get; init; }
public required double ElapsedMs { get; init; }
}

public record LatestSolutionOutputs
{
public required int Year { get; init; }
public required int Day { get; init; }
public required string Name { get; init; }
public required Dictionary<int, PartOutput> PartOutputs { get; init; }
}

public record LatestSolutionFile
{
public List<LatestSolutionOutputs> Solutions { get; init; } = [];
}

public record SolutionFile
{
public string? InformationVersion { get; init; }
public string? BuildConfiguration { get; init; }
public DateTime Timestamp { get; init; } = DateTime.UtcNow;
public List<SolutionOutputs> Solutions { get; init; } = [];
}

public record SolutionOutputs(int Year, int Day, string Name, PartOutput[] PartOutputs, double ElapsedMs);
[JsonSourceGenerationOptions(WriteIndented = true, Converters = [typeof(JsonStringEnumConverter<ResultType>)])]
[JsonSerializable(typeof(SolutionFile))]
[JsonSerializable(typeof(LatestSolutionFile))]
internal partial class SourceGenerationContext : JsonSerializerContext { }
Loading
Loading