Source code for day22.lib.vis

"""Visualization classes."""
import random
from typing import Any

import vpython

from day22.lib.classes import BoxData, Matrix, Vector3


[docs] def construct_box(box_data: BoxData, color: vpython.vector) -> vpython.box: """Constructs a vpython box from a box_data. Args: box_data (BoxData): box data to mimic color (vpython.vector): color of box for vis. Returns: vpython.box: a vpython.box """ return vpython.box( pos=box_data.vpos, length=box_data.length, height=box_data.height, width=box_data.width, color=color, )
[docs] def random_color() -> vpython.vector: """Returns a random color compatible with vpython.""" hsv = vpython.vector(random.random(), random.uniform(0.5, 1.0), 1.0) return vpython.color.hsv_to_rgb(hsv)
CAMERA_START = vpython.vector(40.0164, 11.0337, 39.9238) CAMERA_AXIS = -CAMERA_START CAMERA_POS_1 = vpython.vector(111.512, 122.347, 65.0144) CAMERA_AXIS_1 = vpython.vector(-83.3746, -20.0517, -69.4084)
[docs] def init_vis(boxes: list[BoxData]) -> None: """Initialize vis boxes. Only called if we're visualizing.""" for box in boxes: color = random_color() vbox = construct_box(box, color) box.set_vbox(vbox) ground = BoxData("ground", Vector3(0, 0, 0), Vector3(10, 10, 0)) construct_box(ground, random_color()) # init camera: vpython.scene.camera.axis = CAMERA_AXIS vpython.scene.camera.pos = CAMERA_START vpython.scene.height = 600 vpython.scene.width = 400
[docs] def bind_keys(on_key_down: Any) -> None: """Bind keyboard events, so that ``enter`` calls the given callback.""" def callback(evt: Any) -> None: character = evt.key if character == "shift": return print(character) if character in ["\n", "enter", "return"]: on_key_down() vpython.scene.bind("keydown", callback)
[docs] def follow_block(y: float, box: BoxData) -> None: """Force camera to follow a block.""" pos = vpython.scene.camera.pos pos.y = max(y + box.start_pos.z, pos.y) vpython.scene.camera.pos = pos
[docs] def animate_part1(boxes: list[BoxData], matrix: Matrix) -> None: """Animates part1.""" vpython.scene.camera.pos = CAMERA_POS_1 vpython.scene.camera.axis = CAMERA_AXIS_1 for box in boxes: if matrix.can_fly_up(box): box.select() vpython.rate(60) for box in boxes: if matrix.can_fly_up(box): box.unselect() vpython.rate(60)
[docs] def animate_part2(boxes: list[BoxData]) -> None: """Animates part2.""" vpython.scene.camera.pos = CAMERA_POS_1 vpython.scene.camera.axis = CAMERA_AXIS_1 reversed_boxes = sorted(boxes, key=lambda box: box.end_pos.z, reverse=True) for box in reversed_boxes: to_fall = box.recursive_fall({box}) to_fall_sorted = sorted(to_fall, key=lambda x: x.z_val_bot) if len(to_fall_sorted) == 0: continue for faller in to_fall_sorted: faller.select() vpython.rate(20) for faller in to_fall: faller.unselect()