Example #1
0
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()
Example #2
0
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
Example #3
0
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()
Example #4
0
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()))
Example #5
0
def parse_area(lines):
    area = {}

    for y, line in enumerate(lines):
        for x, acre in enumerate(line):
            area[Pt(x, y)] = acre

    return area
Example #6
0
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)
Example #7
0
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["~"])
Example #8
0
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