Sopa de letras
Contents
6. Sopa de letras¶
Uno de los pasatiempos más extendidos es el de las sopas de letras. Hace años era habitual encontrar publicaciones enteras de sopas de letras en los kioskos de estaciones y hospitales. A pesar de la sencillez de su mecanismo, su elaboración no es tan evidente. Existían profesiononales cuyo trabajo era exclusivamente preparar estos pasatiempos. Y fue así hasta que esta tarea se consiguió automatizar mediante programas informáticos.
En este capítulo vamos implementar un generador de sopas de letras muy sencillo, que además nos permita jugar. Para facilitar su programación vamos a asumir las siguientes simplificaciones:
No vamos a permitir que dos palabras se solapen (que una palabra use una letra de otra palabra)
La posición de las palabras sólo puede ser vertical o horizontal (en sentido inverso o no) pero en ningún caso en diagonal
See also
Podéis encontrar más información sobre este pasatiempo aquí.
6.1. Rellenar aleatoriamente la sopa de letras¶
En este apartado vamos a implementar la función fill_soup_random(available_letters, board_size) que rellena el tablero con letras aleatorias.
Los argumentos de entrada de la función son:
available_letters es una variable tipo LIST con las letras que se pueden usar en la sopa de letras
board_size es una varible tipo INT con el tamaño de la sopa de letras
La función devuelve una lista de listas con las letras que componen la sopa de letras. Por ejemplo, si definimos una variable available_letters con todas las letras del abecedario y una sopa de letras con board_size igual a 10. La función fill_soup_random(available_letters, board_size) nos devuelve una inicialización aleatoria de nuestro tablero de 10x10.
available_letters = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z']
fill_soup_random(available_letters, board_size=10)
[['u', 'h', 'f', 'i', 'e', 't', 'v', 'd', 'i', 's'],
['p', 'r', 'l', 'q', 'n', 'r', 'u', 'e', 'e', 'i'],
['n', 'o', 'a', 'i', 'a', 'l', 'x', 's', 'r', 'h'],
['l', 'f', 'p', 's', 'r', 'm', 'y', 'h', 'o', 'a'],
['r', 'v', 'b', 'k', 'v', 'i', 'e', 'u', 'f', 'd'],
['t', 'g', 'x', 'x', 'd', 'c', 'v', 'r', 'o', 'x'],
['j', 'g', 'n', 'b', 'x', 'e', 'u', 'j', 'o', 'h'],
['h', 'i', 'v', 'q', 'r', 'w', 's', 'u', 'd', 'e'],
['d', 'y', 'f', 'r', 'j', 'o', 'b', 'x', 'e', 'm'],
['e', 'x', 'c', 'q', 'v', 'y', 'a', 'x', 'w', 'y']]
Note
Esta función sólo distribuye letras de manera aleatoria. Puedes probar a ejecutar varias veces la misma función y comprobar que la distribución de consonantes y vocales cambia. En los próximos apartados rellenaremos la sopa de letras con palabras.
Solución:¶
import random
def fill_soup_random(available_letters, board_size):
soup = []
for i in range(board_size):
row = []
for j in range(board_size):
row.append(random.choice(available_letters))
soup.append(row)
return soup
6.2. Generación de dirección y sentido de una palabra¶
Para aumentar la aleatorización a la hora de colocar nuestras palabras, vamos a definir una función que seleccione aleatoriamente si la posición de la palabra es vertical u horizontal y si la dirección de la palabra es normal o inversa.
La función get_params() no tiene argumentos de entrada y debe devolver las siguientes variables buleanas:
is_horizontal es una variable de tipo BOOL que indica si la palabra va a ser horizontal o vertical
is_reverse: es una variable de tipo BOOL que indica si la palabra va a colocarse en dirección normal o invertida
Solución:¶
def get_params():
is_horizontal = random.choice([True, False])
is_reverse = random.choice([True, False])
return is_horizontal, is_reverse
get_params()
(True, False)
6.3. Obtener máximo índice de inicio¶
A la hora de colocar las palabras en el tablero de la sopa de letras, tenemos que saber qué posiciones podemos utilizar. Por ejemplo, si tenemos un tablero de longitud 5x5, y queremos introducir una palabra de longitud 3, podríamos colocar la palabra empezando en las posiciones 0, 1 y 2. Si intentáramos colocar una palabra de longitud 3 empezando en la posición 3, no tendríamos casillas suficientes (recordad que no contemplamos posiciones diagonales).
En este apartado vamos a implementar la función get_indexes(word, board_size, horizontal, reverse) para calcular los indices en filas y columnas que podemos usar para colocar una palabra. La función recibe como parámetros:
word con la palabra que queremos introducir en la sopa de letras en formato STRING
board_size con el tamaño de la sopa de letras
horizontal con un valor buleano indicando si la palabra se escribe en horizontal o vertical
reverse con un valor buleano indicando si la palabra se escribe en el sentido normal (de izquierda a derecha o de arriba hacia abajo) o invertida (de derecha a izquierda o de abajo hacia arriba)
La función debe devolver dos listas de índices aptos: una para las filas y otra para las columnas. Supongamos, por ejemplo, que tenemos que colocar la palabra “custom” en un tablero de 10x10. A continuación se muestran los índices en filas y columnas que se podrían utilizar dependiendo de la dirección y el sentido de escritura en el tablero:
get_indexes('custom', 10,horizontal=True, reverse=False)
([0, 1, 2, 3, 4, 5, 6, 7, 8, 9], [0, 1, 2, 3, 4])
get_indexes('custom', 10,horizontal=True, reverse=True)
([0, 1, 2, 3, 4, 5, 6, 7, 8, 9], [5, 6, 7, 8, 9])
get_indexes('custom', 10,horizontal=False, reverse=False)
([0, 1, 2, 3, 4], [0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
get_indexes('custom', 10,horizontal=False, reverse=True)
([5, 6, 7, 8, 9], [0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
Note
Notar que cuando la palabra se escribe en horizontal, cualquier fila es apta, mientras que cuando la palabra se escribe en vertical, cualquier columna es apta.
Solución:¶
def get_indexes(word, board_size, horizontal, reverse):
if horizontal and not reverse:
return list(range(0,board_size)),list(range(0,board_size - len(word)+1))
elif horizontal and reverse:
return list(range(0,board_size)),list(range(len(word)-1, board_size))
elif not horizontal and not reverse:
return list(range(0,board_size - len(word)+1)),list(range(0,board_size))
elif not horizontal and reverse:
return list(range(len(word)-1, board_size)),list(range(0,board_size))
6.4. Posición que ocupa una palabra en la sopa¶
En este apartado vamos a definir la función get_word_positions(start_index_rows, start_index_columns, is_horizontal, is_reverse, word) que devuelve una lista con las posiciones que ocupa una palabra en la sopa. La función recibe los siguientes parámetros:
start_index_rows es un número INT con el índice de la fila donde se empieza a escribir la palabra
start_index_columns es un número INT con el ínice de la columna donde se empieza a escribir la palabra
is_horizontal variable BOOL que indica si la palabra se escribe en horizontal o vertical
is_reverse: variable BOOL que indica si la palabra se escribe en sentido normal (de izquierda a derecha o de arriba hacia abajo) o invertida (de derecha a izquierda o de abajo hacia arriba)
word es una variable STRING que contiene la palabra que queremos escribir
La función debe devolver una lista con las posiciones que ocupa la palabra en la sopa de letras. Cada posicion es una tupla que contiene el índice de la fila y el índice de la columna. Por lo tanto, habrá tantas posiciones como letras de la palabra. En el caso de que la palabra esté en sentido inverso, las posiciones irán en sentido inverso.
Para entender mejor el funcionamiento de la función, veamos los siguientes ejemplos. Si intentamos escribir la palabra “hello” a partir de la posición (2,0) en dirección horizontal y sentido de izquierda a derecha, la lista de coordenadas será la siguiente:
get_word_positions(start_index_rows = 2, start_index_columns = 0, is_horizontal = True, is_reverse = False, word = "hello")
[(2, 0), (2, 1), (2, 2), (2, 3), (2, 4)]
El mismo ejemplo pero escribiendo en vertical y de arriba hacia abajo:
get_word_positions(start_index_rows = 2, start_index_columns = 0, is_horizontal = False, is_reverse = False, word = "hello")
[(2, 0), (3, 0), (4, 0), (5, 0), (6, 0)]
Escribiendo en horizontal pero de derecha a izquierda:
get_word_positions(start_index_rows = 7, start_index_columns = 10, is_horizontal = True, is_reverse = True, word = "hello")
[(7, 10), (7, 9), (7, 8), (7, 7), (7, 6)]
Y escribiendo en vertical pero de abajo hacia arriba:
get_word_positions(start_index_rows = 7, start_index_columns = 10, is_horizontal = False, is_reverse = True, word = "hello")
[(7, 10), (6, 10), (5, 10), (4, 10), (3, 10)]
Solución:¶
def get_word_positions(start_index_rows, start_index_columns, is_horizontal, is_reverse, word):
positions = []
if is_horizontal:
start_index = start_index_columns
if is_reverse==False:
end_index = start_index_columns + len(word) - 1
step=1
else:
end_index = start_index_columns - len(word) - 1
step=-1
for i in range(start_index, end_index + 1,step):
positions.append((start_index_rows,i))
else:
start_index = start_index_rows
if is_reverse==False:
end_index = start_index_rows + len(word) - 1
step=1
else:
end_index = start_index_rows - len(word) - 1
step=-1
for i in range(start_index, end_index + 1, step):
positions.append((i, start_index_columns))
return positions
6.5. Validar posición¶
Como hemos explicado, la simplificación de nuestro generador de sopas de letras no permite que haya solapamiento de palabras. Por ello, necesitamos construir una función que verifique si las posiciónes que ocupará una palabra están ya siendo utilizadas por alguna otra palabra.
La función se llama is_valid_position(word_positions, used_positions) y devuelve True si la posición es válida y False en caso contrario. Una palabra se considera válida si todas las posiciones que ocupa están disponibles. La función recibe como argumentos de entrada:
word_positions que contiene una lista de tuplas (fila, columna) que representan las posiciones de la palabra que estamos intentado colocar en el tablero
used_positions que contiene una lista de tuplas (fila, columna) que representan las posiciones ya ocupadas
Solución:¶
def is_valid_position(word_positions, used_positions):
for position in word_positions:
if position in used_positions:
return False
return True
6.6. Creación de la sopa de letras¶
En este apartado vamos a implementar, por fin, nuestro generador. La función create_soup(words, board_size) recibe como argumentos de entrada:
words es una variable que contiene una lista con las palabras que queremos colocar en la sopa de letras
board_size es una variable de tipo INT con el tamaño de la sopa de letras. Como sólo estamos considerando tableros cuadrados, la variable board_size sólo indicará el número de filas o el número de columnas
La lógica de la función es la siguiente:
Rellenamos la sopa de letras con letras aleatorias
Para cada palabra que vamos a colocar en la sopa de letras hacemos lo siguiente:
2.1. Obtenemos los parámetros de la palabra que indican si es horizontal o vertical y si es inversa o no
2.2. Obtenemos los rangos de índices válidos para las filas y las columnas
2.3. Obtenemos una posición aleatoria de entre los índices válidos para las filas
2.4. Obtenemos una posición aleatoria de entre los índices válidos para las columnas
2.5. Obtenemos las posiciones de la palabra
2.6. Comprobamos si las posiciones de la palabra se solapan con alguna palabra ya colocada anteriormente. Si hay solapamiento, volvemos al paso 2.1
2.7. Si las posiciones de la palabra son válidas, añadimos la palabra al diccionario dict_word_position cuyas claves son las palabras de la sopa de letras y los valores las posiciones que ocupa cada palabra
2.8. Añadimos las posiciones a una lista used_positions para llevar la cuenta de las posiciones ocupadas
2.9. Añadimos letra por letra la palabra a la sopa de letras
La función devuelve:
soup con una lista de listas de letras que contiene la información de la sopa de letras
dict_word_position con un diccionario que contiene las palabras de la sopa de letras y sus posiciones
Solución¶
def create_soup(words, board_size):
letras = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z']
soup = fill_soup_random(letras, board_size)
used_positions = []
dict_word_position = {}
for word in words:
valid = False
while not valid:
is_horizontal, is_reverse = get_params()
row_indexes,col_indexes=get_indexes(word, board_size,is_horizontal, is_reverse)
start_index_rows = random.sample(row_indexes,1)[0]
start_index_columns = random.sample(col_indexes,1)[0]
word_positions = get_word_positions(start_index_rows, start_index_columns, is_horizontal, is_reverse, word)
valid = is_valid_position(word_positions, used_positions)
dict_word_position[word] = word_positions
for i in range(len(word)):
used_positions.append(word_positions[i])
soup[word_positions[i][0]][word_positions[i][1]] = word[i]
return soup, dict_word_position
Aunque esta no será el interfaz de juego, conviene testear el comportamiento de la función create_soup de manera aislada:
soup, dict_word_position = create_soup(words=["custom","white","glass","computer"], board_size=10)
soup
[['h', 'd', 'f', 'i', 'i', 'z', 'c', 'g', 'c', 'i'],
['j', 'h', 'y', 'l', 'v', 'f', 'f', 'x', 'h', 's'],
['y', 's', 'o', 'a', 't', 's', 'q', 'p', 'w', 'c'],
['m', 's', 'p', 't', 'z', 'd', 'y', 'u', 'w', 'f'],
['j', 'a', 'c', 'u', 's', 't', 'o', 'm', 'p', 'q'],
['q', 'l', 'f', 'l', 'j', 't', 'i', 'g', 'o', 't'],
['j', 'g', 'e', 't', 'i', 'h', 'w', 't', 't', 'r'],
['k', 'd', 'o', 'd', 's', 'a', 'p', 'l', 'b', 'a'],
['r', 'e', 't', 'u', 'p', 'm', 'o', 'c', 'q', 'n'],
['j', 'l', 'v', 'b', 'y', 'u', 'p', 'c', 'q', 'y']]
dict_word_position
{'custom': [(4, 2), (4, 3), (4, 4), (4, 5), (4, 6), (4, 7)],
'white': [(6, 6), (6, 5), (6, 4), (6, 3), (6, 2)],
'glass': [(6, 1), (5, 1), (4, 1), (3, 1), (2, 1)],
'computer': [(8, 7), (8, 6), (8, 5), (8, 4), (8, 3), (8, 2), (8, 1), (8, 0)]}
Puedes revisar una a una cada palabra y sus posiciones para verificar que la función hace lo deseado. Tampoco sería mala idea probar la función con un tamaño de tablero más pequeño para ver cómo se comporta cuando el número de posiciones es insuficiente. O probar el mismmo ejemplo con un número de palabras muy elevado para ver qué ocurre cuando el tablero no puede encontrar una posición válida para una palabra…
Note
Es importante tener presente que el mecanismo que hemos implementado no es perfecto. Si queremos colocar muchas palabras en un tablero relativamente pequeño puede ocurrir que las limitaciones impuestas por las simplificaciones y que la forma de elección aleatoria de posiciones haga que la función create_soup necesite un tiempo arbitrariamente grande o incluso que se quede bloqueado porque no llega a encontrar una posición válida. La resolución de esta limitación se propone en el último apartado de este capítulo como mejora a implementar.
6.7. Interfaz Gráfico¶
Una vez que tenemos la sopa de letras, tenemos que ofrecer al usuario la posiblidad de jugarla. En otros capítulos de este libros hemos implementado la posibilidad de introducir manualmente las coordenadas, pero en un caso como este sería demasiado tedioso. Por eso vamos a construir un interfaz gráfico en el que iremos seleccionando con el ratón las letras que forman parte de una palabra.
Un ejemplo muy sencillo se muestra a continuación utilizando la librería PySimpleGUI. Empezamos creando una sopa de letras de 10x10 y colocando cuatro palabras.
words=["custom","white","glass","computer"]
soup, dict_word_position = create_soup(words, board_size=10)
Este código genera un tablero con las letras de la sopa de letras y permite ir pinchando en las casillas con el ratón. Tras cada pulsación del ratón, el color de la casilla cambia de blanco a negro. Al mismo tiempo, la posición de la casilla se devuelve en la variable event. Para clarificar su funcionamiento hemos incluido un:
print(event)
Esta instrucción te permite comprobar cómo al pulsar en cada una de las letras, el código devuelve la posición de la celda pulsada.
import PySimpleGUI as sg
import time
original_color = ('white',"#2d3a59")
selected_color = ('white','black')
layout = [[sg.Button(soup[i][j], size=(4, 2), key=(i,j), pad=(0,0)) for j in range(len(soup[0]))] for i in range(len(soup))]
layout.append([sg.Button('Exit', size=(4*4, 2), pad=(10,10), button_color=original_color)])
layout.append([sg.Text('Words: ', size=(10, 2), pad=(0,10)), sg.Text(",".join(words), size=(4*len(soup)*2, 2), pad=(0,10), key='-WORDS-')])
window = sg.Window('WORD SEARCH!', layout, element_justification='c')
while True:
event, _ = window.read()
print(event)
if event in (sg.WIN_CLOSED, 'Exit'):
break
window[event].update(soup[event[0]][event[1]], button_color=('white','black'))
window.close()
Vamos a intentar explicar un poco el código anterior. La variable layout contine una lista de lista de elementos sg.Button con la misma distribución que la variable soup. Si no lo ves claro, puedes intentar ejecutar, en una celda nueva, el comando:
layout = [[sg.Button(soup[i][j], size=(4, 2), key=(i,j), pad=(0,0)) for j in range(len(soup[0]))] for i in range(len(soup))]
print(layout)
Además de la propia sopa de letras, nuestro interfaz incluye un botón de salida que al ser pulsado enviará el evento EXIT, eso se consigue con el código:
layout.append([sg.Button('Exit', size=(4*4, 2), pad=(10,10), button_color=original_color)])
El interfaz también incluye un texto en la parte inferior de la ventana con la lista de palabras que hay que buscar en la sopa de letras. Eso se consigue con el código:
layout.append([sg.Text('Words: ', size=(10, 2), pad=(0,10)), sg.Text(",".join(words), size=(4*len(soup)*2, 2), pad=(0,10), key='-WORDS-')])
Note
Nota que el código:
while True:
event, _ = window.read()
if event in (sg.WIN_CLOSED, 'Exit'):
break
window[event].update(soup[event[0]][event[1]], button_color=('white','black'))
window.close()
Se limita a entrar en un bucle infinito hasta que se pulse el botón de EXIT o bien se cierre la ventana (generándose el evento sg.WIN_CLOSED) que permiten salir del while.
Tenemos que utilizar este código como punto de partida y adaptarlo a nuestro caso. Necesitaremos ir registrando todas las celdas que se vayan pulsando y almacenando la posición devuelta por la variable event. En función de las coordenadas pulsadas, tendremos que programar la inteligencia que permita detectar si con esas posiciones hemos localizado o no una palabra de las colocadas en la sopa de letras.
6.8. Obtener todas las palabras detectadas¶
Como el programa principal irá almacenando las coordenadas de las celdas pulsadas por el jugador, la detección de cuantas palabras han sido descubiertas se realizará comparando esas posiciones con las coordenadas almacenadas en el diccionario dict_word_position. Esa tarea la vamos a implementar en la función detect_words(dict_word_position,coordinates) que recibe como argumentos de entrada:
dict_word_position con el diccionario de las palabras escondidas y sus coordenadas
coordinates con una lista tuplas que continen las coordenadas de las celdas pulsadas por el jugador
La función debe devolver la lista de palabras que todavía no se han encontrado.
Solución:¶
def detect_words(dict_word_position,coordinates):
pending=[]
for word,positions in dict_word_position.items():
found=[]
for letter in positions:
if letter in coordinates:
found.append(1)
if sum(found)!=len(word):
pending.append(word)
return pending
Note
Esta función puede implementarse de diferentes formas. Nosotros hemos decidido ir verificando si las posiciones de las letras de cada palabra escondida han sido pulsadas por el jugador. Por cada posición pulsada, vamos a almacenar un 1 en la variable found. Una vez recorridas todas las posiciones de las letras de una misma palabra, chequeamos si la suma de esos 1’s coincide con la longitud de la palabra. El incumplimiento de esta condición significaría que hay alguna letra de esa palabra que todavía no ha sido pulsada, por lo que tendremos que añadir la variable word a la lista de palabras pendientes.
Por ejemplo, vamos a partir de este diccionario:
dict_word_position
{'custom': [(6, 0), (6, 1), (6, 2), (6, 3), (6, 4), (6, 5)],
'white': [(9, 5), (9, 6), (9, 7), (9, 8), (9, 9)],
'glass': [(3, 8), (4, 8), (5, 8), (6, 8), (7, 8)],
'computer': [(8, 8), (8, 7), (8, 6), (8, 5), (8, 4), (8, 3), (8, 2), (8, 1)]}
Si invocamos a la función detect_words(dict_word_position,coordinates) con una lista de posiciones aleatorias que no coincide con ninguna de las palabras, la función detect_words debería devolver todas las palabras:
detect_words(dict_word_position,[(0,0),(1,0),(1,1),(4,5),(7,2)])
['custom', 'white', 'glass', 'computer']
Si por el contrario invocamos a la función con las posiciones de las palabras white y glass, la función detect_words debería devolver sólo las palabras custom y computer:
detect_words(dict_word_position,[(3, 4), (3, 3), (3, 2), (3, 1), (3, 0),(0, 4), (0, 5), (0, 6), (0, 7), (0, 8)])
['custom', 'white', 'glass', 'computer']
6.9. Creación de la UI¶
Ahora es el momento de crear la interfaz gráfica de la sopa de letras. Para ello usaremos la librería PySimpleGUI que sirve para hacer interfaces gráficas sencillas. El objetivo es generar un interfaz similar a este con el tablero de letras, un texto que nos indique las palabras que hay que buscar y un botón para terminar la partida:
La función word_soup(soup, dict_word_position) recibirá dos argumentos de entrada:
soup con la lista que contiene las letras y las palabras de la sopa de letras
dict_word_position con el diccionario que contiene las palabras escondidas y las posiciones de sus letras
La función debe realizar las siguientes tareas, pero no es necesario que devuelva ningún valor:
Almacenar las coordenadas de las celdas pulsadas
Cambiar su color de blanco a negro
Si el juegado pulsa una celda ya pulsada, el código no debe hacer nada, es decir, ni se vuelve a almacenar su posición ni se devuelve su color de negro a blanco
Con cada pulsación del jugador, la función debe verificar las coordenadas almacenadas y compararlas con las posiciones de las palabras escondidas para detectar qué palabras han sido localizadas
Cada vez que el jugador localice una palabra, dicha palabra se eliminará de la lista que se muestra en la parte inferior del interfaz gráfico
Note
Puedes instalar la librería PySimpleGUI con el comando:
pip install pysimplegui
See also
Puedes encontrar más información sobre esta librería aquí.
Solución:¶
import PySimpleGUI as sg
import time
def word_soup(soup, dict_word_position):
original_color = ('white',"#2d3a59")
selected_color = ('white','black')
selected = []
pending_words = detect_words(dict_word_position,selected)
layout = [[sg.Button(soup[i][j], size=(4, 2), key=(i,j), pad=(0,0)) for j in range(len(soup[0]))] for i in range(len(soup))]
layout.append([sg.Button('Exit', size=(4*4, 2), pad=(10,10), button_color=original_color)])
layout.append([sg.Text('Words: ', size=(10, 2), pad=(0,10)), sg.Text(",".join(pending_words), size=(4*len(soup)*2, 2), pad=(0,10), key='WORDS')])
window = sg.Window('WORD SEARCH!', layout, element_justification='c')
start = time.time()
while len(pending_words)!=0:
event, values = window.read()
if event in (sg.WIN_CLOSED, 'Exit'):
# If the windows is closed or if the button Exist is pushed
break
else:
if event in selected:
# If the user pushed a cell that was already pushed before
pass
else:
selected.append(event)
window[event].update(button_color=selected_color)
pending_words = detect_words(dict_word_position,selected)
window['WORDS'].update(",".join(pending_words))
end = time.time()
elapsed = end - start
sg.Popup('Enhorabuena! Has terminado en {} segundos!'.format(round(elapsed,2)), keep_on_top=True)
window.close()
Podemos hacer una prueba generando un tablero pequeño de 6x6 y colocando 3 palabras fáciles de localizar:
words=["custom","white","glass"]
soup, dict_word_position = create_soup(words, board_size=6)
word_soup(soup, dict_word_position)
Al encontrar las tres palabras el código debería mostrar un popup informando del tiempo que hemos dedicado.
6.10. Extensiones del Juego¶
Este sencillo juego se puede mejorar mucho. Para empezar, hemos simplificado mucho el generador de sopas de letras limitándonos exclusviamente a palabras verticales y horizontales. Y respecto al interfaz, hemos utilizado un template muy básico. Estas son algunas ideas que puedes animarte a implementar:
Mejorar el sistema de posicionamiento de palabras para que la función create_soup no corra el riesgo de quedarse colgada en caso de no encontrar una posición para una palabra
Implementar la selección aleatoria de N palabras para la sopa de letras. En el repositorio de este libro adjuntamos un fichero words.txt con las palabras del diccionario español
Añadir la posibilidad de deshacer el pulsado de algunas celdas volviendo a pulsar en ellas
Utilizar colores diferentes para resaltar las celdas de palabras diferentes
Diseñar una sopa de letras que permita el solapamiento de palabras
Diseñar una sopa de letras que permita palabras en diagonal
Añadir un botón de reset que permita reinicializar el tablero con las mismas y otras palabras
Mejorar el aspecto del interfaz gráfico para que parezca más profesional