Java - Ayuda con ejercicio

 
Vista:

Ayuda con ejercicio

Publicado por Luis (3 intervenciones) el 11/09/2022 03:39:29
Necesito ayuda para lo siguiente:
Necesito a partir de ua matriz y una palabra validar si la palabra esta contenida en la matriz de forma diagonal.
Aqui va un ejemplo:
S S D Z F
F G U Y T
H L F R T
E E E E E
G E T Y U
Ñ P O J Y

palabra luz

Logre hacerlo para la forma horizontal y vertical con dos metodos, pero claramente necesito ayuda para la forma diagonal, mas que nada, nose como estudiar todos los casos posibles.
Mil gracias, cualquier pista sirve!
Valora esta pregunta
Me gusta: Está pregunta es útil y esta claraNo me gusta: Está pregunta no esta clara o no es útil
0
Responder
Imágen de perfil de Kabuto
Val: 3.428
Oro
Ha mantenido su posición en Java (en relación al último mes)
Gráfica de Java

Ayuda con ejercicio

Publicado por Kabuto (1381 intervenciones) el 11/09/2022 13:27:13
Hola Luis.

Te propongo la siguiente solución.
En el siguiente código, hay un método que explora las 8 posibles direcciones:
- horizontal hacia la derecha
- horizontal hacia la izquierda
- vertical hacia abajo
- vertical hacia arriba
- diagonal superior derecha
- diagonal superior izquierda
- diagonal inferior derecha
- diagonal inferior izquierda

Para hacer esto, lo que hacemos es, con dos bucles anidados, recorrer la matriz buscando una letra que coincida con la primera letra (posición 0) de la palabra que buscamos.

Cuando encontramos dicha letra, se empieza a comprobar cada posible dirección. ¿Cómo?
Iniciamos un tercer bucle que recorrerá las siguientes posiciones de la palabra, es decir, la posición 1, la 2,... hasta terminar la palabra.
Para poder comparar con las letras correspondientes a la dirección que estamos comprobando, lo que haremos será hacer una suma o una resta con el índice que está recorriendo la palabra y con el índice, o índices, que recorren las letras de la matriz.

Es decir, la matriz la estaremos recorriendo con dos índices, los clásicos i y j ...
El índice i recorre las "filas" de la matriz, es decir, hace el recorrido vertical
El índice j recorre las "columnas", o sea, el recorrido horizontal.

Entonces, si yo quiero comprobar la dirección "Vertical hacia abajo", lo que haré será hacer una suma del valor del indice i + el valor del índice que recorre la palabra.
De esa manera, estoy recorriendo la palabra y al mismo tiempo las letras en vertical hacia abajo, a partir de la letra que había coincidido.

Te pongo un fragmento del código porque seguro se entiende mejor.
Fíjate en lo que marco en negrita, a la matriz (que yo llamo sopa, por ser una Sopa de Letras), con su indice i hago una suma con el indice v, que es que recorre la palabra
1
2
3
4
5
6
7
8
for (int v = 1; v < pal.length(); v++) {
							if (pal.charAt(v) == sopa[i+v][j])
								encontrado = true;
							else {
								encontrado = false;
								break;
							}
						}
.
Si encuentro que la siguiente letra coincide, a un boolean llamado encontrad le mantengo el valor true. Esto me ayuda a saber si al terminar de recorrer la palabra, me han coincidido todas las letras.
En cambio, si encuentro una letra que NO coincide, ese boolean pasa a ser false, y además hago un break. Ese break lo que hace es interrumpir, este tercer bucle, porque si me ha fallado una letra no vale la pena seguir comprobando las demás.

Bien, esto es para buscar en vertical hacia abajo.
Si quiero buscar en la vertical hacia arriba, el código es el mismo, solo que ahora en lugar de una suma, hago una resta.
Porque así recorro las "filas" de la matriz a la inversa, es decir, hacia arriba
1
2
3
4
5
6
7
8
for (int v = 1; v < pal.length(); v++) {
							if (pal.charAt(v) == sopa[i-v][j])
								encontrado = true;
							else {
								encontrado = false;
								break;
							}
						}

