Skip to content
On this page

Advent Of Code 2022

It’s that time of year again! and this time I’m going to have a right good go and completing the advent of code! I’m not promising I'll have it all done…but I’ll have a go.

I’m going to be doing these in TypeScript as I often forget the intricacies of this language and thought this would be a good way of remembering them.

All my code for this will be available here

Day 1

Ok, so going through all the usual elf story nonsense and extracting the good stuff! essentially the task is:

Given a list of numbers:

1000
2000
3000

4000

5000
6000

7000
8000
9000

10000

Each section of this list is separated by a new line, the task is to sum up all sections and output the highest value. So in this example:

  • The first section is 10002000, and 3000 , a total of 6000.
  • The second section is a total of 4000.
  • The third section is 5000 and 6000, a total of 11000.
  • The fourth section is 70008000, and 9000, a total of 24000.
  • The fifth section is 10000.

So the fourth sections total is the highest and that's the number we output. Easy.

Attempt for first star

First of all I tried with a fetch but I got the message “Puzzle inputs differ by user. Please log in to get your puzzle input.” ugh…fine.. so I just had to copy it all to a text file.

My thought process was to split the data where there is a new line followed by a new line. This would give me an array containing each section. Then I would split each section and convert to a Number array using a map, and then use reduce to sum up each individual array. Finally I would add each of these results to a result array and using Math.max get the highest value.

I know the inline functions are hard to read but this is just how it came out in my head. In production code I would refactor this.

tsx
import fs from "fs";
fs.readFile("input_day1.txt", "utf8", (err, data) => {
  if (err) {
    console.error(err);
    return;
  }
  const results: number[] = [];
  data.split("\n\n").forEach((group) => {
    results.push(
      group
        .split("\n")
        .map((str) => {
          return Number(str);
        })
        .reduce((sum, current) => sum + current, 0)
    );
  });
  console.log(Math.max(...results));
});

Attempt for second star

So the second part of this task is very much the same as the first, only difference is we want a total of the 3 highest values.

This is basically the same code but I’ve sorted the results into lowest→highest value and then using pop() (which helpfully returns and removes the highest value from the array) I’ve summed up my three totals.

tsx
fs.readFile("input_day1.txt", "utf8", (err, data) => {
  if (err) {
    console.error(err);
    return;
  }
  const results: number[] = [];
  data.split("\n\n").forEach((group) => {
    results.push(
      group
        .split("\n")
        .map((str) => {
          return Number(str);
        })
        .reduce((sum, current) => sum + current, 0)
    );
  });
  const sorted = results.sort((n1, n2) => n1 - n2);
  console.log(sorted.pop() + sorted.pop() + sorted.pop());
});

Boom! Day 1 done! Let’s see if i can keep this motivation going!

Day 2

Hello! so today the elves are playing Rock Paper Scissors… but apparently I have been given the outcomes by some evil elf or something…I dunno..

I have been given a file which looks like:

A Y
B X
C Z

My opponent will choose Rock paper scissors based on the letters in the first column:

  • A for Rock
  • B for Paper
  • C for Scissors

and I will choose mine based on the letters i the second column:

  • X for Rock
  • Y for Paper
  • Z for Scissors

I need to get the total score from the file I’ve been given.

The total score is the sum of your scores for each round. The score for a single round is the score for the shape you selected (1 for Rock, 2 for Paper, and 3 for Scissors) plus the score for the outcome of the round(0 if you lost, 3 if the round was a draw, and 6 if you won).

So for the above file:

  • A Y = (2 because I chose Paper + 6 because I won) 8
  • B X = (1 because chose Rock + 0 because I lost ) 1
  • C Z = (This is a draw because we both chose scissors, so 3 + 3) 6

Total = (8 + 1 + 6) 15

Simple.

Attempt for first star

My thinking here is work out how many different combinations there could be.

Then generate a score for each one of those combinations using the logic above. I can then put those in a switch and pass each line from the text file into the switch which will then append a score variable.

