Add day 22
This commit is contained in:
162
Days/Day22.cs
Normal file
162
Days/Day22.cs
Normal file
@@ -0,0 +1,162 @@
|
||||
using System.Collections.Frozen;
|
||||
using System.Numerics;
|
||||
using System.Runtime.Intrinsics.X86;
|
||||
using System.Text;
|
||||
using Spectre.Console;
|
||||
|
||||
namespace AdventOfCode.Days;
|
||||
|
||||
public class Day22 : Day
|
||||
{
|
||||
public override int Number => 22;
|
||||
public override string Name => "Monkey Market";
|
||||
|
||||
private const int Iterations = 2000;
|
||||
private const int PruneValue = 16777216;
|
||||
|
||||
public override void RunPart1(bool display = true)
|
||||
{
|
||||
var secretsSum = 0L;
|
||||
|
||||
foreach (var line in Input.AsSpan().EnumerateLines())
|
||||
{
|
||||
var secret = long.Parse(line);
|
||||
|
||||
for (var i = 0; i < Iterations; i++)
|
||||
{
|
||||
var result = secret * 64;
|
||||
secret = (secret ^ result) % PruneValue;
|
||||
|
||||
result = secret / 32;
|
||||
secret = (secret ^ result) % PruneValue;
|
||||
|
||||
result = secret * 2048;
|
||||
secret = (secret ^ result) % PruneValue;
|
||||
}
|
||||
|
||||
secretsSum += secret;
|
||||
}
|
||||
|
||||
if (display)
|
||||
{
|
||||
AnsiConsole.MarkupLine($"[green]Sum of {Iterations}th secret numbers: [yellow]{secretsSum}[/][/]");
|
||||
}
|
||||
}
|
||||
|
||||
public override void RunPart2(bool display = true)
|
||||
{
|
||||
var maximumBananas = 0L;
|
||||
|
||||
var initialSecrets = Input.ReadAllLines().Select(l => long.Parse(l)).ToArray();
|
||||
var matchSequences = GenerateSequences().ToArray();
|
||||
|
||||
AnsiConsole.Progress().Start(progress =>
|
||||
{
|
||||
var progressTask = progress.AddTask("Finding best sequence", maxValue: matchSequences.Length);
|
||||
|
||||
Parallel.ForEach(matchSequences, matchSequence =>
|
||||
{
|
||||
Span<long> sequence = stackalloc long[4];
|
||||
var currentBananas = 0L;
|
||||
|
||||
for (var initialSecretIndex = 0; initialSecretIndex < initialSecrets.Length; initialSecretIndex++)
|
||||
{
|
||||
var secret = initialSecrets[initialSecretIndex];
|
||||
|
||||
for (var i = 0; i < Iterations; i++)
|
||||
{
|
||||
var previousSecret = secret;
|
||||
|
||||
// Compute new secret
|
||||
var result = secret * 64;
|
||||
secret = (secret ^ result) % PruneValue;
|
||||
|
||||
result = secret / 32;
|
||||
secret = (secret ^ result) % PruneValue;
|
||||
|
||||
result = secret * 2048;
|
||||
secret = (secret ^ result) % PruneValue;
|
||||
|
||||
var lastDigit = secret % 10;
|
||||
var previousSecretLastDigit = previousSecret % 10;
|
||||
|
||||
// Update sequence
|
||||
sequence[0] = sequence[1];
|
||||
sequence[1] = sequence[2];
|
||||
sequence[2] = sequence[3];
|
||||
sequence[3] = lastDigit - previousSecretLastDigit;
|
||||
|
||||
// Check if sequence match
|
||||
if (sequence[0] == matchSequence.Item1
|
||||
&& sequence[1] == matchSequence.Item2
|
||||
&& sequence[2] == matchSequence.Item3
|
||||
&& sequence[3] == matchSequence.Item4
|
||||
&& i >= 3)
|
||||
{
|
||||
currentBananas += lastDigit;
|
||||
|
||||
// Go to next monkey
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Stop early if it's not possible to beat current maximum
|
||||
if (maximumBananas - currentBananas >= ((initialSecrets.Length - initialSecretIndex - 1) * 9))
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ExchangeIfGreaterThan(ref maximumBananas, currentBananas);
|
||||
|
||||
progressTask.Increment(1);
|
||||
});
|
||||
});
|
||||
|
||||
if (display)
|
||||
{
|
||||
AnsiConsole.MarkupLine($"[green]Maximum amount of bananas: [yellow]{maximumBananas}[/][/]");
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
IEnumerable<(long, long, long, long)> GenerateSequences()
|
||||
{
|
||||
for (var a = -9L; a <= 9; a++)
|
||||
{
|
||||
for (var b = -9L; b <= 9; b++)
|
||||
{
|
||||
for (var c = -9L; c <= 9; c++)
|
||||
{
|
||||
for (var d = -9L; d <= 9; d++)
|
||||
{
|
||||
yield return (a, b, c, d);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Source: https://stackoverflow.com/a/13323172
|
||||
private static void ExchangeIfGreaterThan(ref long location, long value)
|
||||
{
|
||||
// Read
|
||||
var current = Interlocked.Read(ref location);
|
||||
|
||||
// Compare
|
||||
while (current < value)
|
||||
{
|
||||
// Set
|
||||
var previous = Interlocked.CompareExchange(ref location, value, current);
|
||||
|
||||
// If another thread has set a greater value, we can break
|
||||
// or if previous value is current value, then no other thread has it changed in between
|
||||
if (previous == current || previous >= value) // note: most common case first
|
||||
break;
|
||||
|
||||
// For all other cases, we need another run (read value, compare, set)
|
||||
current = Interlocked.Read(ref location);
|
||||
}
|
||||
}
|
||||
}
|
||||
2244
Inputs/Day22.txt
Normal file
2244
Inputs/Day22.txt
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user