# --- Day 13: A Maze of Twisty Little Cubicles --- # You arrive at the first floor of this new building to discover a much # less welcoming environment than the shiny atrium of the last one. # Instead, you are in a maze of twisty little cubicles, all alike. # Every location in this area is addressed by a pair of non-negative # integers (x,y). Each such coordinate is either a wall or an open space. # You can't move diagonally. The cube maze starts at 0,0 and seems to # extend infinitely toward positive x and y; negative values are invalid, # as they represent a location outside the building. You are in a small # waiting area at 1,1. # While it seems chaotic, a nearby morale-boosting poster explains, the # layout is actually quite logical. You can determine whether a given x,y # coordinate will be a wall or an open space using a simple system: # Find x*x + 3*x + 2*x*y + y + y*y. # Add the office designer's favorite number (your puzzle input). # Find the binary representation of that sum; count the number of bits # that are 1. # If the number of bits that are 1 is even, it's an open space. # If the number of bits that are 1 is odd, it's a wall. # For example, if the office designer's favorite number were 10, drawing # walls as # and open spaces as ., the corner of the building containing # 0,0 would look like this: # 0123456789 # 0 .#.####.## # 1 ..#..#...# # 2 #....##... # 3 ###.#.###. # 4 .##..#..#. # 5 ..##....#. # 6 #...##.### # Now, suppose you wanted to reach 7,4. The shortest route you could take # is marked as O: # 0123456789 # 0 .#.####.## # 1 .O#..#...# # 2 #OOO.##... # 3 ###O#.###. # 4 .##OO#OO#. # 5 ..##OOO.#. # 6 #...##.### # Thus, reaching 7,4 would take a minimum of 11 steps (starting from your # current location, 1,1). # What is the fewest number of steps required for you to reach 31,39? # Your puzzle input is 1350. inp = 1350 destination = (31, 39) size = 100 def is_wall(x: int, y: int) -> bool: res = inp + (x * x + 3 * x + 2 * x * y + y + y * y) return format(res, "b").count("1") % 2 def part_1() -> None: visited = {(1, 1)} steps = 0 while visited: places_to_check = visited.copy() visited = set() for dx, dy in places_to_check: # neighboring points to the current point (left, right, up, and down) for x, y in [ (dx + 1, dy), (dx - 1, dy), (dx, dy + 1), (dx, dy - 1), ]: if x < 0 or y < 0 or (x, y) in visited or is_wall(x, y): continue visited.add((x, y)) steps += 1 if destination in visited: print(steps) break # --- Part Two --- # How many locations (distinct x,y coordinates, including # your starting location) can you reach in at most 50 steps? def part_2() -> None: visited = traversed = {(1, 1)} steps = 0 while visited: places_to_check = visited.copy() visited = set() for dx, dy in places_to_check: # neighboring points to the current point (left, right, up, and down) for x, y in [ (dx + 1, dy), (dx - 1, dy), (dx, dy + 1), (dx, dy - 1), ]: if x < 0 or y < 0 or (x, y) in visited or is_wall(x, y): continue visited.add((x, y)) traversed.add((x, y)) steps += 1 if steps == 50: print(len(traversed)) break if __name__ == "__main__": part_1() part_2()