2024.08 visualisation

This commit is contained in:
akp 2024-12-08 13:43:39 +00:00
parent 1656243727
commit 8f7d4b9278
No known key found for this signature in database
GPG key ID: CF8D58F3DEB20755
5 changed files with 116 additions and 2 deletions

View file

@ -3,4 +3,6 @@
Part 1 is:
* less than 298
This is not a fully generic solution as, in a situation where the differences between x and y dimensions of pairs of coordinates are not coprime, this implementation would skip steps.
This is not a fully generic solution as, in a situation where the differences between x and y dimensions of pairs of coordinates are not coprime, this implementation would skip steps.
Visualisation exists as `out.mp4`

View file

@ -0,0 +1,6 @@
#!/usr/bin/env bash
set -ex
cat input.txt | PYTHONPATH=../../../ python3 vis.py
ffmpeg -y -framerate 30 -pattern_type glob -i 'frames/*.png' -c:v libx264 -pix_fmt yuv420p out.mp4

Binary file not shown.

View file

@ -0,0 +1,106 @@
import sys
from gridutil import grid, coord
from collections import defaultdict
import itertools
from fractions import Fraction
import os
from pathlib import Path
from PIL import Image
from tqdm import tqdm
from colorsys import hsv_to_rgb
def parse(instr: str) -> tuple[dict[str, list[coord.Coordinate]], tuple[int, int]]:
g = grid.parse(instr)
antenna_by_type = defaultdict(list)
for key in g:
if g[key] == ".":
continue
antenna_by_type[g[key]].append(key)
return antenna_by_type, (grid.get_max_x(g), grid.get_max_y(g))
lowest_colour = (255, 245, 237)
highest_colour = (255, 159, 45)
highlight_colour = (255, 47, 47)
shadow_colour = (226, 218, 211)
colour_diffs = tuple(map(lambda x: x[1] - x[0], zip(highest_colour, lowest_colour)))
def get_colour_for(n):
return tuple(
map(int, map(lambda x: x[0] - x[1], zip(lowest_colour, map(lambda x: x * n, colour_diffs))))
)
scale_factor = 8
def get_highlight_for(n):
return tuple(map(lambda x: int(x * 255), hsv_to_rgb(n, 0.82, 1)))
def generate_frame(i, base_img, highlight_locs, hc, sequence) -> int:
for n in range(len(sequence)):
s = sequence[:n+1]
img = base_img.copy()
sl = len(s) + 1
for j, p in enumerate(s):
img.putpixel(p, get_colour_for((j + 1) / sl))
for h in highlight_locs:
img.putpixel(h, hc)
maxx, maxy = img.size
img = img.resize((maxx * scale_factor, maxy * scale_factor), resample=Image.NEAREST)
img.save(f"frames/{str(i).zfill(5)}.png")
i += 1
return i
def update_base(base_img, add):
for v in add:
base_img.putpixel(v, shadow_colour)
if __name__ == "__main__":
inp = sys.stdin.read().strip()
(antenna_by_type, (max_x, max_y)) = parse(inp)
ns = list(sorted(antenna_by_type.keys()))
nns = len(ns)
try:
os.makedirs("frames")
except FileExistsError:
pass
base_img = Image.new("RGB", (max_x+1, max_y+1), color=lowest_colour)
i = 0
for antenna_type in tqdm(antenna_by_type):
for (a, b) in itertools.permutations(antenna_by_type[antenna_type], 2):
if (
a.x > b.x
): # filter out (most) duplicate pairs eg ((1, 2), (2, 1)) will only be calculated as ((2, 1), (1, 2)) will be filtered. This also prevents diff.x from being negative (useful for the mod operation)
continue
this_iter = []
diff = coord.sub(b, a)
m = Fraction(
diff.y, diff.x
) # equiv of diff.y / diff.x but without the 26.9999999999996 issue
c = a.y - (m * a.x)
x_cursor = a.x % diff.x
y_cursor = int((x_cursor * m) + c)
while x_cursor <= max_x:
if 0 <= y_cursor <= max_y:
this_iter.append((x_cursor, y_cursor))
x_cursor += diff.x
y_cursor += diff.y
i = generate_frame(i, base_img, (a, b), get_highlight_for(ns.index(antenna_type) / nns), this_iter)
update_base(base_img, this_iter)

View file

@ -21,4 +21,4 @@ A day denoted with an asterisk means it has a visualisation.
| 05 - Print Queue | ★ ★ | Python | Before you dismiss and idea as being "too simple", make sure you check that it doesn't work. |
| 06 - Guard Gallivant | ★ ★ | Python | oh dear runtime (also I knew what I wanted to do for so long it just took me 3 hours to implement it properly) |
| 07 - Bridge Repair | ★ ★ | Python | Maths? Backwards?? |
| 08 - Resonant Collinearity | ★ ★ | Python | `Fraction` saving us all from the curse of a computer's inability to do floating point arithmetic |
| 08* - Resonant Collinearity | ★ ★ | Python | `Fraction` saving us all from the curse of a computer's inability to do floating point arithmetic |