While figuring out my convoluted solution to day 3 I really needed to visualize the wire paths to get an idea of the solution. After getting a pretty picture and tweeting it, I got more likes than I expected, and a response by someone about not having time for it. That’s what this post is for: visualizing in Python is not that hard, here’s how to do it.
I’ve used Pillow, which is a fork of PIL, the Python Image Library. After the usual install rituals all you really need to get started is this code:
from PIL import Image, ImageDraw
...
im = Image.new('RGB', (800, 600), (0, 0, 0))
draw = ImageDraw.Draw(im)
In this code (800, 600)
is the canvas size and (0, 0, 0)
is the RGB code of the background (black in this case). For puzzle purposes lines and points cover 90% of your needs:
draw.line((x1, y1, x2, y2), (255, 255, 0), width=5)
draw.ellipse((x1, y1, x2, y2), fill=(255, 0, 255)
Both line
and ellipse
use a tuple of two points to determine what to draw. In the case of ellipse
you basically define the bounding box, so (0, 0, 10, 10)
gives you a circle centered at (5, 5) with a diameter of 10. Then there’s an RGB tuple for the color, and a line width. Larger values are good to publish large images and still see some lines, a width of 1 allows precise puzzle output when you’re looking for inspiration on a solution.
im.show()
That’s all there is to showing your image. On a Mac this will fire up Preview with an image.
There’s one thing that you might like to do in code, which is flipping the coordinate system. This is needed because the coordinate system of the image is to have (0, 0) in the top left with the positive x-axis to the right and the positive y-axis downwards. So why not fix this?
def flip(point):
return point[0], im.height - point[1]
Finally you will likely have minimum and maximum values that aren’t neatly between (0, 0) and some nice positive coordinate like (800, 800). You can fix this by translating every puzzle coordinate to an image coordinate. Given that you’ve figured out your minimum and maximum values in a tuple boundaries
, we can translate all coordinates to the correct position, and let’s make sure we do the rotation right away…
min_x, min_y, max_x, max_y = boundaries
im = Image.new('RGB', (abs(max_x - min_x), abs(max_y - min_y)), (0, 0, 0))
...
def to_image_coords(point):
return flip((point[0] - min_x, point[1] - min_y))
And that’s it. To prevent you having to write all this yourself I’ve created a small .py file that has a convenience class that wraps the above for you. You can find it here. I just cooked it up, so I hope that it doesn’t have too many bugs… 🙂 Have fun visualizing!
Advent of Code 2019 Series
- Advent of Code 2019 Has Started – Join In!
- Advent of Code 2019 – Day 2
- Advent of Code: How Excel Made My Day and Saved My Son’s Day Too
- Advent of Code – Day 4: Visualize
- Advent of Code – Day 5: Saintaerkla2s
- Advent of Code – Day 6: How I Got Hooked on AoC
- Advent of Code – Day 7: Share Your Workflow
- Advent of Code – Day 8: How Simple Things Can Be Very Hard for Some People
- Advent of Code – Day 9: How I Started Enjoying Solving Programming Puzzles
- Advent of Code – Day 10: Space Cowboys Shooting Pixels in the Sky
- Advent of Code – Day 11: To Be or Not to Be
- Advent of Code – Day 12: Shooting for the Moon
- Advent of Code – Day 14: Chain Reaction
- Advent of Code – Day 16: Curses
- Advent of Code – Day 17: Vacuuming a Scaffold with the Intcode Program
- How Little Green Men Helped Me Solve a Puzzle
- Advent of Code – Day 20: A Little Bit of Revision
- Advent of Code – Day 21: It’s a Marathon, Not a Sprint
- Advent of Code – Day 22: Shuffling Cards Until Eternity
- Advent of Code – Day 23: The Network is Reliable
- Advent of Code – Day 24 & 25: Think Out of the Box