Advent of Code 2019: Day 8
After spending hours on day 7, I finished day 8 in about 15 minutes. It was simply reading in a series of numbers which represented pixels in various layers in an email. In part one I’ll break the pixels into layers, and evaluate each one. In part two, I’ll actually create the image.
Challenge
The puzzle can be found here. I’m given a string of 0s, 1s, and 2s. The string is 15000 characters long, which I must break into layers that are 25 wide by 6 tall. In part one, I’ll find the layer with the fewest 0s, and then return the number of 1s in that layer times the number of 2s.
In part two, I’ll understand that 2 is transparent, 1 is black, and 0 is white. Looking down from the top layer, I’ll draw the picture.
Solution
Part 1
Python makes this so simple. I’ll read in the input, and then break it into layers. Then I can use the min
command, passing it a lambda function as key
. The lambda just tells it to count the number of 0
.
#!/usr/bin/env python3
import sys
w, h = 25, 6
with open(sys.argv[1], "r") as f:
pixels = f.read().strip()
layers = [pixels[i : i + w * h] for i in range(0, len(pixels), w * h)]
fewest_0 = min(layers, key=lambda x: x.count("0"))
print(f"Part 1: {fewest_0.count('1')*fewest_0.count('2')}")
It runs and immediately returns the answer:
$ time python3 day8.py 08-puzzle_input.txt
Part 1: 1330
real 0m0.028s
user 0m0.020s
sys 0m0.008s
Part 2
I now just need to write something that will loop over the pixels, and then starting at layer 0, find the first layer with a non-2 at that pixel.
#!/usr/bin/env python3
import sys
w, h = 25, 6
with open(sys.argv[1], "r") as f:
pixels = f.read().strip()
layers = [pixels[i : i + w * h] for i in range(0, len(pixels), w * h)]
fewest_0 = min(layers, key=lambda x: x.count("0"))
print(f"Part 1: {fewest_0.count('1')*fewest_0.count('2')}")
print(f"Part 2:")
for y in range(h):
line = ""
for x in range(w):
l = 0
while layers[l][x + (y * w)] == "2":
l += 1
line += layers[l][x + (y * w)]
print(line)
This prints an image, but it’s hard to read:
$ time python3 day8.py 08-puzzle_input.txt
Part 1: 1330
Part 2:
1111001100100101111011110
1000010010100101000010000
1110010010111101110011100
1000011110100101000010000
1000010010100101000010000
1000010010100101111010000
real 0m0.046s
user 0m0.043s
sys 0m0.004s
I’ll replace the 0s with a unicode block character, and the 1s with a space:
print(line.replace("0", chr(9608)).replace("1", " "))
Now I get an image:
$ time python3 day8.py 08-puzzle_input.txt
Part 1: 1330
Part 2:
██ ██ ██ █ █ █
████ ██ █ ██ █ ████ ████
██ ██ █ █ ██ ██
████ █ ██ █ ████ ████
████ ██ █ ██ █ ████ ████
████ ██ █ ██ █ █ ████
real 0m0.032s
user 0m0.028s
sys 0m0.004s
That’s getting better. It’s actually easier to read if I invest the image, switching 0 and 1:
$ time python3 day8.py 08-puzzle_input.txt
Part 1: 1330
Part 2:
████ ██ █ █ ████ ████
█ █ █ █ █ █ █
███ █ █ ████ ███ ███
█ ████ █ █ █ █
█ █ █ █ █ █ █
█ █ █ █ █ ████ █
real 0m0.048s
user 0m0.044s
sys 0m0.004s
Here’s an image from my terminal in case the text doesn’t format right:
Final Code
#!/usr/bin/env python3
import sys
w, h = 25, 6
with open(sys.argv[1], "r") as f:
pixels = f.read().strip()
layers = [pixels[i : i + w * h] for i in range(0, len(pixels), w * h)]
fewest_0 = min(layers, key=lambda x: x.count("0"))
print(f"Part 1: {fewest_0.count('1')*fewest_0.count('2')}")
print(f"Part 2:")
for y in range(h):
line = ""
for x in range(w):
l = 0
while layers[l][x + (y * w)] == "2":
l += 1
line += layers[l][x + (y * w)]
print(line.replace("1", chr(9608)).replace("0", " "))