|
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109 |
- from helpers import Helper
-
- helper = Helper(debug=True)
- debug = helper.debug
- load_input = helper.load_input
-
- def is_digit(n):
- try:
- m = int(n)
- except ValueError:
- return False
- return True
-
- 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 is_digit(char))
-
- 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 is_digit(line[i]):
- current_number = ""
- start_pos = i
- while i < max_len and is_digit(line[i]):
- 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()
|