def print_area(area): max_x = max(pos.x for pos in area.keys()) + 1 max_y = max(pos.y for pos in area.keys()) draw_area = area.copy() for y in range(max_y + 1): for x in range(max_x + 1): if Pt(x, y) in draw_area: print(draw_area[Pt(x, y)], end="") else: print(" ", end="") print() print()
def parse_scan(lines): scan = defaultdict(lambda: " ") for line in lines: numbers = list(map(int, re.findall(r'-?\d+', line))) if line[0] == "x": x = numbers[0] for y in range(numbers[1], numbers[2]+1): scan[Pt(x, y)] = "#" elif line[0] == "y": y = numbers[0] for x in range(numbers[1], numbers[2]+1): scan[Pt(x, y)] = "#" return scan
def print_scan(scan): min_x = min(pos.x for pos in scan.keys()) - 1 max_x = max(pos.x for pos in scan.keys()) + 1 max_y = max(pos.y for pos in scan.keys()) draw_area = scan.copy() for y in range(max_y + 1): for x in range(min_x, max_x + 1): if Pt(x, y) in draw_area: print(draw_area[Pt(x, y)], end="") else: print(" ", end="") print() print()
def find_paths(base): distances = {} seen = set() to_visit = collections.deque([(Pt(0, 0), 0)]) while to_visit: pos, current_distance = to_visit.popleft() # Add neighbours if base[pos].up and pos.above() not in seen: to_visit.append((pos.above(), current_distance + 1)) if base[pos].down and pos.below() not in seen: to_visit.append((pos.below(), current_distance + 1)) if base[pos].left and pos.left() not in seen: to_visit.append((pos.left(), current_distance + 1)) if base[pos].right and pos.right() not in seen: to_visit.append((pos.right(), current_distance + 1)) if pos not in distances or current_distance < distances[pos]: distances[pos] = current_distance seen.add(pos) max_distance = max(distances.items(), key=lambda d: distances[d[0]]) # type: tuple print("Max distance: {} to {}".format(max_distance[1], max_distance[0])) print("Number of rooms that are at least 1k doors away:", sum(dist >= 1000 for dist in distances.values()))
def parse_area(lines): area = {} for y, line in enumerate(lines): for x, acre in enumerate(line): area[Pt(x, y)] = acre return area
def print_area_map(area: dict): min_x = min(area.keys(), key=lambda point: point.x).x max_x = max(area.keys(), key=lambda point: point.x).x min_y = min(area.keys(), key=lambda point: point.y).y max_y = max(area.keys(), key=lambda point: point.y).y for row in range(min_y, max_y + 1): top = "" middle = "" bottom = "" for col in range(min_x, max_x + 1): p = Pt(col, row) t, m, b = area[p].print() top += t middle += m bottom += b print(top) print(middle) print(bottom)
def simulate_water_flow(scan): min_x = min(pos.x for pos in scan.keys()) - 1 max_x = max(pos.x for pos in scan.keys()) + 1 min_y = min(pos.y for pos in scan.keys()) max_y = max(pos.y for pos in scan.keys()) # DO THIS AFTER FINDING MIN/MAX VALUES! scan[Pt(500, 0)] = "+" sources = deque([Pt(500, 0)]) while sources: pos = sources.popleft() # If water is settled here, move on if scan[pos] == "~": continue # Follow the source downwards pos = pos.below() while pos.y <= max_y: # If we find air, keep dropping if scan[pos] == " ": scan[pos] = "|" pos = pos.below() # If we find clay or settled water, spread sideways elif scan[pos] == "#" or scan[pos] == "~": # Move back up one layer pos = pos.above() # Spread to the right right, r_overflows = flow_sideways(copy.copy(pos), Pt(1, 0), scan, sources) # Spread to the left left, l_overflows = flow_sideways(copy.copy(pos), Pt(-1, 0), scan, sources) for spread_x in range(left.x, right.x + 1): scan[Pt(spread_x, pos.y)] = "|" if (r_overflows or l_overflows) else "~" # If we hit another falling stream, merge with it elif scan[pos] == "|": break counts = Counter(scan[Pt(x, y)] for x in range(min_x-1, max_x+1) for y in range(min_y, max_y+1)) print(counts["~"] + counts["|"]) print(counts["~"])
def create_base_map(regex): area = {} pos = Pt(0, 0) # type: Pt area[pos] = Room() latest_branches = collections.deque() for char in regex: current_room = area[pos] if char == "N": # If we are heading into a new room, create it if pos.above() not in area: next_room = Room() else: # Otherwise, get the next room from the map next_room = area[pos.above()] # Link together rooms current_room.up = next_room next_room.down = current_room # Move pos in the correct direction and store the new room there pos = pos.above() area[pos] = next_room elif char == "S": # If we are heading into a new room, create it if pos.below() not in area: next_room = Room() else: # Otherwise, get the next room from the map next_room = area[pos.below()] # Link together rooms current_room.down = next_room next_room.up = current_room # Move pos in the correct direction and store the new room there pos = pos.below() area[pos] = next_room elif char == "E": # If we are heading into a new room, create it if pos.right() not in area: next_room = Room() else: # Otherwise, get the next room from the map next_room = area[pos.right()] # Link together rooms current_room.right = next_room next_room.left = current_room # Move pos in the correct direction and store the new room there pos = pos.right() area[pos] = next_room elif char == "W": # If we are heading into a new room, create it if pos.left() not in area: next_room = Room() else: # Otherwise, get the next room from the map next_room = area[pos.left()] # Link together rooms current_room.left = next_room next_room.right = current_room # Move pos in the correct direction and store the new room there pos = pos.left() area[pos] = next_room elif char == "(": # Begin branch latest_branches.append(pos) elif char == "|": # Pop last pos from stack, then continue with new branch from there pos = latest_branches.pop() latest_branches.append(pos) elif char == ")": pos = latest_branches.pop() elif char in "^$": continue else: print("other char:", char) assert len(latest_branches) == 0 # print_area_map(area) return area