🚀Wordle Solver: Mi Aliado para Ganar en Wordle
Hola! soy Rody y creé Wordle Solver, una herramienta visual y práctica que te ayuda a encontrar la mejor palabra en cada intento.
Wordle Solver es una herramienta diseñada para ayudar a resolver Wordle de manera rápida y eficiente. Se basa en un sistema de filtrado que utiliza el feedback (representado con los símbolos _ para “no aparece”, ? para “aparece pero en posición equivocada” y + para “aparece en la posición correcta”) para descartar palabras y sugerir las mejores opciones. La herramienta utiliza diccionarios de palabras en distintos idiomas y longitudes, con una diferenciación especial entre las palabras comunes (pre-filtradas y priorizadas) y las ampliadas.
Note
Lee detenidamente este documento, ya que contiene información importante sobre el proyecto.
La idea surgió tras descubrir el canal Programa con Arnau y su método para optimizar la resolución de Wordle. Su contenido me motivó a desarrollar una solución propia.
- Filtrado Eficiente: Utilizar un sistema basado en listas y conjuntos para descartar palabras en función del feedback recibido.
- Prioridad en Palabras Comunes: Sugerir primero palabras del diccionario “common”, los cuales han sido pre-filtrados por frecuencia y longitud.
- Interfaz Intuitiva: Proveer una experiencia visual y práctica para el usuario, con soporte multilingüe.
Exploré varios métodos para encontrar la mejor estrategia para filtrar palabras:
-
Trie:
Estructura eficiente para almacenar y buscar palabras. -
Búsqueda Binaria:
Excelente para listas ordenadas; es rápida pero requiere un diccionario ordenado. -
Tablas Hash (Set):
Búsquedas rápidas y eliminación de duplicados; muy práctica pero consume más memoria.
Note
Uso de Tablas Hash en el Proyecto
- excluded_letters: Se utiliza un set para almacenar las letras que no deben aparecer en la palabra.
- required_letters: Se utiliza un set para almacenar las letras que deben estar en la palabra.
- position_constraints: Se utiliza un diccionario con sets para manejar las restricciones de posición.
Justificación:
Opté por Tablas Hash (Set) porque ofrece una búsqueda eficiente y rápida, lo que se ajusta bien a la naturaleza de Wordle.
wordle-solver/
├── resources/ # Diccionarios de palabras
│ ├── 5_caracteres/
│ │ ├── common_english_5.txt
│ │ ├── common_spanish_5.txt
│ │ ├── english_5.txt
│ │ └── spanish_5.txt
│ ├── common_english.txt
│ ├── common_spanish.txt
│ ├── english.txt
│ └── spanish.txt
├── static/ # Assets del frontend
│ ├── css/
│ │ └── styles.css
│ └── js/
│ └── script.js
├── templates/ # Plantillas HTML
│ └── index.html
├── app.py # Servidor Flask
├── wordle_solver.py # Lógica principal del algoritmo
├── requirements.txt # Dependencias del proyecto
├── vercel.json # Configuración de despliegue en Vercel
└── LICENSE # Licencia del proyecto
Warning
NO BORRAR el archivo package.json si decides trabajar en el frontend.
-
Para palabras de 5 caracteres:
- Comunes:
resources/5_caracteres/common_spanish_5.txtresources/5_caracteres/common_english_5.txt
- Ampliados:
resources/5_caracteres/spanish_5.txtresources/5_caracteres/english_5.txt
- Comunes:
-
Para palabras de 4, 6, 7, 8, 9, 10, 11 caracteres:
- Comunes:
resources/common_spanish.txtresources/common_english.txt
- Ampliados:
resources/spanish.txtresources/english.txt
- Comunes:
Las palabras se cargan y normalizan (se eliminan acentos, excepto la Ñ, y se convierten a mayúsculas) al iniciarse el programa. Además, se eliminan duplicados usando estructuras de conjunto para asegurar que cada palabra aparezca una única vez.
Instala las dependencias con:
pip install -r requirements.txtpython app.pyVisita: http://localhost:5000
Important
Lee las guías de contribución antes de enviar un pull request.
- Selección de idioma.
- Mostrar el tablero del juego (game-dashboard).
- El usuario elige:
- Obtener una lista de palabras sugeridas.
- Escribir manualmente una palabra.
- Activar el área de juego con la primera palabra.
- El usuario cambia los colores según su feedback.
- Al siguiente clic en
generate-word-btn, se activavalid-wordsy se reduce la lista según el feedback.
_(Gris): La letra no está en la palabra.?(Amarillo): La letra está en la palabra, pero no en esa posición.+(Verde): La letra está en la palabra y en la posición correcta.
- Eliminar palabras no viables según las restricciones.
- Actualizar las opciones sugeridas.
- Letras excluidas: Las letras con
_no deben aparecer en la palabra. - Letras requeridas: Las letras con
?o+deben estar en la palabra. - Posiciones exactas: Las letras con
+deben estar en la posición exacta. - Posiciones prohibidas: Las letras con
?no deben estar en esa posición.
- Inicialización:
reset(): Reinicia restricciones y estado del solver.process_feedback(): Procesa el feedback y actualiza restricciones.
- Filtrado:
filter_words(): Filtra palabras válidas según restricciones.get_suggested_words(): Devuelve palabras sugeridas tras el filtrado.
- Manejo de Restricciones:
excluded_letters: Letras que no deben aparecer.required_letters: Letras que deben aparecer.position_constraints: Restricciones de posición.
- Uso de Palabras:
mark_word_as_used(): Marca palabras como usadas para no sugerirlas nuevamente.
Para la palabra "pato" con feedback _?+_:
pno está en la palabra (_).aestá en la palabra, pero no en la segunda posición (?).testá en la posición correcta (+).ono está en la palabra (_).
Las palabras sugeridas serán aquellas que cumplan estas condiciones.
- Validación de Feedback:
- Solo debe contener
_,?, y+. - Debe coincidir en longitud con la palabra ingresada.
- Solo debe contener
- Priorización de Palabras Comunes:
- Se dará prioridad a palabras de los diccionarios comunes antes de usar los ampliados.
A continuación, un fragmento comentado para que puedas entender el código:
from collections import defaultdict
import unicodedata
import random
class WordleSolver:
def __init__(self, word_list, word_length=5):
self.word_list = word_list
self.word_length = word_length
self.reset()
def reset(self):
"""Reinicia las restricciones y el estado del solver."""
self.excluded_letters = set() # Letras que no están en la palabra
self.required_letters = set() # Letras que deben estar en la palabra
self.position_constraints = {} # Restricciones de posición
self.used_words = set() # Palabras ya usadas
def process_feedback(self, word, feedback):
"""Procesa el feedback y actualiza las restricciones."""
if len(word) != self.word_length or len(feedback) != self.word_length:
raise ValueError("La palabra y el feedback deben tener la misma longitud.")
print(f"Procesando feedback para la palabra {word}: {feedback}")
for i, (letter, symbol) in enumerate(zip(word, feedback)):
if symbol == "_":
# La letra no está en la palabra
if letter not in self.required_letters:
self.excluded_letters.add(letter)
elif symbol == "?":
# La letra está en la palabra, pero no en esta posición
self.required_letters.add(letter)
if i not in self.position_constraints:
self.position_constraints[i] = set()
self.position_constraints[i].add(letter)
elif symbol == "+":
# La letra está en la posición correcta
self.required_letters.add(letter)
self.position_constraints[i] = letter
else:
raise ValueError(f"Símbolo no válido: {symbol}")
# Verificar que no haya contradicciones entre letras excluidas y requeridas
self.excluded_letters -= self.required_letters
# Imprimir los conjuntos de letras excluidas, requeridas y las restricciones de posición
print(f"Letras excluidas (no deberían estar en ninguna posición): {self.excluded_letters}")
print(f"Letras requeridas (deben estar en alguna posición): {self.required_letters}")
print(f"Restricciones de posición: {self.position_constraints}")
def filter_words(self):
"""Filtra las palabras válidas basadas en las restricciones actuales."""
print(f"Filtrando palabras con restricciones: {self.excluded_letters}, {self.required_letters}, {self.position_constraints}")
# Imprimir el total de palabras disponibles antes del filtro
print(f"Total palabras disponibles antes del filtro: {len(self.word_list)}")
print("Ejemplo de palabras antes del filtro:", self.word_list[:10]) # Muestra las 10 primeras
valid_words = []
for word in self.word_list:
print(f"Verificando palabra: {word}") # Nueva línea de depuración
if word in self.used_words:
continue # Saltar palabras ya usadas
# Verificar letras excluidas
if any(letter in self.excluded_letters for letter in word):
print(f"Palabra descartada por letras excluidas: {word}") # Nueva línea de depuración
continue
# Verificar letras requeridas
if not all(letter in word for letter in self.required_letters):
print(f"Palabra descartada por letras requeridas: {word}") # Nueva línea de depuración
continue
# Verificar restricciones de posición
valid = True
for i, constraint in self.position_constraints.items():
if i >= len(word):
continue # Evitar error de índice
if isinstance(constraint, set):
# Restricción de posición prohibida (símbolo "?")
if word[i] in constraint:
print(f"Palabra descartada por restricción de posición prohibida: {word}") # Nueva línea de depuración
valid = False
break
else:
# Restricción de posición exacta (símbolo "+")
if word[i] != constraint:
print(f"Palabra descartada por restricción de posición exacta: {word}") # Nueva línea de depuración
valid = False
break
if valid:
valid_words.append(word)
# Imprimir el total de palabras después del filtro
print(f"Total palabras después del filtro: {len(valid_words)}")
print("Ejemplo de palabras después del filtro:", valid_words[:10]) # Muestra las 10 primeras
print(f"Palabras sugeridas después de filtrar: {valid_words}") # ✅ Nueva línea para depuración
return valid_words
def get_suggested_words(self):
"""Obtiene una lista de palabras sugeridas basadas en las restricciones."""
valid_words = self.filter_words()
return valid_words
def mark_word_as_used(self, word):
"""Marca una palabra como usada."""
self.used_words.add(word)- Rendimiento: La búsqueda actual es O(n).
- Optimización: Se planea mejorar el filtrado y uso de memoria.
- Futuro: Implementar técnicas de Machine Learning para mejorar la selección de palabras.
| Estructura | Búsqueda | Inserción | Filtrado |
|---|---|---|---|
| Trie | O(m) | O(m) | O(m + k) |
| Tabla Hash | O(1) | O(1) | O(n) |
| BST | O(log n) | O(log n) | O(log n + k) |
- m: Longitud de la palabra.
- n: Número de palabras en el diccionario.
- k: Número de palabras válidas después del filtrado.
🚀 Conclusión sobre Estructuras
- Para una base de datos de palabras grande (> 10,000), Trie o Tabla Hash son mejores.
- Para optimizar aún más, se podría usar una combinación de Trie para indexar palabras y una tabla hash para acceso rápido a candidatos filtrados.
