• 37 Posts
  • 1.07K Comments
Joined 2 years ago
cake
Cake day: June 12th, 2023

help-circle










  • I’m only casting a ray to detect where turning right now would lead. So to stick with your example:

    .O..
    -^+#
    #++.
    ..#.
    

    If the guard had come from the left and run this little loop I’d detect this location to place an obstacle.
    Alternatively, if I switch back to recursive rays, I’d detect this location a little later:

    .O..
    .^.#
    #|..
    .|#.
    








  • Python

    Essentially I’m extracting strings from the word search and compare them to the desired value. For part one that means extracting from an X in eight directions. Because I’m reading from the central X outwards, I don’t need to reverse any of them.
    Part two reads two strings in an X-shape around the coordinates of each X. The resulting strings are filtered down to include only “MAS” and “SAM”. If there are exactly two strings we found an X-MAS.

    from pathlib import Path
    
    
    def parse_input(input: str) -> list[str]:
        return input.strip().splitlines()
    
    
    def extract_strings_one(m: int, n: int, haystack: list[str], l: int = 4) -> list[str]:
        result = []
        # Right
        if m + l <= len(haystack[n]):
            result.append(haystack[n][m : m + l])
        # Up-Right
        if m + l <= len(haystack[n]) and n > l - 2:
            result.append("".join([haystack[n - i][m + i] for i in range(l)]))
        # Up
        if n > l - 2:
            result.append("".join([haystack[n - i][m] for i in range(l)]))
        # Up-Left
        if m > l - 2 and n > l - 2:
            result.append("".join([haystack[n - i][m - i] for i in range(l)]))
        # Left
        if m > l - 2:
            result.append("".join([haystack[n][m - i] for i in range(l)]))
        # Down-Left
        if m > l - 2 and n + l <= len(haystack):
            result.append("".join([haystack[n + i][m - i] for i in range(l)]))
        # Down
        if n + l <= len(haystack):
            result.append("".join([haystack[n + i][m] for i in range(l)]))
        # Down-Right
        if m + l <= len(haystack[n]) and n + l <= len(haystack):
            result.append("".join([haystack[n + i][m + i] for i in range(l)]))
        return result
    
    
    def extract_strings_two(m: int, n: int, haystack: list[str], d: int = 1) -> list[str]:
        result = []
        if 0 <= m - d and m + d < len(haystack[n]) and 0 <= n - d and n + d < len(haystack):
            result.append("".join([haystack[n + i][m + i] for i in range(-d, d + 1)]))
            result.append("".join([haystack[n - i][m + i] for i in range(-d, d + 1)]))
        return result
    
    
    def part_one(input: str) -> int:
        lines = parse_input(input)
        xmas_count = 0
        for i, line in enumerate(lines):
            x = line.find("X", 0)
            while x != -1:
                xmas_count += len(
                    list(filter(lambda s: s == "XMAS", extract_strings_one(x, i, lines)))
                )
                x = line.find("X", x + 1)
        return xmas_count
    
    
    def part_two(input: str) -> int:
        lines = parse_input(input)
        x_mas_count = 0
        for i, line in enumerate(lines[1:-1], 1):
            a = line.find("A", 0)
            while a != -1:
                if (
                    len(
                        list(
                            filter(
                                lambda s: s in ("MAS", "SAM"),
                                extract_strings_two(a, i, lines),
                            )
                        )
                    )
                    == 2
                ):
                    x_mas_count += 1
                a = line.find("A", a + 1)
        return x_mas_count
    
    
    if __name__ == "__main__":
        input = Path("input").read_text("utf-8")
        print(part_one(input))
        print(part_two(input))
    


  • Python

    Also took advantage of cmp_to_key.

    from functools import cmp_to_key
    from pathlib import Path
    
    
    def parse_input(input: str) -> tuple[dict[int, list[int]], list[list[int]]]:
        rules, updates = tuple(input.strip().split("\n\n")[:2])
        order = {}
        for entry in rules.splitlines():
            values = entry.split("|")
            order.setdefault(int(values[0]), []).append(int(values[1]))
        updates = [[int(v) for v in u.split(",")] for u in updates.splitlines()]
        return (order, updates)
    
    
    def is_ordered(update: list[int], order: dict[int, list[int]]) -> bool:
        return update == sorted(
            update, key=cmp_to_key(lambda a, b: 1 if a in order.setdefault(b, []) else -1)
        )
    
    
    def part_one(input: str) -> int:
        order, updates = parse_input(input)
        return sum([u[len(u) // 2] for u in (u for u in updates if is_ordered(u, order))])
    
    
    def part_two(input: str) -> int:
        order, updates = parse_input(input)
        return sum(
            [
                sorted(u, key=cmp_to_key(lambda a, b: 1 if a in order[b] else -1))[
                    len(u) // 2
                ]
                for u in (u for u in updates if not is_ordered(u, order))
            ]
        )
    
    
    if __name__ == "__main__":
        input = Path("input").read_text("utf-8")
        print(part_one(input))
        print(part_two(input))