Day 20 solution

Yes, I skipped day 19. For now. It sucks.

Day 20 is another "oh right, % is remainder in C#, not modulo" which means it does dumb things with negative numbers. I originally implemented this by hand, looping through the addition/subtraction and wrapping as necessary, but found "euclidean division" after a few Google searches for, essentially, "surely C# can do modulo somehow, right?" and finding that the answer is "no, not really" (though there is an open proposal to make %% a true modulo operator, but that doesn't help me now). So this math utility was the best thing I could find on Wikipedia that did what I wanted (I don't need both the division and modulo response, though, so I left the division part commented out for now). The other trick here is using the shortened length of the array when performing the modulo due to the rules around how wrapping works in this problem (which I think is terribly explained and confusing, but it's also late and I could just be dumb).

I think a faster solution is to just change indices instead of actually moving numbers around in the list, but I'm happy with this for now.
This commit is contained in:
2022-12-20 00:45:40 -06:00
parent 6de69511e5
commit 52bd9dfc2b
5 changed files with 5098 additions and 102 deletions

View File

@ -81,6 +81,7 @@
<None Remove="inputs\20.txt" />
<EmbeddedResource Include="inputs\20.txt" />
<None Remove="inputs\21.txt" />
<EmbeddedResource Include="inputs\20a.txt" />
<EmbeddedResource Include="inputs\21.txt" />
<None Remove="inputs\22.txt" />
<EmbeddedResource Include="inputs\22.txt" />

File diff suppressed because it is too large Load Diff

7
inputs/20a.txt Normal file
View File

@ -0,0 +1,7 @@
1
2
-3
3
-2
0
4

75
src/20.cs Normal file
View File

@ -0,0 +1,75 @@
namespace aoc2022;
internal class Day20 : Day
{
private List<(int num, int origIdx)> nums = new();
internal override void Parse()
{
foreach (var line in Util.Parsing.ReadAllLines("20"))
{
nums.Add((int.Parse(line), nums.Count));
}
}
private static void mix(List<(int num, int origIdx)> mixedNums, IList<(int num, int origIdx)> origNums)
{
for (int i = 0; i < origNums.Count; i++)
{
if (origNums[i].num == 0)
{
continue;
}
var idx = mixedNums.FindIndex(n => n.origIdx == origNums[i].origIdx);
mixedNums.RemoveAt(idx);
var newIdx = Util.Math.Modulo(idx + origNums[i].num, mixedNums.Count);
mixedNums.Insert((int)newIdx, origNums[i]);
}
}
private static void mix(List<(long num, int origIdx)> mixedNums, IList<(long num, int origIdx)> origNums)
{
for (int i = 0; i < origNums.Count; i++)
{
if (origNums[i].num == 0)
{
continue;
}
var idx = mixedNums.FindIndex(n => n.origIdx == origNums[i].origIdx);
mixedNums.RemoveAt(idx);
var newIdx = Util.Math.Modulo(idx + origNums[i].num, mixedNums.Count);
mixedNums.Insert((int)newIdx, origNums[i]);
}
}
internal override string Part1()
{
var mixedNums = new List<(int num, int origIdx)>(nums);
mix(mixedNums, nums);
var zeroIdx = mixedNums.FindIndex(n => n.num == 0);
var coord1 = mixedNums[(zeroIdx + 1000) % mixedNums.Count].num;
var coord2 = mixedNums[(zeroIdx + 2000) % mixedNums.Count].num;
var coord3 = mixedNums[(zeroIdx + 3000) % mixedNums.Count].num;
return $"Grove coordinate sum: <+white>{coord1 + coord2 + coord3}";
}
internal override string Part2()
{
var keyedNums = new List<(long num, int origIdx)>(nums.Select(c => (c.num * 811589153L, c.origIdx)));
var mixedKeyedNums = new List<(long num, int origIdx)>(keyedNums);
for (int i = 0; i < 10; i++)
{
mix(mixedKeyedNums, keyedNums);
}
var zeroIdx = mixedKeyedNums.FindIndex(n => n.num == 0);
var coord1 = mixedKeyedNums[(zeroIdx + 1000) % mixedKeyedNums.Count].num;
var coord2 = mixedKeyedNums[(zeroIdx + 2000) % mixedKeyedNums.Count].num;
var coord3 = mixedKeyedNums[(zeroIdx + 3000) % mixedKeyedNums.Count].num;
return $"Fully decrypted grove coordinate sum: <+white>{coord1 + coord2 + coord3}";
}
}

View File

@ -43,4 +43,19 @@ public static class Math
{
return (a * b) / GCD(a, b);
}
public static long Modulo(long numer, long denom) {
// long q = numer / denom;
long r = numer % denom;
if (r < 0) {
if (denom > 0) {
// q = q - 1;
r = r + denom;
} else {
// q = q + 1;
r = r - denom;
}
}
return r;
}
}