There are 9 different combinations:

  1. A X - (Score: 4)
  2. A Y - (Score: 8)
  3. A Z - (Score: 3)
  4. B X - (Score: 1)
  5. B Y - (Score: 5)
  6. B Z - (Score: 9)
  7. C X - (Score: 7)
  8. C Y - (Score: 2)
  9. C Z - (Score: 6)

Now its just a case of slapping all that together:

tsx
import fs from "fs";

let score = 0;

function generateScore(line: String) {
  switch (line) {
    case "A X":
      score += 4;
      break;
    case "A Y":
      score += 8;
      break;
    case "A Z":
      score += 3;
      break;
    case "B X":
      score += 1;
      break;
    case "B Y":
      score += 5;
      break;
    case "B Z":
      score += 9;
      break;
    case "C X":
      score += 7;
      break;
    case "C Y":
      score += 2;
      break;
    case "C Z":
      score += 6;
      break;
  }
}
function day2Task() {
  fs.readFile("resources/input_day2.txt", "utf8", (err, data) => {
    if (err) {
      console.error(err);
      return;
    }
    const lines = data.split("\n");
    lines.forEach((line) => {
      generateScore(line);
    });
    console.log(score);
  });
}

day2Task();

Attempt for second star

Ok so I was a bit too quick of the mark, turns out this evil elf forgot to tell me something, turns out the X Y Z tell me how the match will end…not what hand I should play.

X means I need to lose.

Y means I need to end the round in a draw.

Z means I need to win.

So this changes the scorings really.. I need to remember this part:

outcome of the round(0 if you lost, 3 if the round was a draw, and 6 if you won).

  • A Y = (I need to draw, so because they used Rock (A), I also should use Rock(A). 3 + 1) 4
  • B X = (I need to lose, they chose Paper(B), so I should chose Rock(A). 1 + 0 ) 1
  • C Z = (I need to win, they chose Scissors(C), so I’ll chose Rock(A) 1 + 6) 7

Total = (4 + 1 + 7) 12

makes sense I guess..

All I need to do is change some of the score points in my switch statement. I don’t want to break my first attempt so instead I’m going to add in a task parameter to my generateScore function and use ternary operators to switch between the scores. If I pass a 1 in there it will work as it did before. If I pass a 2 in there it will use out new scoring system defined by the logic above:

tsx
function generateScore(task: number, line: String) {
  switch (line) {
    case "A X":
      task === 1 ? (score += 4) : (score += 3);
      break;
    case "A Y":
      task === 1 ? (score += 8) : (score += 4);
      break;
    case "A Z":
      task === 1 ? (score += 3) : (score += 8);
      break;
    case "B X":
      score += 1;
      break;
    case "B Y":
      score += 5;
      break;
    case "B Z":
      score += 9;
      break;
    case "C X":
      task === 1 ? (score += 7) : (score += 2);
      break;
    case "C Y":
      task === 1 ? (score += 2) : (score += 6);
      break;
    case "C Z":
      task === 1 ? (score += 6) : (score += 7);
      break;
  }
}

Boom! another day done! 😄

Day 3

Back again! Today the elves are having some issues packing bags or something...

The basic goal here is, given an input such as:

vJrwpWtwJgWrhcsFMMfFFhFp
jqHRNqRjqzjGDLGLrsFMfFZSrLrFZsSL
PmmdzqPrVvPwwTWBwg
wMqvLMZHhHMvwLHjbvcjnnSBnvTQFn
ttgJtRGJQctTZtZT
CrZsJsPPZsGzwwsLwLmpwMDw

Split each row in half, and then compare to two halves to find which letters they have in common.

  • The first row is vJrwpWtwJgWrhcsFMMfFFhFp, its first half is vJrwpWtwJgWr, and its second half is hcsFMMfFFhFp. The only letter that appears in both strings is lowercase p.
  • The second string when spilt is jqHRNqRjqzjGDLGL and rsFMfFZSrLrFZsSL. The only letter that appears in both strings is uppercase L.
  • The third string split is PmmdzqPrV and vPwwTWBwg; the only common letter is uppercase P.
  • The fourth string, when split, only shares the letter v.
  • The fifth string, when split, only shares the letter t.
  • The sixth string, when split, only shares the letter s.

