Advent of Code Day 6: Doing Cephalopods' Math

On Day 6 of Advent of Code, we’re helping some cephalopods with their kids’ math homework…while they open a trash compactor.

First, I define a problem and function to solve it. A problem is an operation and some numbers.

static int Perform(Problem p)
    => p.Operation switch
    {
        Operation.Add => p.Numbers.Sum(),
        Operation.Multiply => p.Numbers.Aggregate((a, b) => a*b),
        _ => throw new NotImplementedException()
    };

abstract record Operation
{
    public record Add : Operation;
    public record Multiply : Operation;
}
record Problem(Operation Operation, IEnumerable<int> Numbers);

Cephalopods’ math is weird with operations and operands organized vertically, not horizontally. Parsing is the trick part: the input is a 2D array where each column is a problem. Numbers above and operator at the bottom.

I loop through the array of arrays column-wise. The last element becomes the operation, and the rest become the numbers,

static IEnumerable<Problem> Parse(string[][] problems)
{
    var parsedProblems = new List<Problem>();

    for (int j = 0; j < problems[0].Length; j++)
    {
        var numbers = Enumerable.Range(0, problems.Length - 1)
                                .Select(i => int.Parse(problems[i][j]))
                                .ToList();
        Operation op = problems[^1][j] == "+"
                            ? new Operation.Add()
                            : new Operation.Multiply();
        parsedProblems.Add(new Problem(op, numbers));
    }
    return parsedProblems;
}

With the parsing in place, Day 6 is almost done. Here’s my final solution,

var problems = new[]
{
    new[]{ "123", "328", "51", "64" },
    new[]{ "45", "64", "387", "23" },
    new[]{ "6", "98", "215", "314" },
    new[]{ "*", "+", "*", "+" }
};

var total = Parse(problems).Sum(Perform);
Console.WriteLine(total);
Console.ReadKey();

static IEnumerable<Problem> Parse(string[][] problems)
{
    var parsedProblems = new List<Problem>();

    for (int j = 0; j < problems[0].Length; j++)
    {
        var numbers = Enumerable.Range(0, problems.Length - 1)
                                .Select(i => int.Parse(problems[i][j]))
                                .ToList();
        Operation op = problems[^1][j] == "+"
                            ? new Operation.Add()
                            : new Operation.Multiply();
        parsedProblems.Add(new Problem(op, numbers));
    }
    return parsedProblems;
}

static int Perform(Problem p)
    => p.Operation switch
    {
        Operation.Add => p.Numbers.Sum(),
        Operation.Multiply => p.Numbers.Aggregate((a, b) => a*b),
        _ => throw new NotImplementedException()
    };

abstract record Operation
{
    public record Add : Operation;
    public record Multiply : Operation;
}
record Problem(Operation Operation, IEnumerable<int> Numbers);

Two one-off bugs got me this time, but I finally cracked it. The parsing part isn’t that functional in style, but “it works on my machine.” Et voilà!

Advent of Code sharpens your coding skills. But coding is more than typing symbols fast. It’s also about teamwork, collaboration, and many skills I share in my book, Street-Smart Coding: 30 Ways to Get Better at Coding. That’s the roadmap I wish I’d known from day one.

Get your copy of Street-Smart Coding here

Advent of Code Day 5: Counting Fresh Ingredients

On Day 5 of Advent of Code, we’re helping the elves to find which ingredients are fresh or spoiled.

To find if an ingredient is fresh, I create a FreshIngredientRange with a method IsFresh(),

record FreshIngredientRange(int IngredientId1, int IngredientId2)
{
    public bool IsFresh(int productId)
        => productId >= IngredientId1 && productId <= IngredientId2;
}

Then, to count all the fresh ingredients, I write a method that receives all product ranges and all candidate products. A single LINQ query will do the counting,

static int CountFreshIngredients(
    IEnumerable<FreshIngredientRange> ranges,
	IEnumerable<int> productIds)
        => productIds.Count(productId => ranges.Any(r => r.IsFresh(productId)));

Here’s my final solution,

var ranges = new FreshIngredientRange[]
{
    new FreshIngredientRange(3, 5),
    new FreshIngredientRange(10, 14),
    new FreshIngredientRange(16, 20),
    new FreshIngredientRange(12, 18)
};

var productIds = new int[] { 1, 5, 8, 11, 17, 32 };

var count = CountFreshIngredients(ranges, productIds);
Console.WriteLine(count);
Console.ReadKey();

static int CountFreshIngredients(IEnumerable<FreshIngredientRange> ranges, IEnumerable<int> productIds)
    => productIds.Count(productId => ranges.Any(r => r.IsFresh(productId)));

record FreshIngredientRange(int IngredientId1, int IngredientId2)
{
    public bool IsFresh(int productId)
        => productId >= IngredientId1 && productId <= IngredientId2;
}

That’s an easy one with LINQ. Just one single line. Et voilà!

Advent of Code sharpens your coding skills. But coding is more than typing symbols fast. It’s also about teamwork, collaboration, and many skills I share in my book, Street-Smart Coding: 30 Ways to Get Better at Coding. That’s the roadmap I wish I’d known from day one.

Get your copy of Street-Smart Coding here

A Quick Lesson After A Long Debugging Session (And Almost Pulling My Hair Off)

I almost pulled my hair off.

I debugged an issue in a Blazor grid for over two half days. I followed my own advice from Street-Smart Coding:

  • Isolated the problem
  • Removed all irrelevant parts
  • Discussed it with a rubber duck

Just to keep seeing the same error message: TypeError: Cannot read properties of null (reading ‘removeChild’).

StackOverflow says it was Blazor trying to remove an orphan element. So I removed everything except for my grid and wrapped it around a div.

