Day 9: Movie Theater
Megathread guidelines
- Keep top level comments as only solutions, if you want to say something other than a solution put it in a new post. (replies to comments can be whatever)
- You can send code in code blocks by using three backticks, the code, and then three backticks or use something such as https://topaz.github.io/paste/ if you prefer sending it through a URL
FAQ
- What is this?: Here is a post with a large amount of details: https://programming.dev/post/6637268
- Where do I participate?: https://adventofcode.com/
- Is there a leaderboard for the community?: We have a programming.dev leaderboard with the info on how to join in this post: https://programming.dev/post/6631465


Python
Part 2 is only partially optimized (runs in ~7.5s).
The optimization I did do is to compress the grid coords by recording all red tiles and their adjacent cells only (thanks Everybody,Codes #15)
The part which needs further optimization is my approach to getting the largest rectangle in the polygon. I did it by flood-filling the area outside the polygon, then walking through all cells of every pair of red tiles to make sure their rectangle is within the polygon.
click to view code
# combinations helps us get all pairs of red tiles # pairwise helps us get all adjacent pairs of red tiles from itertools import combinations, pairwise from collections import deque def get_area(p1, p2): x1, y1 = p1 x2, y2 = p2 return (abs(x2 - x1) + 1) * (abs(y2 - y1) + 1) @timer() def part1(data: str): red_tiles = [tuple(map(int, line.split(','))) for line in data.splitlines()] max_area = 0 for r1, r2 in combinations(red_tiles, 2): max_area = max(max_area, get_area(r1, r2)) return max_area def compress_coordinates(coords: list[tuple[int, int]]): i_of_interest_set = set() j_of_interest_set = set() for i, j in coords: i_of_interest_set.update([i-1, i, i+1]) j_of_interest_set.update([j-1, j, j+1]) sorted_is = sorted(list(i_of_interest_set)) sorted_js = sorted(list(j_of_interest_set)) m = len(sorted_is) n = len(sorted_js) compress_i_map = {val: id for id, val in enumerate(sorted_is)} compress_j_map = {val: id for id, val in enumerate(sorted_js)} return m, n, compress_i_map, compress_j_map @timer() def part2(data: str): red_tiles = [tuple(map(int, line.split(','))) for line in data.splitlines()] m, n, compress_i_map, compress_j_map = compress_coordinates(red_tiles) def get_compressed_coords(og_coords: tuple[int, int]): return compress_i_map[og_coords[0]], compress_j_map[og_coords[1]] # make the grid grid = [['.']*n for _ in range(m)] for i, j in red_tiles: ci, cj = get_compressed_coords((i, j)) grid[ci][cj] = '#' # make the walls of the polygon enclosed by the red tiles def make_line(r1, r2): r1_i, r1_j = get_compressed_coords(r1) r2_i, r2_j = get_compressed_coords(r2) wall_char = '#' if r1_i == r2_i: # same row row = r1_i for col in range(min(r1_j, r2_j) + 1, max(r1_j, r2_j)): grid[row][col] = wall_char elif r1_j == r2_j: # same col col = r1_j for row in range(min(r1_i, r2_i) + 1, max(r1_i, r2_i)): grid[row][col] = wall_char for r1, r2 in pairwise(red_tiles): make_line(r1, r2) make_line(red_tiles[-1], red_tiles[0]) # whiteout the exterior DIRECTIONS = [(0, 1), (1, 0), (0, -1), (-1, 0)] queue = deque([(0, 0)]) while queue: i, j = queue.popleft() if grid[i][j] == ' ': continue grid[i][j] = ' ' for di, dj in DIRECTIONS: ni, nj = i+di, j+dj if not (0 <= ni < m) or not (0 <= nj < n): continue if grid[ni][nj] != '.': continue queue.append((ni, nj)) # DEBUG: print the grid # print() # for row in grid: # print(''.join(row)) # check if the rectangle formed by the corners r1, r2 is contained within the red-green polygon def check_contained(r1, r2): r1_i, r1_j = get_compressed_coords(r1) r2_i, r2_j = get_compressed_coords(r2) min_i, max_i = min(r1_i, r2_i), max(r1_i, r2_i) min_j, max_j = min(r1_j, r2_j), max(r1_j, r2_j) for i in range(min_i, max_i+1): for j in range(min_j, max_j+1): if grid[i][j] == ' ': return False return True # get the max area of a rectangle that is contained within the red-green polygon # and has red tiles at two of its corners max_area = 0 for r1, r2 in combinations(red_tiles, 2): area = get_area(r1, r2) if area <= max_area: # dont bother continue if not check_contained(r1, r2): continue max_area = area return max_area sample = """7,1 11,1 11,7 9,7 9,5 2,5 2,3 7,3""" assert part1(sample) == 50 assert part2(sample) == 24___