Each of of these letters has a priority value that I need to add up at the end. The rules are:

  • Lowercase item types a through z have priorities 1 through 26.
  • Uppercase item types A through Z have priorities 27 through 52.

so in the above example, the priority of the letter that appears in both parts of the strings are:

  • p = 16
  • L = 38
  • P = 42
  • v = 22
  • t = 20
  • s = 19

the sum of these is 157

My first thought it how to get the right numerical value for the letter. To do that we can take a look at an ASCII table, specifically the part I'm showing below:

ASCII Table

You can see here that a = 97 so to get its position in the alphabet all I have to do is - 96

and for capital letters, all I need to do is something like:

tsx
if (c >= 65 && c <= 90) {
  return c - 38;
}

sounds simple.. famous last words

Attempt for first star

I realized that my previous answers are not very TypeScripty.. so I’m leaning into TypeScript today.

So I need to half each row, find the shared letters and value them, then move onto the next.

tsx
const fs = require("fs");
const input = fs.readFileSync("resources/input_day3.txt", "utf8");

const row = input.split("\n") as string[];

function getHalves(items: string): [string, string] {
  const length = items.length;
  return [items.substring(0, length / 2), items.substring(length / 2)];
}

function getShared(first: string, second: string): string | null {
  const lettersInFirst = new Set();
  const lettersInSecond = new Set();
  for (let i = 0; i < first.length; i++) {
    if (first[i] === second[i]) {
      return first[i];
    }
    lettersInFirst.add(first[i]);
    lettersInSecond.add(second[i]);

    if (lettersInSecond.has(first[i])) {
      return first[i];
    }
    if (lettersInFirst.has(second[i])) {
      return second[i];
    }
  }
  return null;
}

function getValue(char: string): number {
  const c = char.charCodeAt(0);

  if (c >= 65 && c <= 90) {
    return c - 38;
  } else {
    return c - 96;
  }
}

const result = row.reduce((currentSum, rucksack) => {
  const shared = getShared(...getHalves(rucksack));
  if (!shared) {
    return currentSum;
  }
  return currentSum + getValue(shared);
}, 0);

console.log(result);

I’ve made use of TypeScript much more in this one I think. And I’ve refactored it for readability.

The functions should be self explanatory really, getValue is implementing the logic I described before so that should make sense.

Attempt for second star

Ok so now we have to group every three lines together and total up the priority of those three, then the next three etc etc, and then return a total.

so in our example above, this is one group:

vJrwpWtwJgWrhcsFMMfFFhFp
jqHRNqRjqzjGDLGLrsFMfFZSrLrFZsSL
PmmdzqPrVvPwwTWBwg

and this is another:

wMqvLMZHhHMvwLHjbvcjnnSBnvTQFn
ttgJtRGJQctTZtZT
CrZsJsPPZsGzwwsLwLmpwMDw

r is the only letter that appears on each line in the first group

Z is the only letter that appears on each line in the second group

r = 18

Z = 52

total = 70

I think here we just need to change the getShared function to take a group of three rather than two. Not too difficult really. Lets delete the getHalves function and instead just pass through the three strings, then we will do what we did before and loop over the number of characters to find the shared.

tsx
const fs = require("fs");
const input = fs.readFileSync("resources/input_day3.txt", "utf8");

const row = input.split("\n") as string[];

