Finished
11def solve(puzzle: str) -> dict[str, int] | None:
2 pass
2 """
3 Solve an alphametics puzzle.
4
5 Args:
6 puzzle: A string representing the alphametics puzzle (e.g., "SEND + MORE == MONEY")
7
8 Returns:
9 A dictionary mapping letters to digits that solves the puzzle, or None if no solution exists.
10
11 Example:
12 >>> solve("SEND + MORE == MONEY")
13 {'S': 9, 'E': 5, 'N': 6, 'D': 7, 'M': 1, 'O': 0, 'R': 8, 'Y': 2}
14 """
15 # Edge Case: Empty or None puzzle
16 if not puzzle:
17 return None
18
19 # Parse the puzzle
20 parts = puzzle.replace("==", "=").replace(" ", "").split("=")
21
22 # Edge Case: Invalid puzzle format (no equals sign or too many parts)
23 if len(parts) != 2:
24 return None
25
26 right_side = parts[1]
27 left_parts = parts[0].replace("+", " ").split()
28
29 # Edge Case: No terms on the left side
30 if not left_parts:
31 return None
32
33 # Check if right side is a numeric constant
34 if right_side.isdigit():
35 target_value = int(right_side)
36 # Extract letters only from left side
37 letters = set()
38 for part in left_parts:
39 letters.update(part)
40 right_side_letters = ""
41 else:
42 # Right side contains letters
43 target_value = None
44 # Extract all unique letters
45 letters = set()
46 for part in left_parts + [right_side]:
47 letters.update(part)
48 right_side_letters = right_side
49
50 # Edge Case: No letters in puzzle
51 if not letters:
52 # Special case: if it's a pure numeric equation like "5 == 5"
53 if target_value is not None:
54 left_values = []
55 for word in left_parts:
56 if word.isdigit():
57 left_values.append(int(word))
58 else:
59 # This shouldn't happen in a valid puzzle with no letters
60 return None
61 if sum(left_values) == target_value:
62 return {}
63 return None
64
65 # Extract first letters (can't be zero)
66 first_letters = {word[0] for word in left_parts}
67 if right_side_letters:
68 first_letters.add(right_side_letters[0])
69
70 # Convert letters to a list for indexing
71 letters_list = list(letters)
72
73 # Try all permutations of digits for the letters
74 from itertools import permutations
75
76 # Edge Case: More letters than digits (0-9)
77 if len(letters_list) > 10:
78 return None
79
80 # Try all digit assignments
81 for perm in permutations(range(10), len(letters_list)):
82 mapping = dict(zip(letters_list, perm))
83
84 # Edge Case: Leading zero in any number
85 if any(mapping[first] == 0 for first in first_letters):
86 continue
87
88 # Calculate values of left side terms
89 left_values = []
90 for word in left_parts:
91 if word.isdigit():
92 left_values.append(int(word))
93 else:
94 value = 0
95 for char in word:
96 value = value * 10 + mapping[char]
97 left_values.append(value)
98
99 # Calculate value of right side
100 if target_value is not None:
101 right_value = target_value
102 else:
103 right_value = 0
104 for char in right_side_letters:
105 right_value = right_value * 10 + mapping[char]
106
107 # Check if equation is satisfied
108 if sum(left_values) == right_value:
109 return mapping
110
111 # Edge Case: No valid solution found
112 return None
113
114# Handled Edge Cases: Empty or None puzzle, Invalid puzzle format, No terms on left side, No letters in puzzle, More letters than digits, Leading zero in any number, 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.