Si quiero buscar en las horizontales, las sumas restas, se las hago a j que es quien recorre las columnas:
1
2
3
4
5
6
7
8
for (int h = 1; h < pal.length(); h++) {
							if (pal.charAt(h) == sopa[i][j-h])
								encontrado = true;
							else {
								encontrado = false;
								break;
							}
						}

¿Y si quiero buscar en las diagonales?
Pues hago las operaciones en ambos índices. Sumaré o restaré según la dirección que quiero comprobar.
Por ejemplo, si quiero mirar la diagonal inferior derecha, necesito sumar tanto las filas como las columnas:
1
2
3
4
5
6
7
8
for (int d = 1; d < pal.length(); d++) {
							if (pal.charAt(d) == sopa[i+d][j+d])
								encontrado = true;
							else {
								encontrado = false;
								break;
							}
						}
En cambio, si quiero mirar la diagonal inferior izquierda, sumo a las filas pero resto a las columnas:
1
2
3
4
5
6
7
8
for (int d = 1; d < pal.length(); d++) {
							if (pal.charAt(d) == sopa[i+d][j-d])
								encontrado = true;
							else {
								encontrado = false;
								break;
							}
						}


En definitiva, jugando con estas sumas y restas, podemos movernos en todos los sentidos posibles dentro de las dos dimensiones que tiene la matriz.

Pero, ojo cuidado, hay que tener en cuenta una cosa.
En nuestras exploraciones de las distintas direcciones, corremos el riesgo de salirnos de los límites de la matriz, lo cuál producirá una excepción y el programa terminará de forma brusca.

Para evitarlo, en cada dirección explorada, debemos usar TRY CATCH para capturar esa posible excepción y que el programa pueda continuar.
Si una dirección explorada provoca excepción, es que en esa dirección no vamos a encontrar la palabra que buscamos, por tanto al capturar la excepción, el boolean que nos dice si estamos encontrando lo que buscamos, pasará a false.

Así, cada vez que acabemos de explorar una dirección, ya sea porque los bucles han terminado bien o porque se ha producido una excepción, comprobaremos que valor tiene el boolean "encontrado".
Si es true, nuestra búsqueda ha terminado y hacemos que nuestro método retorne "Verdadero".

Si no es true, pues entonces el método continua para comprobar la siguiente posible dirección de búsqueda:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
					//Diagonal superior izquierda
					try {
						for (int d = 1; d < pal.length(); d++) {
							if (pal.charAt(d) == sopa[i-d][j-d])
								encontrado = true;
							else {
								encontrado = false;
								break;
							}
						}
					} catch(ArrayIndexOutOfBoundsException ex) {
						encontrado = false;
					}
					if (encontrado)
						return true;


Todo esto lo aplicamos en el siguiente programa ya completo, donde podemos comprobar que funciona perfectamente:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
import java.util.Arrays;
 
public class SopaLetras {
 
	public static void main(String[] args) {
 
		char[][] sopa = new char[][] {
			{'S','S','D','Z','F'},
			{'F','G','U','Y','T'},
			{'H','L','F','R','T'},
			{'E','E','E','E','E'},
			{'G','E','T','Y','U'},
			{'Ñ','P','O','J','Y'}
		};
 
		String palabra = "LUZ";
 
		System.out.println("\tSOPA DE LETRAS");
		System.out.println("\t---- -- ------\n");
		for (char[] fila: sopa)
			System.out.println("\t" + Arrays.toString(fila));
 
		System.out.println("\nPalabra a buscar: " + palabra);
 
		System.out.println(buscarEnSopa(sopa, palabra)?"Encontrada":"No encontrada");
	}
 
