tobe

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 puzzle (e.g., "SEND + MORE == MONEY")
7
8 Returns:
9 A dictionary mapping letters to digits, or None if no solution exists
10 """
11 # Edge Case: Empty or None puzzle
12 if not puzzle:
13 return None
14
15 # Parse the puzzle
16 parts = puzzle.replace("==", "=").replace(" ", "").split("=")
17
18 # Edge Case: Invalid puzzle format (no equals sign or too many parts)
19 if len(parts) != 2:
20 return None
21
22 right_side = parts[1]
23 left_sides = parts[0].split("+")
24
25 # Edge Case: No terms on the left side
26 if not left_sides or not all(left_sides):
27 return None
28
29 # Edge Case: Empty right side
30 if not right_side:
31 return None
32
33 # Get all unique letters
34 letters = set()
35 for part in left_sides + [right_side]:
36 letters.update(part)
37
38 # Edge Case: No letters in puzzle
39 if not letters:
40 return None
41
42 # Get first letters (can't be zero)
43 first_letters = {word[0] for word in left_sides + [right_side]}
44
45 # Edge Case: More than 10 unique letters (impossible to solve)
46 if len(letters) > 10:
47 return None
48
49 # Convert to list for indexing
50 letters = list(letters)
51
52 def evaluate(assignment):
53 """Evaluate if the current assignment satisfies the puzzle"""
54 # Check if any first letter is assigned zero
55 for letter in first_letters:
56 if assignment.get(letter) == 0:
57 return False
58
59 # Calculate left side sum
60 left_sum = 0
61 for word in left_sides:
62 num = 0
63 for char in word:
64 if char not in assignment:
65 return False # Not all letters assigned
66 num = num * 10 + assignment[char]
67 left_sum += num
68
69 # Calculate right side value
70 right_num = 0
71 for char in right_side:
72 if char not in assignment:
73 return False # Not all letters assigned
74 right_num = right_num * 10 + assignment[char]
75
76 return left_sum == right_num
77
78 def backtrack(index, assignment, used_digits):
79 """Backtracking search for a valid assignment"""
80 # Base case: all letters assigned
81 if index == len(letters):
82 if evaluate(assignment):
83 return assignment.copy()
84 return None
85
86 # Try each digit for the current letter
87 letter = letters[index]
88 for digit in range(10):
89 # Skip if digit already used
90 if digit in used_digits:
91 continue
92
93 # Assign digit to letter
94 assignment[letter] = digit
95 used_digits.add(digit)
96
97 # Recurse
98 result = backtrack(index + 1, assignment, used_digits)
99 if result is not None:
100 return result
101
102 # Backtrack
103 used_digits.remove(digit)
104 del assignment[letter]
105
106 return None
107
108 # Start backtracking
109 result = backtrack(0, {}, set())
110 return result
111
112# Handled Edge Cases: Empty or None puzzle, Invalid puzzle format, No terms on left side, Empty right side, No letters in puzzle, More than 10 unique letters
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.