Add visualisation for day 4

This commit is contained in:
akp 2024-12-04 20:44:32 +00:00
parent 846f8e73c2
commit b661de71ed
No known key found for this signature in database
GPG key ID: CF8D58F3DEB20755
7 changed files with 139 additions and 4 deletions

View file

@ -2,4 +2,10 @@
Part two is:
* less than 1976
* also, somewhat obviously, less than 1978
* also, somewhat obviously, less than 1978
Heatmap of the most overlapped locations
| Part 1 | Part 2 |
|--------|--------|
| ![heatmap 1](heatmap-1.png) | ![heatmap 2](heatmap-2.png) |

View file

@ -0,0 +1,5 @@
#!/usr/bin/env bash
set -ex
cat input.txt | PYTHONPATH=../../../ python3 vis.py

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

View file

@ -0,0 +1,122 @@
import sys
import gridutil.grid as grid
import gridutil.coord as coord
from collections import defaultdict
import os
from pathlib import Path
from PIL import Image
from tqdm import tqdm
def parse(instr: str) -> grid.Grid:
return grid.parse(instr.upper())
def one(instr: str):
wordsearch = parse(instr)
seq_starts = list(
map(lambda x: x[0], filter(lambda x: x[1] == "X", wordsearch.items()))
)
detected_sequences = set()
for start_pos in seq_starts:
for xdir in [-1, 0, 1]:
for ydir in [-1, 0, 1]:
if xdir == 0 and ydir == 0:
continue
delta = coord.Coordinate(xdir, ydir)
ok = True
b = []
for i, v in enumerate("XMAS"):
if not ok:
break
x = coord.add(start_pos, coord.mult(delta, i))
g = wordsearch.get(x, "-")
ok = g == v
b.append(x)
if ok:
detected_sequences.add(tuple(b))
return detected_sequences
def check_cross_adjacents(s: str) -> bool:
return s == "SM" or s == "MS"
def two(instr: str):
wordsearch = parse(instr)
seq_starts = list(
map(lambda x: x[0], filter(lambda x: x[1] == "A", wordsearch.items()))
)
detected_sequences = set()
for start_pos in seq_starts:
a = wordsearch.get(coord.add(start_pos, (-1, -1)), "") + wordsearch.get(
coord.add(start_pos, (1, 1)), ""
)
b = wordsearch.get(coord.add(start_pos, (-1, 1)), "") + wordsearch.get(
coord.add(start_pos, (1, -1)), ""
)
if check_cross_adjacents(a) and check_cross_adjacents(b):
detected_sequences.add(start_pos)
return detected_sequences
lowest_colour = (255, 245, 237)
highest_colour = (255, 159, 45)
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 = 4
def generate_frame(path: str, wordsearch: grid.Grid, counts: dict[coord.Coordinate, int]):
max_val = max(counts.values())
maxx, maxy = grid.get_max_x(wordsearch), grid.get_max_y(wordsearch)
img = Image.new("RGB", (maxx+1, maxy+1))
for x in range(maxx+1):
for y in range(maxy+1):
img.putpixel((x, y), get_colour_for(counts[(x, y)]/max_val))
img = img.resize((maxx * scale_factor, maxy * scale_factor), resample=Image.NEAREST)
img.save(path)
def main():
inp = sys.stdin.read().strip()
wordsearch = parse(inp)
j = defaultdict(lambda: 0)
for state in one(inp):
for s in state:
j[s] = j[s] + 1
generate_frame("heatmap-1.png", wordsearch, j)
j = defaultdict(lambda: 0)
for state in two(inp):
for dir in [(0, 0), (-1, -1), (-1, 1), (1, 1), (1, -1)]:
s = coord.add(state, dir)
j[s] = j[s] + 1
generate_frame("heatmap-2.png", wordsearch, j)
if __name__ == "__main__":
main()

View file

@ -10,11 +10,11 @@ Total stars: **8 ★**
<!-- ★ ☆ ✗ -->
A day denoted with a star means it has a visualisation.
A day denoted with an asterisk means it has a visualisation.
| Day | Status | Solutions | Notes |
|-------------------------------------|--------|----------------------|-------|
| 01 - Historian Hysteria | ★ ★ | Python | The reading comprehension was the hardest part of this. |
| 02 - Red-Nosed Reindeer | ★ ★ | Python ||
| 03 - Mull It Over | ★ ★ | Python | The first instance of Advent of Parsing this year! |
| 04 - Ceres Search | ★ ★ | Python | When it says a cross, it does not mean a plus. |
| 04* - Ceres Search | ★ ★ | Python | When it says a cross, it does not mean a plus. |

View file

@ -80,4 +80,6 @@ class Direction(Enum):
return self.value == x.value
def __hash__(self):
return hash(self.value)
return hash(self.value)
directions = [Direction.Up, Direction.Down, Direction.Left, Direction.Right]