couple

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 The function uses backtracking to find a valid assignment of digits to letters such that:
12 1. Each letter represents a unique digit
13 2. No leading digit is zero
14 3. The mathematical equation holds true
15 """
16 # Edge Case: Empty or None puzzle
17 if not puzzle:
18 return None
19
20 # Parse the puzzle
21 parts = puzzle.replace("==", "=").replace(" ", "").split("=")
22
23 # Edge Case: Invalid puzzle format (no equals sign or too many parts)
24 if len(parts) != 2:
25 return None
26
27 left_side, right_side = parts[0], parts[1]
28
29 # Split the left side by '+' to get addends
30 addends = left_side.split("+")
31
32 # Edge Case: No addends on the left side
33 if not addends or not all(addends):
34 return None
35
36 # Edge Case: Empty right side
37 if not right_side:
38 return None
39
40 # Extract all unique letters
41 letters = set()
42 for part in addends + [right_side]:
43 letters.update(part)
44
45 # Edge Case: No letters in puzzle
46 if not letters:
47 return None
48
49 # Extract first letters (can't be zero)
50 first_letters = {word[0] for word in addends + [right_side]}
51
52 # Edge Case: More than 10 unique letters (impossible to assign unique digits)
53 if len(letters) > 10:
54 return None
55
56 letters = list(letters)
57
58 def evaluate_word(word, assignment):
59 """Convert a word to a number based on the current assignment"""
60 result = 0
61 for char in word:
62 result = result * 10 + assignment[char]
63 return result
64
65 def is_valid_assignment(assignment):
66 """Check if the current assignment satisfies the equation"""
67 # Check for leading zeros
68 for word in addends + [right_side]:
69 if assignment[word[0]] == 0 and len(word) > 1:
70 return False
71
72 # Check if equation holds
73 left_sum = sum(evaluate_word(addend, assignment) for addend in addends)
74 right_value = evaluate_word(right_side, assignment)
75 return left_sum == right_value
76
77 def backtrack(index, assignment, used_digits):
78 """Recursively try digit assignments using backtracking"""
79 # Base case: all letters assigned
80 if index == len(letters):
81 if is_valid_assignment(assignment):
82 return assignment.copy()
83 return None
84
85 letter = letters[index]
86
87 # Try each digit from 0-9
88 for digit in range(10):
89 # Skip if digit already used
90 if digit in used_digits:
91 continue
92
93 # Skip if this is a first letter and digit is 0
94 if letter in first_letters and digit == 0:
95 continue
96
97 # Make assignment
98 assignment[letter] = digit
99 used_digits.add(digit)
100
101 # Recurse
102 result = backtrack(index + 1, assignment, used_digits)
103 if result is not None:
104 return result
105
106 # Backtrack
107 del assignment[letter]
108 used_digits.remove(digit)
109
110 return None
111
112 # Start backtracking
113 result = backtrack(0, {}, set())
114 return result
115
116# Handled Edge Cases: Empty/None puzzle, Invalid puzzle format, No addends, Empty right side, No letters, More than 10 unique letters, Leading zeros, Equation validation
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.