Browse Source

Day 3

master
Noëlle Anthony 11 months ago
parent
commit
1cfeba342e
2 changed files with 307 additions and 0 deletions
  1. 105
    0
      day03-1.py
  2. 202
    0
      day03-2.py

+ 105
- 0
day03-1.py View File

@@ -0,0 +1,105 @@
from helpers import debug, 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()

+ 202
- 0
day03-2.py View File

@@ -0,0 +1,202 @@
from helpers import debug, load_input

def is_digit(n):
try:
m = int(n)
except ValueError:
return False
return True

def is_star(n):
return n == "*"

input_numbers = []
stars = []

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 thats_me(self, line, pos):
return self.line == line and pos in range(self.start_pos, self.end_pos+1)

class Star:
def __init__(self, line, pos):
self.line = line
self.pos = pos
self.adjacent_numbers = []

def _check_up(self, input):
if self.line == 0:
debug("Already at the top")
return False
found_one = False
for i in range(self.pos-1, self.pos+2):
debug(f"Checking {self.line-1}:{i}")
char = input[self.line-1][i]
if is_digit(char):
target_number = [number for number in input_numbers if number.thats_me(self.line-1, i)][0]
if target_number not in self.adjacent_numbers:
self.adjacent_numbers.append(target_number)
found_one = True
return found_one
def _check_down(self, input):
if self.line == len(input) - 1:
debug("Already at the bottom")
return False
found_one = False
for i in range(self.pos-1, self.pos+2):
debug(f"Checking {self.line+1}:{i}")
char = input[self.line+1][i]
if is_digit(char):
target_number = [number for number in input_numbers if number.thats_me(self.line+1, i)][0]
if target_number not in self.adjacent_numbers:
self.adjacent_numbers.append(target_number)
found_one = True
return found_one
def _check_left(self, input):
if self.pos == 0:
debug ("Already at the left side")
return False
debug(f"Checking {self.line}:{self.pos-1}")
char = input[self.line][self.pos-1]
if is_digit(char):
target_number = [number for number in input_numbers if number.thats_me(self.line, self.pos-1)][0]
if target_number not in self.adjacent_numbers:
self.adjacent_numbers.append(target_number)
return True
return False
def _check_right(self, input):
if self.pos == len(input[0]) - 1:
debug ("Already at the right side")
return False
debug(f"Checking {self.line}:{self.pos+1}")
char = input[self.line][self.pos+1]
if is_digit(char):
target_number = [number for number in input_numbers if number.thats_me(self.line, self.pos+1)][0]
if target_number not in self.adjacent_numbers:
self.adjacent_numbers.append(target_number)
return True
return False
def _is_gear(self, input):
self._check_up(input)
self._check_down(input)
self._check_left(input)
self._check_right(input)
l_adj = len(self.adjacent_numbers)
n_adj = [number.number for number in self.adjacent_numbers]
debug(f"Star at {self.line}:{self.pos} has {l_adj} adjacent number{'s' if l_adj > 1 else ''}: {n_adj}")
return len(self.adjacent_numbers) == 2
def gear_value(self, input):
if self._is_gear(input):
return self.adjacent_numbers[0].number * self.adjacent_numbers[1].number
return 0

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
for j, line in enumerate(lines):
i = 0
while i < max_len:
if is_star(line[i]):
star = Star(
line=j,
pos=i
)
stars.append(star)
# debug(f"Found a star at {star.line}:{star.pos}")
elif 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
if i < max_len and is_star(line[i]):
star = Star(
line=j,
pos=i
)
stars.append(star)
# debug(f"Found a star next to a number at {star.line}:{star.pos}")
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
)
input_numbers.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 and stars in the input.
gear_values = []
for s in stars:
gear_values.append(s.gear_value(lines))
print(sum(gear_values))

if __name__ == "__main__":
main()

Loading…
Cancel
Save