DEV Community

Cover image for Advent of code - Day 16
Quentin Ménoret
Quentin Ménoret

Posted on

Advent of code - Day 16

Are you participating in the Advent of code this year?

If you don't know what the advent of code is, it's a website where you'll find a daily challenge (every day it gets harder). It's a really fun event, you should participate!

I try to solve the exercises using either JavaScript or TypeScript and will share my solutions daily (with one day delay so no one can cheat!). I only share the solution for the second part.

This one was really interesting! Loved the part where you needed to figure out which rule apply to which number. Thankfully, there was no possible conflict where you would need to generate all possible permutations to find out which one was the right one. A simple "filter out the one already assigned and keep the ones with only one possibility" works (recursive, obviously).

The rest was pretty straight forward!

Here is my solution for day #16:

const [rawRules, rawMine, rawNearby] = input.split('\n\n')

const rules = rawRules.split('\n').map((rule) => {
  const [name, definition] = rule.split(': ')
  return {
    name,
    range: definition.split(' or ').map((range) => range.split('-').map((x) => parseInt(x, 10))),
  }
})

const nearby = rawNearby
  .split('\n')
  .slice(1)
  .map((ticket) => ticket.split(',').map((x) => parseInt(x, 10)))
  .filter((numbers) => {
    return !numbers.some((number) => {
      return rules.every((rule) => {
        return (
          number < rule.range[0][0] ||
          (number > rule.range[0][1] && number < rule.range[1][0]) ||
          number > rule.range[1][1]
        )
      })
    })
  })

const possibilities = []
for (let i = 0; i < nearby[0].length; i++) {
  const currentRules = rules.filter((rule) => {
    return nearby.every(
      (numbers) =>
        (numbers[i] >= rule.range[0][0] && numbers[i] <= rule.range[0][1]) ||
        (numbers[i] >= rule.range[1][0] && numbers[i] <= rule.range[1][1]),
    )
  })
  possibilities.push(currentRules.map((rule) => rule.name))
}

function orderRules(possibilities) {
  const loners = possibilities.filter((possibility) => possibility.length === 1).map((rules) => rules[0])
  if (loners.length === possibilities.length) return possibilities.map((x) => x[0])
  const newPossibilities = possibilities.map((possibility) =>
    possibility.length === 1 ? possibility : possibility.filter((rule) => !loners.includes(rule)),
  )
  return orderRules(newPossibilities)
}

const rulesInOrder = orderRules(possibilities)

const myTicket = rawMine
  .split('\n')[1]
  .split(',')
  .map((x) => parseInt(x, 10))

const numbers = myTicket.filter((value, index) => {
  return rulesInOrder[index].startsWith('departure')
})

console.log(numbers.reduce((acc, x) => acc * x, 1))
Enter fullscreen mode Exit fullscreen mode

Feel free to share your solution in the comments!


Photo by Markus Spiske on Unsplash

Top comments (0)