Advent of Code - Day 3 and 4

Only 5 days into Advent of Code and already this thing is kicking my rear. Both challenges over the weekend were (mostly) simply, but I'm already having trouble keeping up. This is a good thing though. I'm still absolutely loving the hell out of these challenges!

Day 3

Day 3 was a rather simple problem. Given three numbers, can you determine if they could be a triangle? Turns out there's a simple mathematical formula for that - any two side lengths must add to a number larger than the third side. So given an input of numbers, the task was to just count the total number of valid triangles.


const fs = require('fs');
const input = fs.readFileSync('./input.txt','utf8');
const shapes = input.split('\n');

var triangles = 0;

shapes.forEach(function(shape) {
    shape = shape.trim();
    shape = shape.replace(/ {2,}/g, " ");
    let sizes = shape.split(' ');
    let sidea = Number(sizes[0]);
    let sideb = Number(sizes[1]);
    let sidec = Number(sizes[2]);
    if(validTriangle(sidea,sideb,sidec)) triangles++;
//    console.log(sidea+' '+sideb+' '+sidec+' : '+validTriangle(sidea,sideb,sidec));
});

function validTriangle(a,b,c) {
    if((a+b) <= c) return false;
    if((a+c) <= b) return false;
    if((b+c) <= a) return false;
    return true;
}

console.log(triangles);

The second part did something evil. Instead of reading the file line by line, now each column of the file represented input. So you needed to read 'down' each column to generate the list of triangle inputs, and then validate them. I cursed this one, but still had fun.


const fs = require('fs');
const input = fs.readFileSync('./input.txt','utf8');

/*
now we need to make a new list of inputs based on columns
*/
let shapes = [];
//var colA = []; var colB = []; var colC = [];
const lines = input.split('\n');

let colA = [];
let colB = [];
let colC = [];

lines.forEach(function(line) {
    line = line.trim();
    line = line.replace(/ {2,}/g, " ");
    let inputs = line.split(' ');
    colA.push(inputs[0]); colB.push(inputs[1]); colC.push(inputs[2]);
});

// now we have 3 arrays of input we need to add to shapes
function makeShapes(inp) {
    let results = [];
    for(var i=0;i<inp.length;i+=3) {
        results.push({sidea:Number(inp[i]), sideb:Number(inp[i+1]), sidec:Number(inp[i+2])});
    }
    return results;
}

shapes = shapes.concat(makeShapes(colA));
shapes = shapes.concat(makeShapes(colB));
shapes = shapes.concat(makeShapes(colC));
//console.log('shapes = '+shapes.length);

var triangles = 0;

shapes.forEach(function(shape) {
    if(validTriangle(shape.sidea,shape.sideb,shape.sidec)) triangles++;
//    console.log(shape.sidea+' '+shape.sideb+' '+shape.sidec+' : '+validTriangle(shape.sidea,shape.sideb,shape.sidec));
});

function validTriangle(a,b,c) {
    if((a+b) <= c) return false;
    if((a+c) <= b) return false;
    if((b+c) <= a) return false;
    return true;
}

console.log(triangles);

Random question - how much of our job is taking crap input and making it useable?

Day 4

This one was a bit fascinating. Our input is a string that looks like so:

aaaaa-bbb-z-y-x-123[abxyz]

Everything up to the last number represents the name of the room, encrypted. The number represents a 'sector'. Finally, the code inside the brackets is a checksum. You can determine if the string is valid if:

  • You count each instance of letters used in the name.
  • You sort out the top 5 used letters, and in case of a tie, sort alphabetically.
  • The checksum then is the top 5 letters as sorted above.

So I wrote a generic function to validate that input and used it on the samples they provided. I mentioned how they suggest that as a good way to test your code and I cannot recommend that enough. Once done, I modified my simple validRoom function to return the sector if the room was valid. This is because the main goal is to sum all the sectors. I don't like my function returning something non-boolean, but I got over it.


const fs = require('fs');
const input = fs.readFileSync('./input.txt','utf8');
const rooms = input.split('\n');

let answer = 0;
rooms.forEach(function(room) {
    answer += validRoom(room);
});

console.log('answer = ' + answer);
/*
if true, returns sector, otherwise returns 0
*/
function validRoom(str) {
//    console.log('input = '+str);
    var parts = str.split('-');
    //first, get the room, which is all but the last
    var room = parts.slice(0, parts.length - 1).join('-');
    var endPart = parts[parts.length-1];
    var sector = Number(endPart.replace(/\[.+\]/g,''));
    var checksumInitial = endPart.replace(/.+\[(.*?)\].*/,'$1');
    //remove trailing newline, this could be done above I think
    checksumInitial = checksumInitial.replace(/\s/,'');
//    console.log('room='+room);
//    console.log('sector='+sector);
//    console.log(checksumInitial.length);
    /*
    now generate data on length of chars
    */
    var chars = [];

    for(var i=0;i<room.length;i++) {
        var char = room.substr(i,1);
        if(char === '-') continue;
        var curr = chars.findIndex(function(x) { return x.letter === char; });
        if(curr != -1) {
            chars[curr].size++;
        } else {
            chars.push({letter:char, size:1});
        }
    }

    //now generate checksum based on # of letters and alpha sort
    var sorted = chars.sort(function(a,b) {
        if(a.size > b.size) return -1;
        if(a.size < b.size) return 1;
        if(a.size === b.size) {
            if(a.letter > b.letter) return 1;
            if(a.letter < b.letter) return -1;
            return 0;
        }
        return 1;
    });
//    console.log(sorted);
    //checksum is just top 5
    var checksum = '';
//    console.log(sorted);
    for(var i=0;i<Math.min(5, sorted.length);i++) {
        checksum += sorted[i].letter;
    }
//    console.log('checksum='+checksum);
    if(checksum === checksumInitial) return sector;
    return 0;
}

The second part then had you decrypt the room name using a shift cipher based on the sector. I found a great caesarShift function here and that worked fine. What wasn't fine was that the puzzle said, "What is the sector ID of the room where North Pole objects are stored?". That made absolutely no sense to me. What they were trying to say is - look at the decrypted room names for something you think makes sense. I saved my output to a file and then CTRL-F for "storage" and found: "northpole object storage". That felt a bit unnecessarily confusing, but heck, it's just like most client-work, right?

You can find my repo of solutions here: https://github.com/cfjedimaster/adventofcode

Like This?

If you like this article, please consider visiting my Amazon Wishlist or donating via PayPal to show your support. You can also subscribe to the email feed to get notified of new posts.

Want to read more like this?