function getShared(one: string, two: string, three: string): string | null {
  const first = new Set();
  const second = new Set();
  const third = new Set();
  for (let i = 0; i < Math.max(one.length, two.length, three.length); i++) {
    const letterInFirst = one[i];
    const letterInSecond = two[i];
    const letterInThird = three[i];

    if (letterInFirst === letterInSecond && letterInSecond === letterInThird) {
      return letterInFirst;
    }
    if (letterInFirst) first.add(letterInFirst);
    if (letterInSecond) second.add(letterInSecond);
    if (letterInThird) third.add(letterInThird);

    if (second.has(letterInFirst) && third.has(letterInFirst)) {
      return letterInFirst;
    }
    if (first.has(letterInSecond) && third.has(letterInSecond)) {
      return letterInSecond;
    }
    if (first.has(letterInThird) && second.has(letterInThird)) {
      return letterInThird;
    }

  return null;
}

function getValue(char: string): number {
  const charCode = char.charCodeAt(0);
  if (charCode >= 65 && charCode <= 90) {
    return charCode - 38;
  } else {
    return charCode - 96;
  }
}

let result = 0;
for (let i = 0; i < row.length; i += 3) {
  const shared = getShared(row[i], row[i + 1], row[i + 2]);
  if (!shared) {
    continue;
  }
  result += getValue(shared);
}

console.log(result);

Yeah that did it. Apologies for the bad variable names, naming is hard.

Bring on Day 4!

Day 4

Day 4! its a Sunday today so I’m a bit later than usual but here goes.

So, the elves are cleaning.. and they have all be assigned areas to clean but for some reason some elves have ben given the same areas to clean as others.. so we have to identify that.

The data I’m given looks like:

2-4,6-8
2-3,4-5
5-7,7-9
2-8,3-7
6-6,4-6
2-6,4-8

Each row is a pair of elves and a range of numbers which show the assigned areas for that elves to clean.

  • The first row, the first Elf was assigned sections 2-4 (sections 23, and 4), while the second Elf was assigned sections 6-8 (sections 678).
  • The second row shows no overlap at all, so thats fine.
  • The third row shows each elf was assigned three sections: one got sections 56, and 7, while the other also got 7, plus 8 and 9

some of these rows we can see that one elves duties fully contains another's, for example

2-8,3-7

The second guy is cleaning an area the first guy has already cleaned. We need to identify those cases, so basically count how many of these there are.

Attempt for first star

So I’m using a Type for this solution! Maybe an Interface would be the more appropriate, I’m not sure it matters all that much though… The idea I have is to create a Pair Type containing from and to to collected all my pairs. Then ill just compare the pairs against each other with and …seems quite simple..

tsx
import fs from "fs";
const input = fs.readFileSync("resources/input_day4.txt", "utf8");

const lines = input.split("\n") as string[];

type Pair = {
  from: number;
  to: number;
};

function createPairs(line: string): [Pair, Pair] {
  const splitted = line.split(",");
  const first = splitted[0].split("-");
  const second = splitted[1].split("-");
  const firstPair: Pair = { from: Number(first[0]), to: Number(first[1]) };
  const secondPair: Pair = { from: Number(second[0]), to: Number(second[1]) };
  return [firstPair, secondPair];
}

let sum1 = 0;
lines.forEach((line) => {
  const [first, second] = createPairs(line);
  if (first.from >= second.from && first.to <= second.to) {
    sum1++;
  } else if (second.from >= first.from && second.to <= first.to) {
    sum1++;
  }
});
console.log(sum1);

So this was quite easy really, although in my head it always seems like a lot more code…maybe its because I think in Java. 😄

Attempt for second star

For the second part I need to find pairs that overlap in any way, and count those, so thats simple enough. I think I’ll generate the missing numbers between for each Pair and then just do an includes? yeah that sounds about right, I’ll give that a go.

tsx
import fs from "fs";
const input = fs.readFileSync("resources/input_day4.txt", "utf8");

const lines = input.split("\n") as string[];

type Pair = {
  from: number;
  to: number;
};

function createPairs(line: string): [Pair, Pair] {
  const splitted = line.split(",");
  const first = splitted[0].split("-");
  const second = splitted[1].split("-");
  const firstPair: Pair = { from: Number(first[0]), to: Number(first[1]) };
  const secondPair: Pair = { from: Number(second[0]), to: Number(second[1]) };
  return [firstPair, secondPair];
}

function generateMissingNumbers(start: number, end: number): number[] {
  let numbers: number[] = [];
  for (start; start <= end; start++) {
    numbers.push(start);
  }
  return numbers;
}

let sum2 = 0;
lines.forEach((line) => {
  const [first, second] = createPairs(line);
  const firstNumbers = generateMissingNumbers(first.from, first.to);
  const secondNumbers = generateMissingNumbers(second.from, second.to);
  firstNumbers.every((num) => {
    if (secondNumbers.includes(num)) {
      sum2++;
      return false;
    }
    return true;
  });
});
console.log(sum2);

Yeah, so again quite simple. Good challenge for a Sunday though!

Day 5

Oooo it’s getting difficult now!

So this one is about moving crates. We have a crane that is capable of moving crates between stacks. All the crates are going to be moved about and I need to find out which crates are on the top of the piles.

Im given a starting drawing of how the crates currently look and some instructions of what to move where:

    [D]
[N] [C]
[Z] [M] [P]
 1   2   3

move 1 from 2 to 1
move 3 from 1 to 3
move 2 from 2 to 1
move 1 from 1 to 2

So the instructions here are saying I need to move 1 create from stack 2 to stack 1, I only have access to the top crates so thats moving create [D] to the top of stack 1.

Then I need to move the 3 creates now on stack 1 ([Z],[N],[D]) to stack three..also can only move one at a time so the end result would be:

        [Z]
        [N]
    [C] [D]
    [M] [P]
 1   2   3

Then I need to move 2 creates from stack 2 to stack 1. So we end up with

        [Z]
        [N]
[M]     [D]
[C]     [P]
 1   2   3

Then move 1 stack from stack 1 to stack 2:

        [Z]
        [N]
        [D]
[C] [M] [P]
 1   2   3

and the result were after is [C],[M],[Z]

Attempt for first star

This is a head scratcher… theres a lot to do. We need to parse the input into two sections, the crates and the instructions.. Then we need to put the stacks into arrays…I’m a visual learner and it helps me more if I turn the input on its side, so above would become:

1 [C]
2 [M]
3 [P][D][N][Z]

so if i build up the stacks into arrays like above I can then extract the numbers from the instructions and preform the logic

I think we need to use some regex to parse the instructions move X from X to X

then move 2 from 3 to 1 would result in extracting the top two from stack 3 [N][Z] reversing them and putting them onto stack 1..

1 [C][N][Z]
2 [M]
3 [P][D]

Ok lets give this a go

tsx
import fs from "fs";
const input = fs.readFileSync("resources/input_day5.txt", "utf8");

function day5Task() {
  const lines = input.split("\n");
  const { crates, instructions } = parseInput(lines);
  const stacks = buildStacks(crates);
  doTheThing(instructions, stacks);
  console.log(stacks.map((stack) => stack[0]).join(""));
}

function parseInput(lines: string[]) {
  const crates = [];
  const instructions = [];

  for (let i = 0; i < lines.length; i++) {
    if (lines[i] === "") {
      continue;
    }
    if (lines[i].includes("[") || lines[i][0] === " ") {
      crates.push(lines[i]);
    } else if (lines[i].startsWith("move")) {
      instructions.push(lines[i]);
    }
  }
  return { crates, instructions };
}

function buildStacks(lines: string[]): string[][] {
  const stacks = [];
  const stackNumbers = lines[lines.length - 1];
  const stackIndex = [];
  for (let i = 0; i < stackNumbers.length; i++) {
    if (stackNumbers[i] !== " ") {
      stackIndex.push(i);
      stacks.push([]);
    }
  }

  for (let l = 0; l < lines.length - 1; l++) {
    const line = lines[l];
    for (let i = 0; i < stackIndex.length; i++) {
      if (line[stackIndex[i]] !== " ") {
        stacks[i].push(line[stackIndex[i]]);
      }
    }
  }
  return stacks;
}

function doTheThing(instructions: string[], stacks: string[][]): string[][] {
  const reg = /move (\d+) from (\d+) to (\d+)/;
  for (const instruction of instructions) {
    const matches = reg.exec(instruction);
    const move = parseInt(matches[1]);
    const from = parseInt(matches[2]) - 1;
    const to = parseInt(matches[3]) - 1;

    for (let a = 0; a < move; a++) {
      const crate = stacks[from].shift();
      stacks[to].unshift(crate);
    }
  }

  return stacks;
}

day5Task();

Ok that took more power then I’m happy to admit to.. few little gotchas in there but I did it! it's done! well…the first part is

Attempt for second star

Ok so it turns the crane is not a model 9000 but a 9001 which means it can pick up multiple crates at once…would have been nice to know this before 😄.

This basically means we don’t need to do the unshift we did earlier in our well named doTheThing function (I’m sorry, I’m so bad at naming..) and I think that might be it…

Yeah so this is the only change:

tsx
for (let a = 0; a < times; a++) {
  const crate = stacks[from].shift();
  if (task === 1) {
    stacks[to].unshift(crate);
  } else {
    stacks[to].splice(a, 0, crate);
  }
}

if we’re running task 1 use unshift and if not then a splice is all thats needed. Boom!

Day 5 done! (worried because they’re getting difficult now though..)

Day 6

Hello again, Day 6 is here and the elves are having some communication issues. I’ve been given a broken communication device that needs sorting..

I’ve been given a big datastream buffer that I need to parse. I need to find the start of a packet by identifying the first sequence of 4 unique characters in the datastream.

Attempt for first star

Sounds easy enough, I’m going to loop through each char in the data, then I’m going to to get the next 3 chars, add them all to a set and then check the length of the set. If the Set length is 3 then go again and start from the next char in the data.

Im not to happy with creating a new Set each time, but there is no add all option…I could use a filter on the array to check for unique values but I think this will be fine really…might refactor later

tsx
import { day6 } from "../../data";

const data = day6.split("");

for (let i = 0; i < data.length; i++) {
  let results = new Set(data.slice(i, i + 4));
  if (results.size === 4) {
    console.log(i + 4);
    break;
  }
}

This was really simple, especially compared to yesterdays task…

Attempt for second star

now that we’ve identified the start of the package in the data, we now also need to find the start of the message marker. A start-of-message marker is just like a start-of-packet marker, except it consists of 14 distinct characters rather than 4.

so basically the same code as above but with 14 rather than 4 😄

tsx
import { day6 } from "../../data";

const data = day6.split("");

for (let i = 0; i < data.length; i++) {
  let results = new Set(data.slice(i, i + 14));
  if (results.size === 14) {
    console.log(i + 14);
    break;
  }
}

wow, this was easy… its nice to have an easy one after yesterdays though.

See you tomorrow!

Day 7

I knew this one would be a hard one 😞

The communications device we were given yesterday requires a systems update…but we cant update the system because Error: No space left on device you can see where this one is going…

I need to look through the device and find the total file size of each directory, then I need to find all the directories with a total size of at most 100000 and then calculate the sum of their total sizes.. 🤦🏻‍♂️

This is difficult (for me) to think about because I’m just thinking of crazy nested directories.. all gets a bit like inception in my head…

The example they give is an input which looks like this:

$ cd /
$ ls
dir a
14848514 b.txt
8504156 c.dat
dir d
$ cd a
$ ls
dir e
29116 f
2557 g
62596 h.lst
$ cd e
$ ls
584 i
$ cd ..
$ cd ..
$ cd d
$ ls
4060174 j
8033020 d.log
5626152 d.ext
7214296 k

These are the commands I’m running on my communication device (denoted with a $, everything else is the result of the command). Using these commands we can see what the file system looks like:

- / (dir)
  - a (dir)
    - e (dir)
      - i (file, size=584)
    - f (file, size=29116)
    - g (file, size=2557)
    - h.lst (file, size=62596)
  - b.txt (file, size=14848514)
  - c.dat (file, size=8504156)
  - d (dir)
    - j (file, size=4060174)
    - d.log (file, size=8033020)
    - d.ext (file, size=5626152)
    - k (file, size=7214296)

The answer for this input would be 95437 as directories a = 94853 and e = 584 everything else is over 100000 in size

I guess I should take it one step at a time.

Attempt for first star

I’m going to read the input, and choose an action depending of whether it starts with a $, cd, ls or dir .

if it’s $ then look for cd or ls and change the directory or get the files.

if it’s dir then set a new current directory.

I’m going to use Types again here for the file size and the directory.

and I think I’m probably going to use the reduce function for the directory size..

The rest (i think) is just fiddly logic so thens get on with it!

tsx
import { day7 } from "../../data";

type File = {
  size: number;
};

type Directory = {
  parent: Directory | null;
  subDirs: Map<string, Directory>;
  files: Map<string, File>;
};

const sizes: number[] = [];

function changeDir(currDir: Directory, name: string): Directory {
  if (name === "/") {
    let dir = currDir;
    while (dir.parent !== null) dir = dir.parent;
    return dir;
  } else if (name === "..") {
    return currDir.parent!;
  } else {
    return currDir.subDirs.get(name)!;
  }
}

function read() {
  const root = { parent: null, subDirs: new Map(), files: new Map() };
  let currDir: Directory = root;
  const input = day7.split("\n");
  input.forEach((line) => {
    const parts = line.split(" ");
    if (parts[0] === "$") {
      if (parts[1] === "cd") {
        currDir = changeDir(currDir, parts[2]);
      }
    } else {
      if (parts[0] === "dir") {
        const [_, name] = parts;
        currDir.subDirs.set(name, {
          parent: currDir,
          subDirs: new Map(),
          files: new Map(),
        });
      } else {
        const [size, name] = parts;
        currDir.files.set(name, { size: Number(size) });
      }
    }
  });
  return root;
}

function getSize(dir: Directory): number {
  const dirsSize = Array.from(dir.subDirs.values()).reduce(
    (size, dir) => size + getSize(dir),
    0
  );
  const filesSize = Array.from(dir.files.values()).reduce(
    (size, file) => size + file.size,
    0
  );
  const totalSize = dirsSize + filesSize;
  sizes.push(totalSize);
  return totalSize;
}

// const root = read();
getSize(read());
const sumSmallDirs = sizes
  .filter((s) => s <= 100000)
  .reduce((sum, size) => sum + size, 0);
console.log(sumSmallDirs);

Ok I’m tired because its quite early in the morn ing while writing this, but that was quite irritating to write…maybe i should’t do these so early..

Attempt for second star

Part one was finding the files to delete, and this is the part where I actually do the deleting.

The total disk space available to me on the filesystem is 70000000

I need at least 30000000 **of unused space

In the first example the total space used was 48381165 which means the current unused space is 21618835 which isn’t quite enough for this system update we want to do… so i need to free up at least 8381165 worth of space.

So I have the following options:

  • Delete directory e, which would increase unused space by 584.
  • Delete directory a, which would increase unused space by 94853.
  • Delete directory d, which would increase unused space by 24933642.
  • Delete directory /, which would increase unused space by 48381165.

Directories e and a are both too small; deleting them would not free up enough space. However, directories d and / are both big enough! Between these, choose the smallestd, increasing unused space by 24933642.

So I need to find the smallest directory that, if deleted, would free up enough space on the filesystem to run the update.

I can just use a reduce here again I think as I already have a sizes array, first calculate how much space I need then use that to find the smallest directory that gives me enough room for the update:

tsx
const root = read();
const rootDirSize = getSize(root);
const neededSpace = 30000000 + rootDirSize - 70000000;
const smallest = sizes.reduce(
  (smallest, size) => (size > neededSpace && size < smallest ? size : smallest),
  rootDirSize
);
console.log(smallest);

Difficult! maybe I’m just grumpy because it’s very early… anyway see you tomorrow!