let it go

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