Actually, just having to rewind things at all.
Software developer in Halifax, Nova Scotia, Canada. Dad to 2 kids.
Find me on the Fediverse in other places:
Actually, just having to rewind things at all.
Using pencils to manually rewind cassette tapes.
The command that I can never get right the first time is ln
. I always end up creating a dead link inside my target folder, even when I read the man page directly prior.
I’ll usually do steps 1 and 2 for a reasonably complex review. I’ll reference the diff from the website (for work, this is Azure DevOps, for personal, GitHub or similar) while I inspect and run the modified code locally.
Breadth-first search, then take the max of the values of searches starting from all the edge tiles.
https://code.dinn.ca/stevedinn/AdventOfCode/src/branch/main/2023/day16/Program.cs
Obviously, you can’t calculate 1 billion iterations, so the states must repeat after a while. My solution got to 154 different states and then started looping from state 92 to state 154 (63 steps). From there we can find the index in the state cache that the final state would be, and calculate the supported load from that.
https://code.dinn.ca/stevedinn/AdventOfCode/src/branch/main/2023/day14/Program.cs
Me too. I ran all the samples, and I was still banging my head. I can usually see the mistake if it’s an off-by-one error in a calculation, but this was a mistake in reading the problem description, so I couldn’t see it at first.
Man this one frustrated me because of a subtle difference in the wording of part 1 vs part 2. I had the correct logic from the start, but with an off-by-one error because of my interpretation of the wording. Part 1 says, “any rows or columns that contain no galaxies should all actually be twice as big” while part 2 says, “each empty column should be replaced with 1000000
empty columns”.
I added 1 column/row in part 1
, and 1_000_000
in part 2. But if you’re replacing an empty column with 1_000_000
, you’re actually adding 999_999
columns. It took me a good hour to discover where that off-by-one error was coming from.
Thanks for that state machine. I was a bit lost in part 2, but after reading this, it totally makes sense.
Snippet:
static void Part1(string data)
{
var result = ParseInput(data)
.Select(history => ProcessHistory(history, g => g.Length - 1, (a, b) => a + b))
.Sum();
Console.WriteLine(result);
}
static void Part2(string data)
{
var result = ParseInput(data)
.Select(history => ProcessHistory(history, g => 0, (a, b) => a - b))
.Sum();
Console.WriteLine(result);
}
static int ProcessHistory(
int[] history,
Func guessIndex,
Func collateGuess)
{
bool allZeros = true;
var diffs = new int[history.Length - 1];
for (int i = 0; i < diffs.Length; i++)
{
var diff = history[i + 1] - history[i];
diffs[i] = diff;
allZeros = allZeros && (diff == 0);
}
var guess = history[guessIndex(history)];
if (!allZeros)
{
guess = collateGuess(
guess,
ProcessHistory(diffs, guessIndex, collateGuess));
}
return guess;
}
Used recursion to determine the differences for part 1 and then extracted the variations in processing from predicting the end vs. the beginning of the history and passed them in as Func variables to the recursive method.
I barely registered a difference between part 1 and part 2.
Part 1: 00:00:00.0018302
Part 2: 00:00:00.0073136
I suppose it took about 3.5 times as long, but I didn’t notice :P
Edit: I realize that I made the implicit assumption in my solution that it doesn’t make sense to have multiple jokers be interpreted as different values. i.e., The hand with the maximum value will have all Jokers interpreted as the same other card. I think that is true though. It worked out for me anyway.
Wow, this is exactly what I did, but in C#. That’s cool.
public class Hand
{
public string Cards;
public int Rank;
public int Bid;
}
public static HandType IdentifyHandType(string hand)
{
var cardCounts = hand
.Aggregate(
new Dictionary(),
(counts, card) =>
{
counts[card] = counts.TryGetValue(card, out var count) ? (count + 1) : 1;
return counts;
})
.OrderByDescending(kvp => kvp.Value);
using (var cardCount = cardCounts.GetEnumerator())
{
cardCount.MoveNext();
switch (cardCount.Current.Value)
{
case 5: return HandType.FiveOfAKind;
case 4: return HandType.FourOfAKind;
case 3: { cardCount.MoveNext(); return (cardCount.Current.Value == 2) ? HandType.FullHouse : HandType.ThreeOfAKind; }
case 2: { cardCount.MoveNext(); return (cardCount.Current.Value == 2) ? HandType.TwoPairs : HandType.OnePair; }
}
}
return HandType.HighCard;
}
public static Hand SetHandRank(Hand hand, Dictionary cardValues)
{
int rank = 0;
int offset = 0;
var cardValueHand = hand.Cards;
for (int i = cardValueHand.Length - 1; i >= 0; i--)
{
var card = cardValueHand[i];
var cardValue = cardValues[card];
var offsetCardValue = cardValue << offset;
rank |= offsetCardValue;
offset += 4; // To store values up to 13 we need 4 bits.
}
// Put the hand type at the high end because it is the most
// important factor in the rank.
var handType = (int)IdentifyHandType(hand.Cards);
var offsetHandType = handType << offset;
rank |= offsetHandType;
hand.Rank = rank;
return hand;
}
My first version ran for about 90 minutes. My second version, for about 45 seconds. I’m sure there’s more optimization to be done, but that was good enough for me :)
That’s almost identical to my story. After that, I found Navidrome, which started my adventure in self-hosting. I’ve never looked back
Plot twist: they’re allergic to nuts and this was attempted murder.
Oh, look. An U.T.B.A.P.H.
https://99percentinvisible.org/episode/u-t-b-a-p-h/