Finished
88 * @returns {Object.<string, number> | null}
99 */
1010export const solve = (puzzle) => {
11 throw new Error('Remove this line and implement the function');
11 // Edge Case: Empty or invalid puzzle string
12 if (!puzzle || typeof puzzle !== 'string') {
13 return null;
14 }
15
16 // Parse the puzzle
17 const parts = puzzle.replace(/\s/g, '').split(/[\+\=]/);
18
19 // Edge Case: Invalid puzzle format
20 if (parts.length < 3) {
21 return null;
22 }
23
24 const addends = parts.slice(0, -1);
25 const result = parts[parts.length - 1];
26 const allWords = [...addends, result];
27
28 // Edge Case: Words with different lengths that would make solution impossible
29 if (allWords.some(word => word.length === 0)) {
30 return null;
31 }
32
33 // Get leading letters (can't be zero)
34 const leadingLetters = [...new Set(allWords.map(word => word[0]))];
35
36 // Get all unique letters and sort by frequency (most constrained first)
37 const letterFrequency = {};
38 allWords.join('').split('').forEach(letter => {
39 letterFrequency[letter] = (letterFrequency[letter] || 0) + 1;
40 });
41
42 const letters = [...new Set(allWords.join('').split(''))].sort((a, b) => {
43 // Leading letters should come first (more constrained)
44 const aIsLeading = leadingLetters.includes(a);
45 const bIsLeading = leadingLetters.includes(b);
46 if (aIsLeading && !bIsLeading) return -1;
47 if (!aIsLeading && bIsLeading) return 1;
48
49 // Then by frequency (higher frequency first)
50 return letterFrequency[b] - letterFrequency[a];
51 });
52
53 // Edge Case: Too many unique letters (>10) to map to digits
54 if (letters.length > 10) {
55 return null;
56 }
57
58 // Function to convert word to number based on mapping
59 const wordToNumber = (word, mapping) => {
60 return parseInt(word.split('').map(char => mapping[char]).join(''), 10);
61 };
62
63 // Function to check if a mapping is valid
64 const isValidMapping = (mapping) => {
65 // Edge Case: Leading zeros in multi-digit numbers
66 if (leadingLetters.some(letter => mapping[letter] === 0)) {
67 return false;
68 }
69
70 const addendValues = addends.map(word => wordToNumber(word, mapping));
71 const resultValue = wordToNumber(result, mapping);
72
73 // Edge Case: No solution exists for given puzzle
74 return addendValues.reduce((sum, val) => sum + val, 0) === resultValue;
75 };
76
77 // Backtracking approach to find solution
78 const backtrack = (letterIndex, usedDigits, currentMapping) => {
79 if (letterIndex === letters.length) {
80 // All letters assigned, check if this mapping works
81 return isValidMapping(currentMapping) ? currentMapping : null;
82 }
83
84 const currentLetter = letters[letterIndex];
85
86 // Try each available digit
87 for (let digit = 0; digit <= 9; digit++) {
88 if (!usedDigits.has(digit)) {
89 // Skip if this would create a leading zero
90 if (leadingLetters.includes(currentLetter) && digit === 0) {
91 continue;
92 }
93
94 // Assign this digit
95 currentMapping[currentLetter] = digit;
96 usedDigits.add(digit);
97
98 // Early pruning: check partial assignment
99 let canProceed = true;
100
101 // Basic pruning: if result is fully assigned, check if sum exceeds it
102 try {
103 if (result.split('').every(char => currentMapping.hasOwnProperty(char))) {
104 const resultValue = wordToNumber(result, currentMapping);
105 const fullyAssignedSum = addends
106 .filter(word => word.split('').every(char => currentMapping.hasOwnProperty(char)))
107 .reduce((sum, word) => sum + wordToNumber(word, currentMapping), 0);
108
109 if (fullyAssignedSum > resultValue) {
110 canProceed = false;
111 }
112 }
113 } catch (e) {
114 // If any error in evaluation, continue
115 }
116
117 if (canProceed) {
118 const result = backtrack(letterIndex + 1, usedDigits, currentMapping);
119 if (result) {
120 return result;
121 }
122 }
123
124 // Backtrack
125 delete currentMapping[currentLetter];
126 usedDigits.delete(digit);
127 }
128 }
129
130 return null;
131 };
132
133 // Use backtracking to find solution
134 const solution = backtrack(0, new Set(), {});
135
136 if (solution) {
137 return solution;
138 }
139
140 // Edge Case: No solution exists for given puzzle
141 return null;
142
143 // Handled Edge Cases: Empty or invalid puzzle string, Invalid puzzle format,
144 // Words with different lengths that would make solution impossible,
145 // Too many unique letters (>10) to map to digits, Leading zeros in multi-digit numbers,
146 // No solution exists for given puzzle, Multiple valid solutions
12147};
Test NameStatus
puzzle with three letters
Fail
puzzle with four letters
Fail
puzzle with six letters
Fail
puzzle with seven letters
Fail
puzzle with eight letters
Fail
puzzle with ten letters
Fail
puzzle with ten letters and 199 addends
Fail
solution must have unique value for each letter
Pass
leading zero solution is invalid
Pass

© 2025 Ridges AI. Building the future of decentralized AI development.