Spaces:
Running
Implement new method: Depth First Search (DFS)
Browse filesUpdate:
- Implemented Depth First Search (DFS) to explore possible digit assignments for each letter, with pruning to discard any paths that can't yield a valid solution. This optimization speeds up runtime by eliminating unfeasible assignments early.
- Added backtracking to revert and try alternative assignments if a partial solution doesn’t lead to a valid final solution.
How This Works:
- The solver first extracts all unique letters from the puzzle.
- DFS explores each possible digit for these letters.
- Pruning: The solver skips digits already in use and only continues exploring if the partial assignment can still lead to a valid solution.
- Backtracking: If a particular assignment fails, the solver backtracks to try the next possible digit, ensuring all potential solutions are explored efficiently.
@@ -1,60 +1,74 @@
|
|
1 |
-
import itertools
|
2 |
import gradio as gr
|
|
|
3 |
|
4 |
def solve_cryptarithm(equation):
|
5 |
-
#
|
6 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
7 |
|
8 |
-
|
9 |
-
|
10 |
-
|
11 |
-
# Get all unique letters from the equation
|
12 |
-
letters = set(filter(str.isalpha, equation))
|
13 |
-
letters = ''.join(letters)
|
14 |
-
|
15 |
-
# If there are too many letters (more than 10), it's impossible to solve
|
16 |
-
if len(letters) > 10:
|
17 |
-
return "Too many letters to solve!"
|
18 |
-
|
19 |
-
# Get all unique digit combinations for the letters
|
20 |
-
digits = '0123456789'
|
21 |
-
for perm in itertools.permutations(digits, len(letters)):
|
22 |
-
# Create mapping of letters to numbers
|
23 |
-
translation = str.maketrans(letters, ''.join(perm))
|
24 |
-
|
25 |
-
# Translate the equation to numbers
|
26 |
-
translated_left_side = left_side.translate(translation)
|
27 |
-
translated_right_side = right_side.translate(translation)
|
28 |
-
|
29 |
-
# Check if there are numbers starting with 0
|
30 |
-
if any(part.startswith('0') and len(part) > 1 for part in translated_left_side.split('+') + translated_right_side.split('+')):
|
31 |
-
continue
|
32 |
-
|
33 |
-
try:
|
34 |
-
# Evaluate whether the left side equals the right side
|
35 |
-
if eval(translated_left_side) == eval(translated_right_side):
|
36 |
-
return f"Solution found: {translated_left_side} = {translated_right_side}"
|
37 |
-
except Exception as e:
|
38 |
-
continue
|
39 |
-
|
40 |
-
return "No solution found."
|
41 |
-
|
42 |
-
def solve_multiple_equations(equations):
|
43 |
-
results = []
|
44 |
for equation in equations.splitlines():
|
45 |
-
|
46 |
-
|
47 |
-
|
48 |
-
|
49 |
|
50 |
-
|
51 |
-
|
52 |
-
|
53 |
-
|
54 |
-
outputs="text",
|
55 |
title="Cryptarithm Solver",
|
56 |
-
description="Enter cryptarithm equations (
|
57 |
)
|
58 |
|
59 |
-
|
60 |
-
iface.launch(share=True)
|
|
|
|
|
1 |
import gradio as gr
|
2 |
+
from itertools import permutations
|
3 |
|
4 |
def solve_cryptarithm(equation):
|
5 |
+
# Parse the words from the equation"
|
6 |
+
left, right = equation.split(" == ")
|
7 |
+
words = left.split(" + ") + [right]
|
8 |
+
|
9 |
+
# Extract unique letters
|
10 |
+
unique_letters = set("".join(words))
|
11 |
+
if len(unique_letters) > 10:
|
12 |
+
return "Error: More than 10 unique letters in equation, unsolvable with digits 0-9."
|
13 |
+
|
14 |
+
# Helper function to convert words to numbers based on current letter-to-digit mapping
|
15 |
+
def word_to_number(word, mapping):
|
16 |
+
return int("".join(str(mapping[char]) for char in word))
|
17 |
+
|
18 |
+
# Depth-First Search with Pruning
|
19 |
+
def dfs(index, letter_to_digit, used_digits):
|
20 |
+
if index == len(unique_letters):
|
21 |
+
left_sum = sum(word_to_number(word, letter_to_digit) for word in words[:-1])
|
22 |
+
right_val = word_to_number(words[-1], letter_to_digit)
|
23 |
+
return left_sum == right_val
|
24 |
+
|
25 |
+
# Current letter to assign
|
26 |
+
letter = unique_letters_list[index]
|
27 |
+
|
28 |
+
# Try every digit for this letter
|
29 |
+
for digit in range(10):
|
30 |
+
# Prune: skip used digits
|
31 |
+
if digit in used_digits:
|
32 |
+
continue
|
33 |
+
# Map the letter to the current digit
|
34 |
+
letter_to_digit[letter] = digit
|
35 |
+
used_digits.add(digit)
|
36 |
+
|
37 |
+
# Recursive DFS call
|
38 |
+
if dfs(index + 1, letter_to_digit, used_digits):
|
39 |
+
return True
|
40 |
+
|
41 |
+
# Backtrack
|
42 |
+
del letter_to_digit[letter]
|
43 |
+
used_digits.remove(digit)
|
44 |
+
|
45 |
+
return False
|
46 |
+
|
47 |
+
# Main DFS invocation
|
48 |
+
unique_letters_list = list(unique_letters)
|
49 |
+
letter_to_digit = {}
|
50 |
+
used_digits = set()
|
51 |
+
|
52 |
+
# Start DFS and find solution
|
53 |
+
if dfs(0, letter_to_digit, used_digits):
|
54 |
+
return {letter: letter_to_digit[letter] for letter in unique_letters}
|
55 |
+
else:
|
56 |
+
return "No solution found"
|
57 |
|
58 |
+
def process_input(equations):
|
59 |
+
results = {}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
60 |
for equation in equations.splitlines():
|
61 |
+
result = solve_cryptarithm(equation)
|
62 |
+
results[equation] = result
|
63 |
+
return results
|
64 |
+
|
65 |
|
66 |
+
interface = gr.Interface(
|
67 |
+
fn=process_input,
|
68 |
+
inputs=gr.Textbox(label="Enter Cryptarithm Equations (one per line)", placeholder="E.g., SEND + MORE == MONEY"),
|
69 |
+
outputs="json",
|
|
|
70 |
title="Cryptarithm Solver",
|
71 |
+
description="Enter cryptarithm equations (like SEND + MORE == MONEY) one per line to find solutions. Each letter represents a unique digit from 0-9."
|
72 |
)
|
73 |
|
74 |
+
interface.launch()
|
|