	private static boolean buscarEnSopa(char[][] sopa, String pal) {
 
		for (int i = 0; i < sopa.length; i++) {
			for (int j = 0; j < sopa[i].length; j++) {
				if (sopa[i][j] == pal.charAt(0)) {
 
					boolean encontrado = true; //De momento, puede que la hayamos encontrado
					/*
					 * A continuación buscaremos en las 8 direcciones posibles.
					 * En cada búsqueda hay riesgo de salirnos de los límites de la matriz
					 * al buscar letras coincidentes y provocar una excepción.
					 * Con TRY CATCH podemos evitar que dicha excepción interrumpa el programa.
					 */
 
					//Comprobamos Horizontal hacia adelante
					try {
						for (int h = 1; h < pal.length(); h++) {
							if (pal.charAt(h) == sopa[i][j+h])
								encontrado = true; //Sigue abierta la posibilidad de haberla encontrado
							else {
								encontrado = false; //No, aquí no está
								break;//Interrumpimos este bucle, no hace falta seguir comprobando
							}
						}
					} catch(ArrayIndexOutOfBoundsException ex) {
						//Nos hemos salido de la matriz.
						//Significa que la palabra no está en esta dirección de búsqueda
						encontrado = false;
					}
					if (encontrado) //Si se ha encontrado
						return true; //Fin de método
					//Parece que no se ha encontrado, probamos con la siguiente dirección
 
					//Horizontal hacia atrás
					try {
						for (int h = 1; h < pal.length(); h++) {
							if (pal.charAt(h) == sopa[i][j-h])
								encontrado = true;
							else {
								encontrado = false;
								break;
							}
						}
					} catch(ArrayIndexOutOfBoundsException ex) {
						encontrado = false;
					}
					if (encontrado)
						return true;
 
					//Vertical hacia abajo
					try {
						for (int v = 1; v < pal.length(); v++) {
							if (pal.charAt(v) == sopa[i+v][j])
								encontrado = true;
							else {
								encontrado = false;
								break;
							}
						}
					} catch(ArrayIndexOutOfBoundsException ex) {
						encontrado = false;
					}
					if (encontrado)
						return true;
 
					//Vertical hacia arriba
					try {
						for (int v = 1; v < pal.length(); v++) {
							if (pal.charAt(v) == sopa[i-v][j])
								encontrado = true;
							else {
								encontrado = false;
								break;
							}
						}
					} catch(ArrayIndexOutOfBoundsException ex) {
						encontrado = false;
					}
					if (encontrado)
						return true;
 
					//Diagonal superior derecha
					try {
						for (int d = 1; d < pal.length(); d++) {
							if (pal.charAt(d) == sopa[i-d][j+d])
								encontrado = true;
							else {
								encontrado = false;
								break;
							}
						}
					} catch(ArrayIndexOutOfBoundsException ex) {
						encontrado = false;
					}
					if (encontrado)
						return true;
 
					//Diagonal inferior derecha
					try {
						for (int d = 1; d < pal.length(); d++) {
							if (pal.charAt(d) == sopa[i+d][j+d])
								encontrado = true;
							else {
								encontrado = false;
								break;
							}
						}
					} catch(ArrayIndexOutOfBoundsException ex) {
						encontrado = false;
					}
					if (encontrado)
						return true;
 
					//Diagonal superior izquierda
					try {
						for (int d = 1; d < pal.length(); d++) {
							if (pal.charAt(d) == sopa[i-d][j-d])
								encontrado = true;
							else {
								encontrado = false;
								break;
							}
						}
					} catch(ArrayIndexOutOfBoundsException ex) {
						encontrado = false;
					}
					if (encontrado)
						return true;
 
					//Diagonal inferior izquierda
					try {
						for (int d = 1; d < pal.length(); d++) {
							if (pal.charAt(d) == sopa[i+d][j-d])
								encontrado = true;
							else {
								encontrado = false;
								break;
							}
						}
					} catch(ArrayIndexOutOfBoundsException ex) {
						encontrado = false;
					}
					if (encontrado)
						return true;
				}
			}
		}
		//Palabra no ha sido encontrada en ninguna dirección
		return false;
	}
 
}

Sí, es un código bastante largo.
Pero lo importante es que funciona y sobre todo que lo entiendas.
Prueba, revisa y pregunta tanto como necesites para que comprendas la lógica que se ha aplicado.

Una vez lo hayas entendido, vamos a hacer algo para mejorar este código.

Es un código muy largo, pero sobre todo, muy repetitivo.
Fíjate que lo que hacemos es repetir 8 veces el mismo patrón de búsqueda, solo varía ligeramente en que aplicamos sumas y/o restas a unos índices o a otros.

Cuando un programa repite tantas veces un código que es prácticamente lo mismo, seguramente existe una forma de poder simplificarlo y evitar tantas repeticiones.
Solo hace falta un poco de imaginación para encontrar la forma de simplificarlo.


