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 The function uses backtracking with constraint propagation to find a valid digit assignment
12 for each letter such that:
13 1. Each letter maps to a unique digit (0-9)
14 2. No leading digit is zero
15 3. The mathematical equation holds true
16 """
17 # Parse the puzzle
18 if "==" not in puzzle:
19 return None
20
21 left_side, right_side = puzzle.split("==")
22 left_side = left_side.strip()
23 right_side = right_side.strip()
24
25 # Extract all words (alphanumeric sequences)
26 import re
27 words = re.findall(r'[A-Z]+', puzzle)
28 if not words:
29 return None
30
31 # Edge Case: Empty puzzle or no words
32 if not left_side or not right_side:
33 return None
34
35 # Get all unique letters
36 letters = set()
37 for word in words:
38 letters.update(word)
39
40 # Edge Case: More than 10 unique letters (impossible to assign unique digits)
41 if len(letters) > 10:
42 return None
43
44 letters = list(letters)
45
46 # Identify first letters (can't be zero)
47 first_letters = {word[0] for word in words}
48
49 # Split left side into addends
50 addends = [word.strip() for word in left_side.split("+") if word.strip()]
51
52 # Edge Case: No addends or no result
53 if not addends or not right_side:
54 return None
55
56 result = right_side
57
58 def to_number(word, mapping):
59 """Convert a word to a number using the given mapping."""
60 return int(''.join(str(mapping[char]) for char in word))
61
62 def is_valid_mapping(mapping):
63 """Check if the current mapping satisfies the puzzle equation."""
64 # Check for leading zeros
65 for word in words:
66 if mapping[word[0]] == 0 and len(word) > 1:
67 return False
68
69 # Calculate sum of addends
70 total = 0
71 for addend in addends:
72 total += to_number(addend, mapping)
73
74 # Check if it equals the result
75 return total == to_number(result, mapping)
76
77 def backtrack(index, mapping, used_digits):
78 """Backtracking function to find a valid digit assignment."""
79 # Base case: all letters have been assigned
80 if index == len(letters):
81 if is_valid_mapping(mapping):
82 return mapping.copy()
83 return None
84
85 letter = letters[index]
86
87 # Try each digit from 0 to 9
88 for digit in range(10):
89 # Skip if digit is 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 # Try this digit
98 mapping[letter] = digit
99 used_digits.add(digit)
100
101 # Recurse
102 result = backtrack(index + 1, mapping, used_digits)
103 if result is not None:
104 return result
105
106 # Backtrack
107 del mapping[letter]
108 used_digits.remove(digit)
109
110 return None
111
112 # Start backtracking
113 solution = backtrack(0, {}, set())
114 return solution
115
116# Handled Edge Cases: Empty puzzle, no words, more than 10 unique letters, no addends, no result, leading zeros
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.