Skip to content
Snippets Groups Projects
Select Git revision
  • 0f7ff97ce5ef0b4a7eb4db82e4bfddb4fc6b2df5
  • main default protected
2 results

main.py

Blame
    • Duncan Holmes's avatar
      296dbf8c
      added main file · 296dbf8c
      Duncan Holmes authored
      it's very minor.
      only has 2/3rds of 1st "ger reflexive" function
      
      may god help me and all of the students of UNL avoid the evil that lurks here
      296dbf8c
      History
      added main file
      Duncan Holmes authored
      it's very minor.
      only has 2/3rds of 1st "ger reflexive" function
      
      may god help me and all of the students of UNL avoid the evil that lurks here
    Day10.py 6.91 KiB
    import functools
    from typing import List, Tuple
    
    from ImportData import import_data
    
    day: int = 10
    
    # sample_data: List[str] = '''
    # .....
    # .S-7.
    # .|.|.
    # .L-J.
    # .....
    # '''.split('\n')[1:-1]
    # sample_data: List[str] = '''
    # 7-F7-
    # .FJ|7
    # SJLL7
    # |F--J
    # LJ.LJ
    # '''.split('\n')[1:-1]
    # sample_data: List[str] = '''
    # ...........
    # .S-------7.
    # .|F-----7|.
    # .||.....||.
    # .||.....||.
    # .|L-7.F-J|.
    # .|..|.|..|.
    # .L--J.L--J.
    # ...........
    # '''.split('\n')[1:-1]
    # sample_data: List[str] = '''
    # ..........
    # .S------7.
    # .|F----7|.
    # .||....||.
    # .||....||.
    # .|L-7F-J|.
    # .|..||..|.
    # .L--JL--J.
    # ..........
    # '''.split('\n')[1:-1]
    # sample_data: List[str] = '''
    # .F----7F7F7F7F-7....
    # .|F--7||||||||FJ....
    # .||.FJ||||||||L7....
    # FJL7L7LJLJ||LJ.L-7..
    # L--J.L7...LJS7F-7L7.
    # ....F-J..F7FJ|L7L7L7
    # ....L7.F7||L7|.L7L7|
    # .....|FJLJ|FJ|F7|.LJ
    # ....FJL-7.||.||||...
    # ....L---J.LJ.LJLJ...
    # '''.split('\n')[1:-1]
    sample_data: List[str] = '''
    FF7FSF7F7F7F7F7F---7
    L|LJ||||||||||||F--J
    FL-7LJLJ||||||LJL-77
    F--JF--7||LJLJ7F7FJ-
    L---JF-JLJ.||-FJLJJ7
    |F|F-JF---7F7-L7L|7|
    |FFJF7L7F-JF7|JL---7
    7-L-JL7||F7|L7F-7F7|
    L.L7LFJ|||||FJL7||LJ
    L7JLJL-JLJLJL--JLJ.L
    '''.split('\n')[1:-1]
    
    data_structure: type = Tuple[int, int, str, List[str]]
    
    
    def parse_data(data: List[str]) -> data_structure:
        initial_row: int = -1
        initial_column: int = -1
        initial_pipe: str
        number_of_rows = len(data)
        number_of_columns = len(data[0])
        for row in range(number_of_rows):
            for column in range(number_of_columns):
                if data[row][column] == 'S':
                    initial_row = row
                    initial_column = column
        initial_pipe = input('What is the shape of the initial pipe? ')
        return initial_row, initial_column, initial_pipe, data
    
    
    def part1(data: data_structure) -> int:
        row, column, pipe, pipes = data
        previous_locations: List[Tuple[int, int]] = [(row, column), (row, column)]
        current_locations: List[Tuple[int, int]]
        match pipe:
            case '|':
                current_locations = [(row + 1, column), (row - 1, column)]
            case '-':
                current_locations = [(row, column + 1), (row, column - 1)]
            case 'L':
                current_locations = [(row, column + 1), (row - 1, column)]
            case 'J':
                current_locations = [(row, column - 1), (row - 1, column)]
            case '7':
                current_locations = [(row, column - 1), (row + 1, column)]
            case 'F':
                current_locations = [(row, column + 1), (row + 1, column)]
            case _:
                raise ValueError(f'{pipe} at ({row},{column})')
        distance: int = 1
        while current_locations[0] != current_locations[1]:
            distance += 1
            for i in range(len(current_locations)):
                previous_row, previous_column = previous_locations[i]
                row, column = current_locations[i]
                pipe = pipes[row][column]
                previous_locations[i] = current_locations[i]
                row_change = row - previous_row
                column_change = column - previous_column
                match pipe:
                    case '|' | '-':
                        current_locations[i] = (row + row_change, column + column_change)
                    case 'L' | '7':
                        current_locations[i] = (row + column_change, column + row_change)
                    case 'J' | 'F':
                        current_locations[i] = (row - column_change, column - row_change)
                    case _:
                        raise ValueError(f'{pipe} at ({row}, {column})')
        return distance
    
    
    def part2(data: data_structure) -> int:
        row, column, pipe, pipes = data
        # an extra copy of the pipes data, "zoomed in" to allow for gaps between pipes
        tiles: [List[List[str]]] = [['I'] * (2 * len(pipes[0])) for _ in range(2 * len(pipes))]
        # first, draw the main loop on the tiles copy
        previous_location: Tuple[int, int] = (row, column)
        current_location: Tuple[int, int]
        match pipe:
            case '|' | 'F':
                current_location = (row + 1, column)
                tiles[2 * row + 1][2 * column] = 'X'
            case '-' | 'L':
                current_location = (row, column + 1)
                tiles[2 * row][2 * column + 1] = 'X'
            case 'J' | '7':
                current_location = (row, column - 1)
                tiles[2 * row][2 * column - 1] = 'X'
            case _:
                raise ValueError(f'{pipe} at ({row},{column})')
        previous_row, previous_column = previous_location
        row, column = current_location
        while tiles[2 * row][2 * column] != 'X':
            tiles[2 * row][2 * column] = 'X'
            pipe = pipes[row][column]
            previous_location = current_location
            row_change = row - previous_row
            column_change = column - previous_column
            match pipe:
                case '|' | '-':
                    current_location = (row + row_change, column + column_change)
                    tiles[2 * row + row_change][2 * column + column_change] = 'X'
                case 'L' | '7':
                    current_location = (row + column_change, column + row_change)
                    tiles[2 * row + column_change][2 * column + row_change] = 'X'
                case 'J' | 'F':
                    current_location = (row - column_change, column - row_change)
                    tiles[2 * row - column_change][2 * column - row_change] = 'X'
                case 'S':
                    pass
                case _:
                    raise ValueError(f'{pipe} at ({row}, {column})')
            previous_row, previous_column = previous_location
            row, column = current_location
        # now let's create a border
        tiles = [['O'] * (2 * len(pipes[0]))] + tiles + [['O'] * (2 * len(tiles[0]))]
        tiles = [['O'] + tile + ['O'] for tile in tiles]
        # fill in the "outside"
        finished: bool = False
        while not finished:
            finished = True
            for row in range(1, len(tiles) - 1):
                for column in range(1, len(tiles[0]) - 1):
                    if tiles[row][column] == 'I' and (tiles[row - 1][column] == 'O' or tiles[row][column - 1] == 'O' or
                                                      tiles[row + 1][column] == 'O' or tiles[row][column + 1] == 'O'):
                        tiles[row][column] = 'O'
                        finished = False
        # now shrink it back down to size, step 1: remove the border
        # arguably, this step is unnecessary, but it simplifies the expression in step 2
        tiles = [row[1:-1] for row in tiles[1:-1]]
        # shrink it back down to size, step 2: remove the "in between" tiles
        new_tiles: List[List[str]] = []
        for row in range(0, len(tiles), 2):
            new_row: List[str] = []
            for column in range(0, len(tiles[0]), 2):
                new_row.append(tiles[row][column])
            new_tiles.append(new_row)
        # count the "inside"
        return sum([functools.reduce(lambda x, y: x + y, map(lambda x: 1 if x == 'I' else 0, row)) for row in new_tiles])
    
    
    if __name__ == '__main__':
        production_ready = True
        raw_data = import_data(day) if production_ready else sample_data
        print(part1(parse_data(raw_data)))
        print(part2(parse_data(raw_data)))