Lo que podemos hacer es escribir un segundo método al que por argumentos, podamos decirle en que dirección ha de dirigir la búsqueda.
Podemos usar dos enteros con los que sepa a que índice tiene que hacer suma, o resta, o no hacer nada.

Este podría ser el método, fíjate en la parte que marco en negrita
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
private static boolean buscarDireccion(char[][] sopa, String pal, int i, int j, int dI, int dJ) {
		boolean encontrado = true;
		try {
			for (int d = 1; d < pal.length(); d++) {
				if (pal.charAt(d) == sopa[i + (d * dI)][j + (d * dJ)])
					encontrado = true;
				else {
					encontrado = false;
					break;
				}
			}
		} catch(ArrayIndexOutOfBoundsException ex) {
			encontrado = false;
		}
 
		return encontrado;
	}
}

Aquí a los índices (que también han de llegar por argumentos) siempre les aplicamos una suma, pero les estamos sumando el resultado de un producto.
Este producto se calcula según el índice de la palabra y unos enteros que llegan como argumentos, llamados dI y dJ.

Estos enteros indican la "dirección" a la que han de ir los indices i y j.
Y pueden tener tres posibles valores: 1, -1 y 0

Si queremos que la i avance (vertical hacia abajo), lo que haremos será multiplicar el índice de la palabra por 1, y así tendremos una suma positiva.

Si queremos que la i retroceda (vertical hacia arriba), multiplicaremos por -1 para tener una suma negativa, es decir, una resta.

Y si queremos que la i no se mueva (busquedas en horizontal) entonces multiplicamos por 0, para así anular el valor del índice de la palabra y así no habrá ningún recorrido en vertical.

De esta forma, el método anterior que nos había quedado tan grande y largo, ahora se reduce a solo esto:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
private static boolean buscarEnSopa(char[][] sopa, String pal) {
 
		for (int i = 0; i < sopa.length; i++) {
			for (int j = 0; j < sopa[i].length; j++) {
				if (sopa[i][j] == pal.charAt(0)) {
 
					if (buscarDireccion(sopa, pal, i, j, 0, 1)) //Horizontal hacia adelante
						return true;
					if (buscarDireccion(sopa, pal, i, j, 0, -1)) //Horizontal hacia atrás
						return true;
					if (buscarDireccion(sopa, pal, i, j, 1, 0)) //Vertical hacia abajo
						return true;
					if (buscarDireccion(sopa, pal, i, j, -1, 0)) //Vertical hacia arriba
						return true;
					if (buscarDireccion(sopa, pal, i, j, -1, 1)) //Diagonal superior derecha
						return true;
					if (buscarDireccion(sopa, pal, i, j, -1, -1)) //Diagonal superior izquierda
						return true;
					if (buscarDireccion(sopa, pal, i, j, 1, 1)) //Diagonal inferior derecha
						return true;
					if (buscarDireccion(sopa, pal, i, j, 1, -1)) //Diagonal inferior izquierda
						return true;
				}
			}
		}
		//Palabra no ha sido encontrada en ninguna dirección
		return false;
	}

Fíjate como con un único método, podemos hacer búsquedas en las 8 direcciones simplemente indicándole con 0, 1 y -1 hacia dónde ha de dirigir la búsqueda.

Esto hace que el programa final, quede mucho más reducido, y eso que estamos aplicando exactamente la misma lógica que en la primera versión.
Pero un poco de imaginación y aplicando matemáticas básicas ( ¡¡tan solo multiplicar por 1 y 0!! (⊙_☉) ) conseguimos un código más compacto y óptimo.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
public class SopaLetras {
 
	public static void main(String[] args) {
 
		char[][] sopa = new char[][] {
			{'S','S','D','Z','F'},
			{'F','G','U','Y','T'},
			{'H','L','F','R','T'},
			{'E','E','E','E','E'},
			{'G','E','T','Y','U'},
			{'Ñ','P','O','J','Y'}
		};
 
		String palabra = "LUZ";
 
		System.out.println("\tSOPA DE LETRAS");
		System.out.println("\t---- -- ------\n");
		for (char[] fila: sopa)
			System.out.println("\t" + Arrays.toString(fila));
 
		System.out.println("\nPalabra a buscar: " + palabra);
 
		System.out.println(buscarEnSopa(sopa, palabra)?"Encontrada":"No encontrada");
	}
 
