Skip to content

Instantly share code, notes, and snippets.

@jongyllen
Created December 7, 2024 11:32
Show Gist options
  • Select an option

  • Save jongyllen/b6891542ec8175df3761fe859749be57 to your computer and use it in GitHub Desktop.

Select an option

Save jongyllen/b6891542ec8175df3761fe859749be57 to your computer and use it in GitHub Desktop.
def evaluate_expression_slow(nums, operators):
"""Evaluate expression with given numbers and operators."""
result = nums[0]
for i in range(len(operators)):
if operators[i] == '+':
result += nums[i + 1]
elif operators[i] == '*':
result *= nums[i + 1]
else: # '||'
# Convert both numbers to strings, concatenate, then back to int
result = int(str(result) + str(nums[i + 1]))
return result
def evaluate_expression_fast(nums, operators):
"""Evaluate expression with given numbers and operators."""
result = nums[0]
for i in range(len(operators)):
if operators[i] == '+':
result += nums[i + 1]
elif operators[i] == '*':
result *= nums[i + 1]
else: # '||'
# Optimize concatenation by using powers of 10 instead of string operations
num_digits = len(str(nums[i + 1]))
result = result * (10 ** num_digits) + nums[i + 1]
return result
def can_make_equation_part2_slow(test_value, numbers):
"""Try combinations with +, *, and || operators - slower version."""
def try_combinations(pos, operators):
if pos == len(numbers) - 1:
result = evaluate_expression_slow(numbers, operators)
return result == test_value
# Try all three operators
for op in ['+', '*', '||']:
operators.append(op)
if try_combinations(pos + 1, operators):
return True
operators.pop()
return False
return try_combinations(0, [])
def can_make_equation_part2_fast(test_value, numbers):
"""Try combinations with +, *, and || operators - faster version."""
def try_combinations(pos, operators, current_result):
if pos == len(numbers) - 1:
return current_result == test_value
next_num = numbers[pos + 1]
# Try addition
new_result = current_result + next_num
operators.append('+')
if new_result <= test_value and try_combinations(pos + 1, operators, new_result):
return True
operators.pop()
# Try multiplication
new_result = current_result * next_num
operators.append('*')
if new_result <= test_value and try_combinations(pos + 1, operators, new_result):
return True
operators.pop()
# Try concatenation
num_digits = len(str(next_num))
new_result = current_result * (10 ** num_digits) + next_num
operators.append('||')
if new_result <= test_value and try_combinations(pos + 1, operators, new_result):
return True
operators.pop()
return False
return try_combinations(0, [], numbers[0])
def can_make_equation_part1(test_value, numbers):
"""Try combinations with only + and * operators."""
def try_combinations(pos, operators):
if pos == len(numbers) - 1:
result = evaluate_expression_fast(numbers, operators)
return result == test_value
# Try both + and *
for op in ['+', '*']:
operators.append(op)
if try_combinations(pos + 1, operators):
return True
operators.pop()
return False
return try_combinations(0, [])
def parse_line(line):
"""Parse a line into test_value and numbers."""
test_value, numbers = line.split(': ')
return int(test_value), [int(x) for x in numbers.split()]
def solve_calibration_part1(input_data):
"""Solve the calibration puzzle - Part 1."""
total = 0
for line in input_data.strip().split('\n'):
test_value, numbers = parse_line(line)
if can_make_equation_part1(test_value, numbers):
total += test_value
return total
def solve_calibration_part2(input_data):
"""Solve the calibration puzzle - Part 2."""
total = 0
for line in input_data.strip().split('\n'):
test_value, numbers = parse_line(line)
if can_make_equation_part2_fast(test_value, numbers):
total += test_value
return total
# Test case
test_input = """190: 10 19
3267: 81 40 27
83: 17 5
156: 15 6
7290: 6 8 6 15
161011: 16 10 13
192: 17 8 14
21037: 9 7 18 13
292: 11 6 16 20"""
def test_solution():
# Test Part 1
result1 = solve_calibration_part1(test_input)
expected1 = 3749 # 190 + 3267 + 292
assert result1 == expected1, f"Part 1: Expected {expected1}, but got {result1}"
print(f"Part 1 test passed! Result: {result1}")
# Test Part 2
result2 = solve_calibration_part2(test_input)
expected2 = 11387 # 3749 + 156 + 7290 + 192
assert result2 == expected2, f"Part 2: Expected {expected2}, but got {result2}"
print(f"Part 2 test passed! Result: {result2}")
def solve_file():
try:
with open('day7.data', 'r') as file:
data = file.read()
# Solve Part 1
result1 = solve_calibration_part1(data)
print(f"Solution for input file (Part 1): {result1}")
# Solve Part 2
result2 = solve_calibration_part2(data)
print(f"Solution for input file (Part 2): {result2}")
except FileNotFoundError:
print("Error: Could not find day7.data file")
if __name__ == "__main__":
# Run the test cases first
test_solution()
# Then solve the actual puzzle
solve_file()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment