fishlium

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
23 if len(parts) != 2:
24 return None
25
26 right_side = parts[1]
27 left_sides = parts[0].split("+")
28
29 # Edge Case: No terms on the left side
30 if not left_sides or not all(left_sides):
31 return None
32
33 # Edge Case: Empty right side
34 if not right_side:
35 return None
36
37 # Get all unique letters
38 letters = set()
39 for part in left_sides + [right_side]:
40 letters.update(part)
41
42 # Edge Case: No letters in puzzle
43 if not letters:
44 return None
45
46 # Get first letters (can't be zero)
47 first_letters = {word[0] for word in left_sides + [right_side]}
48
49 # Edge Case: More than 10 unique letters (impossible to solve)
50 if len(letters) > 10:
51 return None
52
53 letters = list(letters)
54
55 def evaluate(assignment):
56 """Evaluate if the current assignment satisfies the puzzle."""
57 # Check if any first letter is assigned zero
58 for letter in first_letters:
59 if assignment.get(letter) == 0:
60 return False
61
62 # Convert words to numbers
63 left_values = []
64 for word in left_sides:
65 num = 0
66 for char in word:
67 if char not in assignment:
68 return False # Incomplete assignment
69 num = num * 10 + assignment[char]
70 left_values.append(num)
71
72 right_value = 0
73 for char in right_side:
74 if char not in assignment:
75 return False # Incomplete assignment
76 right_value = right_value * 10 + assignment[char]
77
78 return sum(left_values) == right_value
79
80 def backtrack(index, assignment, used_digits):
81 """Backtracking search for a valid assignment."""
82 # Base case: all letters assigned
83 if index == len(letters):
84 if evaluate(assignment):
85 return assignment.copy()
86 return None
87
88 letter = letters[index]
89
90 # Try each digit
91 for digit in range(10):
92 # Skip if digit already used
93 if digit in used_digits:
94 continue
95
96 # Skip if this is a first letter and digit is 0
97 if letter in first_letters and digit == 0:
98 continue
99
100 # Make assignment
101 assignment[letter] = digit
102 used_digits.add(digit)
103
104 # Recurse
105 result = backtrack(index + 1, assignment, used_digits)
106 if result is not None:
107 return result
108
109 # Backtrack
110 del assignment[letter]
111 used_digits.remove(digit)
112
113 return None
114
115 # Start backtracking
116 result = backtrack(0, {}, set())
117 return result
118
119# Handled Edge Cases: Empty or None puzzle, Invalid puzzle format, No terms on the left side, Empty right side, No letters in puzzle, More than 10 unique letters (impossible to solve)
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.