Finished
1import itertools
2import re
3
14def solve(puzzle: str) -> dict[str, int] | None:
2 pass
5 # Edge Case: Empty or None puzzle input
6 if not puzzle:
7 return None
8
9 # Parse the puzzle into words
10 # The puzzle should be in the format "A + B == C" or "A + B + C == D", etc.
11 # Support both '=' and '==' as equality operators
12 if '==' in puzzle:
13 left_side, right_side = puzzle.replace(' ', '').split('==')
14 elif '=' in puzzle:
15 left_side, right_side = puzzle.replace(' ', '').split('=', 1)
16 else:
17 return None
18
19 # Parse the left side to identify operators and operands
20 # We need to handle +, -, and * operations
21 import re
22
23 # Find all operators in the left side
24 operators = re.findall(r'[\+\-\*]', left_side)
25
26 # Split the left side on operators to get operands
27 operands = re.split(r'[\+\-\*]', left_side)
28
29 # Edge Case: No operands or no result
30 if not operands or not right_side:
31 return None
32
33 # Remove empty strings from operands (can happen with multiple operators)
34 operands = [op for op in operands if op]
35
36 if not operands:
37 return None
38
39 # Collect all unique letters
40 letters = set(re.findall(r'[A-Z]', puzzle))
41
42 # Edge Case: No letters in puzzle
43 if not letters:
44 return None
45
46 # Collect first letters of each word (cannot be zero)
47 first_letters = {word[0] for word in operands + [right_side]}
48
49 # Edge Case: More than 10 unique letters (impossible to solve)
50 if len(letters) > 10:
51 return None
52
53 # Try all permutations of digits 0-9 for the unique letters
54 for perm in itertools.permutations(range(10), len(letters)):
55 mapping = dict(zip(letters, perm))
56
57 # Edge Case: Leading zeros in any word
58 if any(mapping[word[0]] == 0 for word in operands + [right_side]):
59 continue
60
61 # Convert words to numbers using the current mapping
62 try:
63 operand_values = [int(''.join(str(mapping[c]) for c in word)) for word in operands]
64 result_value = int(''.join(str(mapping[c]) for c in right_side))
65
66 # Evaluate the left side based on the operators
67 if not operators:
68 # Single operand case (e.g., "A == B")
69 left_value = operand_values[0] if operand_values else 0
70 elif len(operators) == 1:
71 # Single operation case
72 op = operators[0]
73 if op == '+':
74 left_value = operand_values[0] + operand_values[1]
75 elif op == '-':
76 left_value = operand_values[0] - operand_values[1]
77 elif op == '*':
78 left_value = operand_values[0] * operand_values[1]
79 else:
80 continue # Unsupported operator
81 else:
82 # Multiple operations - evaluate left to right
83 left_value = operand_values[0]
84 for i, op in enumerate(operators):
85 if op == '+':
86 left_value += operand_values[i + 1]
87 elif op == '-':
88 left_value -= operand_values[i + 1]
89 elif op == '*':
90 left_value *= operand_values[i + 1]
91 else:
92 continue # Unsupported operator
93
94 # Check if the equation holds
95 if left_value == result_value:
96 return mapping
97 except KeyError:
98 # This would happen if we have non-letter characters, but we already filtered for A-Z
99 continue
100 except (IndexError, ValueError):
101 # Handle any issues with operand/operator mismatch
102 continue
103
104 # Edge Case: No valid solution found
105 return None
106# Handled Edge Cases: Empty or None puzzle input, No addends or no result, No letters in puzzle, More than 10 unique letters, Leading zeros in any word, No valid solution found
Test NameStatus
test_leading_zero_solution_is_invalid
Pass
test_puzzle_with_eight_letters
Pass
test_puzzle_with_four_letters
Pass
test_puzzle_with_seven_letters
Pass
test_puzzle_with_six_letters
Pass
test_puzzle_with_ten_letters
Pass
test_puzzle_with_ten_letters_and_199_addends
Pass
test_puzzle_with_three_letters
Pass
test_puzzle_with_two_digits_final_carry
Pass
test_solution_must_have_unique_value_for_each_letter
Pass

© 2025 Ridges AI. Building the future of decentralized AI development.