	private static boolean buscarEnSopa(char[][] sopa, String pal) {
 
		for (int i = 0; i < sopa.length; i++) {
			for (int j = 0; j < sopa[i].length; j++) {
				if (sopa[i][j] == pal.charAt(0)) {
 
					if (buscarDireccion(sopa, pal, i, j, 0, 1)) //Horizontal hacia adelante
						return true;
					if (buscarDireccion(sopa, pal, i, j, 0, -1)) //Horizontal hacia atrás
						return true;
					if (buscarDireccion(sopa, pal, i, j, 1, 0)) //Vertical hacia abajo
						return true;
					if (buscarDireccion(sopa, pal, i, j, -1, 0)) //Vertical hacia arriba
						return true;
					if (buscarDireccion(sopa, pal, i, j, -1, 1)) //Diagonal superior derecha
						return true;
					if (buscarDireccion(sopa, pal, i, j, -1, -1)) //Diagonal superior izquierda
						return true;
					if (buscarDireccion(sopa, pal, i, j, 1, 1)) //Diagonal inferior derecha
						return true;
					if (buscarDireccion(sopa, pal, i, j, 1, -1)) //Diagonal inferior izquierda
						return true;
				}
			}
		}
		//Palabra no ha sido encontrada en ninguna dirección
		return false;
	}
 
 
	private static boolean buscarDireccion(char[][] sopa, String pal, int i, int j, int dI, int dJ) {
		boolean encontrado = true;
		try {
			for (int d = 1; d < pal.length(); d++) {
				if (pal.charAt(d) == sopa[i + (d * dI)][j + (d * dJ)])
					encontrado = true;
				else {
					encontrado = false;
					break;
				}
			}
		} catch(ArrayIndexOutOfBoundsException ex) {
			encontrado = false;
		}
 
		return encontrado;
	}
}


Espero que se hayan entendido las explicaciones.
Sobre todo, antes de intentar entender el código "compactado", centra esfuerzos en el primer código que aunque sea más grande, posiblemente sea más fácil para entender la lógica del programa.


Un saludo.
Valora esta respuesta
Me gusta: Está respuesta es útil y esta claraNo me gusta: Está respuesta no esta clara o no es útil
0
Comentar

Ayuda con ejercicio

Publicado por Luis (3 intervenciones) el 11/09/2022 22:50:49
Buenas, muchisimas gracias por la explicacion!

Puede ser que en el caso de que la matriz sea cuadrada no lee entera la diagonal principal?

Para los demas casos funciona a la perfeccion!
Valora esta respuesta
Me gusta: Está respuesta es útil y esta claraNo me gusta: Está respuesta no esta clara o no es útil
0
Comentar
Imágen de perfil de Kabuto
Val: 3.428
Oro
Ha mantenido su posición en Java (en relación al último mes)
Gráfica de Java

Ayuda con ejercicio

Publicado por Kabuto (1381 intervenciones) el 12/09/2022 17:19:56
Pues he probado a "cuadrar" la matriz (6x6) y usar como palabra una cadena que ocupe la diagonal entera, y en mi caso la ha leído bien y encontrado la palabra.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public static void main(String[] args) {
 
		char[][] sopa = new char[][] {
			{'S','S','D','Z','F','X'},
			{'F','G','U','Y','T','Y'},
			{'H','L','F','R','T','D'},
			{'E','E','E','E','E','A'},
			{'G','E','T','Y','U','O'},
			{'Ñ','P','O','J','Y','R'}
		};
 
		String palabra = "RUEFGS";
 
		System.out.println("\tSOPA DE LETRAS");
		System.out.println("\t---- -- ------\n");
		for (char[] fila: sopa)
			System.out.println("\t" + Arrays.toString(fila));
 
		System.out.println("\nPalabra a buscar: " + palabra);
 
		System.out.println(buscarEnSopa(sopa, palabra)?"Encontrada":"No encontrada");
	}

He hecho pruebas con ambas diagonales, y en ambos sentidos, y no me ha fallado.

¿Cómo es la matriz que estás usando tú?
Valora esta respuesta
Me gusta: Está respuesta es útil y esta claraNo me gusta: Está respuesta no esta clara o no es útil
0
Comentar