Same mistake.

After questioning my career choices and almost removing “Senior” from my title, I asked for help.

My coworker pulled my branch and reproduced the issue. To my surprise, the issue wasn’t only in my grid. It was in all other grids, all over the app. It was an issue in the Blazor component itself we were using for grids. Arrggg!

Sometimes you just need to ask for help earlier. Like one of my mentors told me and the team, “you have nothing to prove. Ask for help.” And that’s something I cover on Chapter #2 of Street-Smart Coding.

Two Inspiring Business Lessons From Repairing a Blender (And Why I Almost Quit Online Hustles)

My blender broke. Nothing unusual, until I took it to the only repair shop nearby.

Like any repair shop, it was greasy and hot, with shelves full of small parts… and crowded. It was so packed with people carrying blenders and fans, that I had to wait for a technician.

While waiting for a receipt I learned two business lessons that make me want to start a blender shop too:

1. Forget about fancy businesses. Go with a boring one

Fixing blenders is boring.

You don’t dream about going to business school to start a blender-repair shop. But it’s recession‑proof and even resistant to AI “disruption.” I knew it was a good business immediately.

Almost every house in my town has a blender. With a good location and an attractive name, like “BlenderCenter,” this place won’t run out of potential clients ever.

While I waited, an old lady offered coffee and cold juice to everyone in line. A small gesture, but great customer service. Not like buying a mattress the other day. No wonder this shop never runs out of clients.

Forget about crypto, NFTs, and dropshipping. Go with a boring business with clients.

2. Stick with simple, reliable tools

When I got to the cashier for my receipt, I was surprised.

I looked into the lady’s computer. I expected a fancy point-of-sale software with bells and whistles. Nope!

The entire place runs with Microsoft Access. That’s a simple database tool. I could notice it: the window, bars, buttons, and the look and feel of the app. But, it registered me as a new user, created a new order, and printed a receipt… With Access. I remember learning to build forms and databases with Access in high school.

New business owners are tempted to go with the shiniest tools to start a business. Being a coder by day, you don’t know how many friends and acquaintances have asked me to quote for custom software before starting their business. Honestly, I’d just tell them: start with Access.

Prefer simple, reliable tools to run your business.

I never imagined a blender-repair shop could be so inspiring and full of lessons. Meanwhile, I’m still trying to make money online. Maybe I should ditch the online hustles and start a blender-repair shop instead. LOL!

Advent of Code Day 4: Counting Rolls of Paper

On Day 4 of Advent of Code, we’re finding which rolls of paper forklifts can access, so we can get further into the North Pole base.

I model the diagram of rolls of paper as a boolean grid. A cell is true if it has a roll.

Finding adjacent positions

To find the adjacent positions, I add -1, 0, 1 to each coordinate, with proper bounds checking.

Here’s my FindAdjacentPositions():

static IEnumerable<bool> FindAdjacentPositions(bool[][] rollsOfPaper, int i, int j)
{
    for (int row = -1; row <= 1; row++)
    {
        for (int col = -1; col <= 1; col++)
        {
            var x = i + row;
            var y = j + col;
            if (x >= 0 && x < rollsOfPaper.Length
                    && y >= 0 && y < rollsOfPaper[x].Length)
            {
                if (x == i && y == j)
                {
                    continue;
                }

                var cell = rollsOfPaper[x][y];
                yield return cell;
            }
        }
    }
}

After that, the next step is filtering and counting the rolls with less than 4 neighbor rolls.

Filtering and counting

Here’s my final solution,

var rollsOfPaper = new bool[][]
{
    [ false, false, true, true, false, true, true, true, true, false,  ],
    [ true, true, true, false, true, false, true, false, true, true,  ],
    [ true, true, true, true, true, false, true, false, true, true,  ],
    [ true, false, true, true, true, true, false, false, true, false,  ],
    [ true, true, false, true, true, true, true, false, true, true,  ],
    [ false, true, true, true, true, true, true, true, false, true,  ],
    [ false, true, false, true, false, true, false, true, true, true,  ],
    [ true, false, true, true, true, false, true, true, true, true,  ],
    [ false, true, true, true, true, true, true, true, true, false,  ],
    [ true, false, true, false, true, true, true, false, true, false,  ],
};

var count = 0;

for (int i = 0; i < rollsOfPaper.Length; i++)
{
    for (int j = 0; j < rollsOfPaper[i].Length; j++)
    {
        if (rollsOfPaper[i][j])
        {
            var adjacents = FindAdjacentPositions(rollsOfPaper, i, j);
            if (adjacents.Count(roll => roll) < 4)
            {
                count++;
            }
        }
    }
}

Console.WriteLine(count);
Console.ReadKey();

static IEnumerable<bool> FindAdjacentPositions(bool[][] rollsOfPaper, int i, int j)
{
    for (int row = -1; row <= 1; row++)
    {
        for (int col = -1; col <= 1; col++)
        {
            var x = i + row;
            var y = j + col;
            if (x >= 0 && x < rollsOfPaper.Length
                    && y >= 0 && y < rollsOfPaper[x].Length)
            {
                if (x == i && y == j)
                {
                    continue;
                }

                var cell = rollsOfPaper[x][y];
                yield return cell;
            }
        }
    }
}

My goal is to use “functionalish” solutions, but two loops and an accumulator were so easy that I stuck with them.

Et voilà!

Advent of Code sharpens your coding skills. But coding is more than typing symbols fast. It’s also about teamwork, collaboration, and many skills I share in my book, Street-Smart Coding: 30 Ways to Get Better at Coding. That’s the roadmap I wish I’d known from day one.

Get your copy of Street-Smart Coding here