from helpers import Helper helper = Helper(debug=True) debug = helper.debug load_input = helper.load_input class InputNumber: def __init__(self, number, start_pos, end_pos, line): self.number = number self.start_pos = start_pos self.end_pos = end_pos self.line = line def _is_symbol(self, char): return (char != "." and not char.isdigit()) def _check_up(self, input): if self.line == 0: return False cur_line = input[self.line - 1] for i in range(max(0, self.start_pos-1), min(len(cur_line)-1, self.end_pos+2)): char = cur_line[i] if self._is_symbol(char): debug(f"Found symbol next to {self.number} at line {self.line-1}: {i}") return True return False def _check_down(self, input): if self.line == len(input)-1: return False cur_line = input[self.line + 1] for i in range(max(0, self.start_pos-1), min(len(cur_line)-1, self.end_pos+2)): char = cur_line[i] if self._is_symbol(char): debug(f"Found symbol next to {self.number} at line {self.line+1}: {i}") return True return False def _check_left(self, input): if self.start_pos == 0: debug("Already at the left-hand side of the line") return False if self._is_symbol(input[self.line][self.start_pos-1]): debug(f"Found symbol next to {self.number} at line {self.line}: {self.start_pos-1}") return True return False def _check_right(self, input): if self.end_pos == len(input[0]) - 1: debug("Already at the right-hand side of the line") return False if self._is_symbol(input[self.line][self.end_pos+1]): debug(f"Found symbol next to {self.number} at line {self.line}: {self.end_pos+1}") return True return False def is_part_number(self, input): return ( self._check_up(input) or self._check_down(input) or self._check_left(input) or self._check_right(input) ) def main(): lines = load_input(3) # Input is lines of periods (.), numbers (0-9), and symbols # (anything that isn't a period or number) # Any number adjacent (horizontally, vertically, diagonally) # to a symbol is a part number. Get the sum of the part numbers. max_len = len(lines[0]) # all lines are the same length positions = [] for j, line in enumerate(lines): i = 0 while i < max_len: if line[i].isdigit(): current_number = "" start_pos = i while i < max_len and line[i].isdigit(): current_number += f"{line[i]}" i += 1 end_pos = i input_number = InputNumber( number = int(current_number), start_pos = start_pos, end_pos = end_pos-1, # i is one greater than the end of the number line = j ) positions.append(input_number) debug(f"Found {input_number.number} at line {input_number.line} ({input_number.start_pos}, {input_number.end_pos})") i += 1 # Now I have a list of the positions of all the numbers in the input. part_numbers = [] for p in positions: if p.is_part_number(lines): part_numbers.append(p.number) print(sum(part_numbers)) if __name__ == "__main__": main()