Advent of Code 2021: Day 13

Search for a command to run...

No comments yet. Be the first to comment.
In this series we solve programming challenges from the Advent of Code 2021 using JavaScript.
This blog post is fourteenth in the Advent of Code 2021 series and shows a JavaScript-based solution to the problem described in Day 14. This challenge was about optimizing an algorithm that generates exponentially larger and larger strings. I found ...
This blog post is fourteenth in the Advent of Code 2021 series and shows a JavaScript-based solution to the problem described in Day 14. This challenge was about optimizing an algorithm that generates exponentially larger and larger strings. I found ...

This blog post is twelfth in the Advent of Code 2021 series and shows a JavaScript-based solution to the problem described on Day 12. All solutions are in this GitHub repository. Solving Part One Given a set of connections between underground caves, ...

This blog post is eleventh in the Advent of Code 2021 series and shows a JavaScript-based solution to the problem described in Day 11. This day had many similarities to Day 9, and I solved the challenge using similar methods. All solutions are in thi...

This blog post is the tenth in the Advent of Code 2021 series and shows a JavaScript-based solution to the problem described in Day 10. All solutions are in this GitHub repository. Solving Part One Given a set of lines with opening and closing bracke...

This blog post is thirteenth in the Advent of Code 2021 series and shows a JavaScript-based solution to the problem described in Day 13.
All solutions are in this GitHub repository.
Given a list of x, y coordinates representing dots on a transparent Origami paper along with folding instructions, we must determine the number of visible dots after the first fold.
I broke down the solution as follows:
In terms of the data structure for the Origami paper, I opted for a hash map that stores dot coordinates. An alternative data structure is a matrix of characters . and #. However, since the problem doesn't specify constraints about the paper size and since the matrix size changes at each step, I deemed this approach more difficult to implement.
The first step of reading the input is separating the dot coordinates from the instructions using the empty line separator \n\n.
const [dotsString, instructionsString] = data.split('\n\n')
Next, we add each dot to the hash map using the x,y string as a key and {x, y} as value.
const dots = {}
dotsString.split('\n').map((dot) => {
const [x, y] = dot.split(',').map((n) => parseInt(n))
dots[dot] = { x, y }
})
For example, given the 1,7 coordinates, we store:
const dots = {
'1,7': {
x: 1,
y: 7
}
}
We can get the first line among instructions using the split function and the 0 index.
const firstInstruction = instructionsString.split('\n')[0]
To interpret the folding instruction we need the axis (x or y) and the line coordinate. Thus, we can remove the fold along string.
const [axis, lineString] = firstInstruction
.replace('fold along ', '')
.split('=')
const line = parseInt(lineString)
According to the problem, axis x is a vertical line, thus we must fold the paper to the left, whereas given axis y is a horizontal line, we must fold the paper up. We define the foldLeft and foldUp functions next.
if (axis === 'x') {
foldLeft(dots, line)
} else {
foldUp(dots, line)
}
We must inspect each dot coordinate. We can use the Object.key function to iterate through the elements of the dot hash map. We need to determine whether a dot is on the right half of the paper relative to the folding line. This condition is met when the x coordinate of the dot is larger than the x coordinate representing the line (x > line).
Each dot on the right half of the paper changes its x coordinate after folding the paper by twice the difference between itself and the line. We can express this as const newX = x - 2 * (line - x)
For example, the folding line x=7 updates the x coordinate of dot 9,1 from 9 to 9 - 2 * (9 - 7) = 5 resulting in dot 5,1. We can simplify the expression to const newX = 2 * line - x.
Once we have determined the new coordinates, we can add the new dot to the hash map and delete the dot with old coordinates.
const foldLeft = (dots, line) => {
Object.keys(dots)
.forEach((key) => {
const { x, y } = dots[key]
if (x > line) {
const newX = 2 * line - x
dots[getKey(newX, y)] = { x: newX, y }
delete dots[key]
}
})
}
To fold up, we can use the same algorithm as for folding to the left, except we update the y coordinate instead of x.
const foldUp = (dots, line) => {
Object.keys(dots)
.forEach((key) => {
const { x, y } = dots[key]
if (y > line) {
const newY = 2 * line - y
dots[getKey(x, newY)] = { x, y: newY }
delete dots[key]
}
})
}
We can rely on the Object.keys function to count the number of visible dots after folding the Origami paper.
Object.keys(dots).length
The final solution for part one is in my GitHub repository.
Part two was about following all folding instructions, printing the final Origami result and revealing eight uppercase characters - the expected output.
To solve part two we can build on top of part one with the following additions:
Unlike in part one, we must iterate through and follow all folding instructions one by one.
instructionsString.split('\n').forEach((instruction) => {
const [axis, lineString] = instruction.replace('fold along ', '').split('=')
const line = parseInt(lineString)
if (axis === 'x') {
foldLeft(dots, line)
} else {
foldUp(dots, line)
}
})
Once we have the final coordinates of dots on the folded Origami paper, we are able to print it.
We need to know the size of the folded Origami paper to be able to print it. Thus, we must find the maximum x and y coordinates.
const [maxX, maxY] = Object.keys(dots).reduce(
([maxX, maxY], key) => [
Math.max(maxX, dots[key].x),
Math.max(maxY, dots[key].y),
],
[0, 0]
)
Next, for each two coordinate between 0 and the size of the paper, we print either a # if a dot exists with those coordinates, or a space character .
for (let y = 0; y <= maxY; y++) {
let line = ''
for (let x = 0; x <= maxX; x++) {
const character = dots[getKey(x, y)] ? '#' : ' '
line += character
}
console.log(line)
}
The final solution for part two is in my GitHub repository.
Day 13 was about folding a transparent Origami paper, updating coordinates of dots on the paper and revealing a final eight-character message.