uned progiii practica v1
TRANSCRIPT
UNED
Ingeniería Técnica de sistemas Curso 2012/2013
Programación III Prácticas obligatorias
Realizado por: Alfonso Martín Murillo DNI: 11.820.406-Q e-mail: [email protected] Centro Asociado: Las Tablas
Teléfono móvil: 601058048
Programación III – Práctica Obligatoria 2012 -‐ 2013
Alfonso Martín Murillo ([email protected]) Página 2 de 2
INDICE Introducción ___________________________________________________________ 3
Entorno de desarrollo, trabajo y ejecución ___________________________________ 3
Contenido del ZIP y ejecución de la aplicación ________________________________ 3
Respuesta a las cuestiones planteadas en el enunciado de la práctica ____________ 4
Descripción del algoritmo utilizado y aplicación en el problema _____________________ 4 Representación de los datos del problema ____________________________________________ 4 Recorrido en profundidad, recorrido en anchura y vuelta atrás ____________________________ 6 Estructuras de Datos ______________________________________________________________ 7 Particularizar el esquema de vuelta atrás _____________________________________________ 8
Coste computacional de la práctica ____________________________________________ 9
Análisis de alternativas al esquema utilizado ____________________________________ 9
Datos de prueba utilizados y resultados obtenidos _______________________________ 11
Ejemplo de ejecución para distintos tamaños del problema ____________________ 12
Saltocaballo5x5.sh _________________________________________________________ 12
Saltocaballo6x6.sh _________________________________________________________ 13
Saltocaballo7x7.sh _________________________________________________________ 15
Listado de código fuente completo ________________________________________ 15
SaltoCaballo.JAVA _________________________________________________________ 15
EstadoPartida.JAVA ________________________________________________________ 19
Programación III – Práctica Obligatoria 2012 -‐ 2013
Alfonso Martín Murillo ([email protected]) Página 3 de 3
Introducción Este documento representa la memoria a elaborar en la práctica de Programación III de la carrera de “Ingeniería de Sistemas”.
Entorno de desarrollo, trabajo y ejecución Los datos de ejecución mostrados en esta memoria, así como el código desarrollado y la elaboración de la memoria se han realizado sobre un ordenador MACBOOK PRO INTEL CORE 2 DUO 2,4 GHZ modelo 2008, con 4 GB de memoria RAM.
Contenido del ZIP y ejecución de la aplicación El contenido de la práctica se encuentra empaquetado en un fichero ZIP de nombre 11820406.zip. A continuación se detalla el contenido de dicho fichero:
SaltoCaballo.jar Fichero JAR para la ejecución del programa. Dentro del fichero JAR se encuentran dos clases java, EstadoPartida.class y SaltoCaballo.class. SaltoCaballo.class contiene la función main a la que invoca el programa
UNED-‐PROGIII-‐Practica-‐v01.pdf Documento PDF que representa la memoria asociada a la práctica Directorio SRC Directorio donde están alojados los 2 ficheros fuentes JAVA.
EstadoPartida.java y SaltoCaballo.java. Directorio Output En el proceso de comprobación del programa se han ido
elaborando ficheros de salida de diferentes ejecuciones. Se adjuntan soluciones para tableros 5x5, 6x6 y 7x7.
Ejecución del programa
Para ejecutar el programa se deben de seguir los siguientes pasos:
1. Acceder al terminal (UNIX o MAC) o consola (Windows). Situarse en el directorio raiz generado por el proceso de descompresión del fichero ZIP.
2. Ejecutar desde la línea de comandos la sentencia JAVA –JAR SaltoCaballo.jar estableciendo los parámetros establecidos en el enunciado de la práctica. A continuación se establecen a modo de ejemplo unas cuantas ejecuciones que ilustran el tratamiento de los parámetros:
Java –jar SaltoCaballo.jar –n 6 Ejecución del programa para un tablero de 6x6 con las coordenadas de inicio por defecto (x=1, y=1)
Java –jar SaltoCaballo.jar –n 6 –x 2 –y 2 Ejecución del programa para un tablero de 6x6 estableciendo las coordenadas de inicio (x=2, y=2).
Java –jar SaltoCaballo.jar –n 6 -‐t Ejecución del programa para un tablero de 6x6 invocando al modo traza, que va mostrando los diferentes estados por los que va pasando el tablero en su búsqueda de la solución.
Java –jar SaltoCaballo.jar –n 6 -‐a Ejecución del programa para un tablero de 6x6 y la obtención de todas las soluciones existentes desde las coordenadas de partida.
Java –jar SaltoCaballo.jar –n 6 –f output.txt (No solicitado). Para la realización de pruebas se ha implementado el parámetro –f, no obligatorio, y
Programación III – Práctica Obligatoria 2012 -‐ 2013
Alfonso Martín Murillo ([email protected]) Página 4 de 4
que permite establecer la salida a un fichero, en vez de por pantalla.
Respuesta a las cuestiones planteadas en el enunciado de la práctica
Descripción del algoritmo utilizado y aplicación en el problema A continuación se resumen los tres esquemas algorítmicos básicos, con el tipo de problema al cual se aplican.
Esquema algorítmico Aplicación Algoritmos voraces Construcción de una solución paso a paso, donde no es necesario
reconsiderar decisiones ya tomadas (no hay vuelta atrás). Divide y vencerás Abordar el problema como un conjunto de subproblemas mas pequeños,
a los cuales damos solución, y posteriormente combinamos dichas soluciones parciales para obtener la solución completa.
Exploración de grafos La información tratada por el problema está estructurada en forma de uno o mas grafos, y mediante estos algoritmos podemos recorrer de forma eficiente dichos grafos en busca de la solución.
Representación de los datos del problema Analizando el problema podemos identificar los siguientes componentes:
• Un tablero. Representado como una matriz cuadrada de N filas y N columnas. • Una posición de inicio. Unas coordenadas x e y de las cuales parte nuestro caballo. • Un conjunto de posibles movimientos o desplazamientos que puede hacer el caballo. • Un camino o ruta. El recorrido que realiza el caballo en su búsqueda para recorrer todas las
casillas del tablero.
La estructura que mas fielmente nos puede representar los caminos posibles o imposibles que realiza el caballo desde una posición de partida es un árbol. El nodo inicial correspondería a la situación de partida (Tablero, posición inicial, longitud actual del camino). Cada nodo tiene tantos hijos como posibles movimientos pueda hacer el caballo en el tablero.
Para ilustrar la estructura de árbol vamos a analizar un ejemplo sobre un tablero de 5x5 basado en una situación en la cual el caballo comienza en las coordenadas 1,1. Inicialmente la situación del tablero es que está ocupada la posición 1,1. Podríamos decir que tenemos una longitud de camino de 1.
Programación III – Práctica Obligatoria 2012 -‐ 2013
Alfonso Martín Murillo ([email protected]) Página 5 de 5
una vez analizadas las posibles posiciones a las que puede saltar el caballo nos encontraríamos con 2 hijos:
Es decir, existen dos posibles alternativas para obtener un camino de longitud 2. A su vez cada una de estas alternativas generan nuevos hijos y nuevos caminos alternativos.
Primera posibilidad de camino de longitud 3
Segunda posibilidad de camino de longitud 3
El árbol entero desplegado nos ofrecería la visión de todos los caminos posibles existentes.
Llegados a este punto tomamos nuestra primera decisión, utilizar algoritmos de exploración de grafos.
Programación III – Práctica Obligatoria 2012 -‐ 2013
Alfonso Martín Murillo ([email protected]) Página 6 de 6
Recorrido en profundidad, recorrido en anchura y vuelta atrás Una vez tomada la decisión de usar algoritmos de exploración de grafos tenemos varios esquemas con los que trabajar.
Tomando en cuenta el tamaño que puede tener el grafo, que en este caso es un árbol, podemos valorar si nos interesa construir o no el árbol.
Si tomamos en cuenta que cada nodo puede tener hasta 8 nodos hijos, partiendo de una determinada situación de partida nos encontramos que cada nivel del árbol puede tener el siguiente número teórico de nodos:
Nivel del arbol Número de nodos en el nivel
1 1
2 8
3 64
4 512
5 4.096
6 32.768
7 262.144
8 2.097.152
9 16.777.216
10 134.217.728
11 1.073.741.824
12 8.589.934.592
13 68.719.476.736
14 549.755.813.888
15 4.398.046.511.104
16 35.184.372.088.832
17 281.474.976.710.656
18 2.251.799.813.685.250
19 18.014.398.509.482.000
20 144.115.188.075.856.000
21 1.152.921.504.606.850.000
22 9.223.372.036.854.780.000
23 73.786.976.294.838.200.000
24 590.295.810.358.706.000.000
25 4.722.366.482.869.650.000.000
26 37.778.931.862.957.200.000.000
27 302.231.454.903.657.000.000.000
28 2.417.851.639.229.260.000.000.000
29 19.342.813.113.834.100.000.000.000
30 154.742.504.910.673.000.000.000.000
31 1.237.940.039.285.380.000.000.000.000
32 9.903.520.314.283.040.000.000.000.000
33 79.228.162.514.264.300.000.000.000.000
Programación III – Práctica Obligatoria 2012 -‐ 2013
Alfonso Martín Murillo ([email protected]) Página 7 de 7
34 633.825.300.114.115.000.000.000.000.000
35 5.070.602.400.912.920.000.000.000.000.000
36 40.564.819.207.303.300.000.000.000.000.000
37 324.518.553.658.427.000.000.000.000.000.000
38 2.596.148.429.267.410.000.000.000.000.000.000
39 20.769.187.434.139.300.000.000.000.000.000.000
40 166.153.499.473.114.000.000.000.000.000.000.000
41 1.329.227.995.784.920.000.000.000.000.000.000.000
42 10.633.823.966.279.300.000.000.000.000.000.000.000
43 85.070.591.730.234.600.000.000.000.000.000.000.000
44 680.564.733.841.877.000.000.000.000.000.000.000.000
45 5.444.517.870.735.020.000.000.000.000.000.000.000.000
46 43.556.142.965.880.100.000.000.000.000.000.000.000.000
47 348.449.143.727.041.000.000.000.000.000.000.000.000.000
48 2.787.593.149.816.330.000.000.000.000.000.000.000.000.000
49 22.300.745.198.530.600.000.000.000.000.000.000.000.000.000
El número obtenido correspondería al caso peor, ya que no siempre todas las posiciones son correctas, como hemos podido comprobar en el ejemplo partiendo de la posición 1,1, donde únicamente existen 2 posiciones válidas y no 8.
Se han marcado en verde los niveles 25, 36 y 49. Estos niveles corresponderían a los que sería necesario llegar en el caso de un tablero de longitud 5, 6 y 7 respectivamente. Como podemos comprobar el número de posibles nodos es tan grande que no nos podemos permitir construir el árbol de forma explícita para aplicar posteriormente técnicas de búsqueda.
Nuestra estrategia va a consistir trabajar con un grafo implícito, es decir, conocemos como tienen que ser los nodos, cual es la mecánica para ir generando nodos hijos, cuando hemos obtenido una solución, y por tanto vamos a aplicar un algoritmo de vuelta atrás.
El algoritmo de vuelta atrás se justifica ya que a medida que vamos recorriendo niveles hacia abajo, si llegamos a un punto en el cual no obtenemos mas hijos, pero la longitud del camino no corresponde con el número de casillas del tablero, deberemos de corregir la situación, volviendo hacia atrás en nuestro recorrido y probando un nuevo camino.
Estructuras de Datos Necesitamos manejar los siguientes elementos:
• dimTablero. La dimensión que va a tener el tablero. • Tablero[][]. Una matriz bidimensional que va a representar el tablero, con todas las
posiciones, en función de la dimensión establecida al inicio. • lCamino. La longitud del camino que está realizando el caballo en sus sucesivos
movimientos. • xActual. Posición x actual del caballo. • yActual. Posición y actual del caballo.
Programación III – Práctica Obligatoria 2012 -‐ 2013
Alfonso Martín Murillo ([email protected]) Página 8 de 8
• Xdesp e YDesp. Utilizamos 2 estructuras de datos de tipo vector o array unidimensional para almacenar los 8 posibles movimientos que un caballo puede recorrer en un tablero de ajedrez. A continuación se exponen los valores de dichos vectores, que se corresponden con los diferentes movimientos del caballo.
xDesp=new int[8]
yDesp=new int[8]
xDesp[0]=2;xDesp[1]=1;xDesp[2]=2;xDesp[3]=1;xDesp[4]=2;xDesp[5]=1;xDesp[6]=2;xDesp[7]=1
yDesp[0]=1;yDesp[1]=2;yDesp[2]=1;yDesp[3]=2;yDesp[4]=1;yDesp[5]=2;yDesp[6]=1;yDesp[7]=2
Particularizar el esquema de vuelta atrás A continuación se expone el esquema general de vuelta atrás:
Fun vuelta-‐atrás (ensayo) Si válido (ensayo) entonces Dev ensayo Si no Para cada hijo E compleciones (ensayo) Si condicionesdepoda (hijo) entonces vuelta-‐atrás (hijo) Fin para Fin si Fin Fun
Un algoritmo de vuelta atrás acaba bien por haber encontrado la solución, o bien porque no hay mas nodos hijos a explorar. En la siguiente tabla se particularizan cada uno de los componentes del esquema algorítmico en relación a nuestro problema concreto.:
Componente Particularización Valido(ensayo) Esta función nos valida si hemos encontrado una solución. En este caso si la
longitud del camino recorrido es igual al cuadrado de la dimensión del tablero.
Fun Valido (Ensayo)
Dev (ensayo.lcamino==dimtablero*dimtablero
ffun
Compleciones(ensayo) Esta función nos obtiene la lista de nodos hijos (siguientes casillas) que cumplen las reglas del juego. Fun compleciones (ensayo) Lista <-‐ lista vacía; Para x de 0 a 7 hacer Despx=ensayo.xactual+xdesp[x] Despy=ensayo.yactual+ydesp[x] Si (despx > 0) y despx<=ensayo.dimtablero
Programación III – Práctica Obligatoria 2012 -‐ 2013
Alfonso Martín Murillo ([email protected]) Página 9 de 9
Y (despy > 0) y despy<=ensayo.dimtablero y ensayo.tablero[despx][despy]=0 entonces nuevo-‐Ensayo <-‐ Ensayo nuevo-‐Ensayo.lcamino=nuevo-‐ensayo.lcamino+1; nuevo-‐Ensayo.xactual=Despx; nuevo-‐Ensayo.yactual=Despy; nuevo-‐Ensayo.tablero <-‐ensayo.tablero nuevo-‐Ensayo.Tablero[despx][despy]=ensayo.lcamino+1 lista <-‐ añadir (lista, nuevo-‐ensayo); Fsi fpara Ffun
Condicionesdepoda (hijo) Únicamente vamos a generar nodos hijos que representen casillas alcanzables, por lo tanto no hay ninguna condición de poda que añadir.
No se ha entrado en cuestiones mas operativas del programa, como puedan ser el paso de parámetros a la aplicación, la impresión en pantalla, control de trazas y demás cuestiones que son reflejadas en el código fuente de la aplicación y en los comentarios anexos.
Coste computacional de la práctica Lo que vamos a ofrecer es una cota superior al tamaño de la búsqueda.
Si nos fijamos en la tabla que se ha elaborado con los hijos obtenidos en cada uno de los niveles, podemos ver que crece en el orden de 8.
El coste del algoritmo es exponencial, siendo del orden 𝟖𝒏𝟐 .
Como podemos observar en la tabla de hijos, para tamaños pequeños de N (5, 6) hemos observado que los tiempos son asumibles. Hasta n=7 los tiempos son mas o menos aceptables, pero a partir de N=8 el coste se dispara de forma espectacular, en concordancia con el número de hijos que lógicamente se deben de evaluar, para un árbol de 49 niveles con 8 posibles ramificaciones en cada nivel.
Análisis de alternativas al esquema utilizado En este epígrafe vamos a realizar un repaso del resto de esquemas algorítmicos que se ven en la asignatura para justificar el porqué no son idóneos para el problema que se plantea.
Esquema voraz
Programación III – Práctica Obligatoria 2012 -‐ 2013
Alfonso Martín Murillo ([email protected]) Página 10 de 10
• Este esquema construye paso a paso la solución sin
necesidad de reconsiderar decisiones ya tomadas. Esto no aplica en nuestro problema, ya que a la hora de construir un camino debemos tener la posibilidad de “corregir” nuestra dirección cuando nos encontremos con un camino sin retorno.
• Otro problema que nos encontramos es la función
Seleccionar, que escoge el candidato mas prometedor. En nuestro caso sería “complicado” decidir cual es el candidato mas prometedor, ya que lo que nos puede parecer “prometedor” en el estado 3 o 4 de nuestra partida puede no serlo tanto en un estado posterior.
• Cuando se incorporar un candidato a la solución, o
bien se rechaza, son decisiones que se mantienen hasta el final. En nuestro caso necesitamos la posibilidad de corregir nuestra situación.
Divide y Vencerás
No es factible construir una solución mediante la aplicación a subproblemas mas pequeños.
Recorrido en profundidad
Debemos de marcar todos los nodos del grafo como “no visitados”, por lo que debemos previamente disponer del grafo. Tal como hemos dicho, vamos a trabajar con un grafo implícito, que se va a construir a medida que se va construyendo la solución, por lo que no podemos aplicar un algoritmo de Recorrido en Profundidad. Lo que si utilizamos es el concepto de que a la hora de recorrer el grafo primero recorremos a nivel hijo, y luego el resto de nodos adyacentes, es decir, buscamos la profundidad, ya que llegar a una solución significa llegar al nivel mas profundo del árbol.
Programación III – Práctica Obligatoria 2012 -‐ 2013
Alfonso Martín Murillo ([email protected]) Página 11 de 11
Recorrido en Anchura
En un recorrido en anchura el orden de visita es diferente. Cuando se llega a un nodo N se visitan en primer lugar todos los vecinos de N. No nos interesa aplicar este esquema algorítmico, ya que nuestra solución se basa en llegar lo antes posible al último nivel (mas profundo) del árbol.
Datos de prueba utilizados y resultados obtenidos Se han realizado pruebas exhaustivas para los siguientes tamaños de tableros, obteniendo los siguientes resultados:
Tamaño Observaciones N=5 Primera solución
Para ejecuciones de búsqueda de la primera solución, los resultados han sido instantáneos para cualquier casilla inicial, tanto encontrando una solución como no encontrando ninguna, con tiempos inferiores al segundo. Todas las soluciones (parámetro –a) Resultados instantáneos para cualquier casilla inicial. Es de destacar que el algoritmo no encuentra soluciones para casillas iniciales cuya suma de la posición x con la posición y sea impar, p.ej x=1, y=2.
N=6 Primera solución
Programación III – Práctica Obligatoria 2012 -‐ 2013
Alfonso Martín Murillo ([email protected]) Página 12 de 12
Para ejecuciones de búsqueda de la primera solución, los resultados han sido instantáneos para cualquier casilla inicial, con tiempos inferiores al segundo. Todas las soluciones (parámetro –a) En el caso de la casilla inicial 1,1 el algoritmo encuentra mas de 500.000 soluciones en un tiempo inferior a 2 horas. Es decir, en menos de 2 horas encuentra todas las soluciones para una configuración de casilla inicial que se le indique.
N=7 Primera solución Para ejecuciones de búsqueda de la primera solución, los resultados han sido instantáneos para algunas casillas iniciales, como 1-‐1 pero tardando horas en otros casos. Todas las soluciones (parámetro –a) La obtención de soluciones se demora a horas y horas.
N=8 Primera solución Para ejecuciones de búsqueda de la primera solución, el ordenador debe trabajar mas de 1 día, para la configuración de casilla inicial 1-‐1. Todas las soluciones (parámetro –a) La obtención de soluciones se demora a días y días.
Ejemplo de ejecución para distintos tamaños del problema Para el análisis y ejecución en bloque de pruebas he elaborado unos scripts UNIX (sh) que me permiten ejecutar de forma secuencial el algoritmo, y obtener ficheros con los resultados obtenidos. Para ello se ha implementado el parámetro –f (no solicitado) , que permite redirigir la salida a un fichero de texto.
Saltocaballo5x5.sh #SCRIPT PARA EJECUTAR
java SaltoCaballo -‐n 5 -‐x 1 -‐y 1 -‐f 5x5-‐1_1.txt
java SaltoCaballo -‐n 5 -‐x 1 -‐y 2 -‐f 5x5-‐1_2.txt
java SaltoCaballo -‐n 5 -‐x 1 -‐y 3 -‐f 5x5-‐1_3.txt
java SaltoCaballo -‐n 5 -‐x 1 -‐y 4 -‐f 5x5-‐1_4.txt
java SaltoCaballo -‐n 5 -‐x 1 -‐y 5 -‐f 5x5-‐1_5.txt
Programación III – Práctica Obligatoria 2012 -‐ 2013
Alfonso Martín Murillo ([email protected]) Página 13 de 13
java SaltoCaballo -‐n 5 -‐x 2 -‐y 1 -‐f 5x5-‐2_1.txt
java SaltoCaballo -‐n 5 -‐x 2 -‐y 2 -‐f 5x5-‐2_2.txt
java SaltoCaballo -‐n 5 -‐x 2 -‐y 3 -‐f 5x5-‐2_3.txt
java SaltoCaballo -‐n 5 -‐x 2 -‐y 4 -‐f 5x5-‐2_4.txt
java SaltoCaballo -‐n 5 -‐x 2 -‐y 5 -‐f 5x5-‐2_5.txt
java SaltoCaballo -‐n 5 -‐x 3 -‐y 1 -‐f 5x5-‐3_1.txt
java SaltoCaballo -‐n 5 -‐x 3 -‐y 2 -‐f 5x5-‐3_2.txt
java SaltoCaballo -‐n 5 -‐x 3 -‐y 3 -‐f 5x5-‐3_3.txt
java SaltoCaballo -‐n 5 -‐x 3 -‐y 4 -‐f 5x5-‐3_4.txt
java SaltoCaballo -‐n 5 -‐x 3 -‐y 5 -‐f 5x5-‐3_5.txt
java SaltoCaballo -‐n 5 -‐x 4 -‐y 1 -‐f 5x5-‐4_1.txt
java SaltoCaballo -‐n 5 -‐x 4 -‐y 2 -‐f 5x5-‐4_2.txt
java SaltoCaballo -‐n 5 -‐x 4 -‐y 3 -‐f 5x5-‐4_3.txt
java SaltoCaballo -‐n 5 -‐x 4 -‐y 4 -‐f 5x5-‐4_4.txt
java SaltoCaballo -‐n 5 -‐x 4 -‐y 5 -‐f 5x5-‐4_5.txt
java SaltoCaballo -‐n 5 -‐x 5 -‐y 1 -‐f 5x5-‐5_1.txt
java SaltoCaballo -‐n 5 -‐x 5 -‐y 2 -‐f 5x5-‐5_2.txt
java SaltoCaballo -‐n 5 -‐x 5 -‐y 3 -‐f 5x5-‐5_3.txt
java SaltoCaballo -‐n 5 -‐x 5 -‐y 4 -‐f 5x5-‐5_4.txt
java SaltoCaballo -‐n 5 -‐x 5 -‐y 5 -‐f 5x5-‐5_5.txt
Saltocaballo6x6.sh #SCRIPT PARA EJECUTAR
java SaltoCaballo -‐n 6 -‐x 1 -‐y 1 -‐f 6x6-‐1_1.txt
java SaltoCaballo -‐n 6 -‐x 1 -‐y 2 -‐f 6x6-‐1_2.txt
java SaltoCaballo -‐n 6 -‐x 1 -‐y 3 -‐f 6x6-‐1_3.txt
java SaltoCaballo -‐n 6 -‐x 1 -‐y 4 -‐f 6x6-‐1_4.txt
Programación III – Práctica Obligatoria 2012 -‐ 2013
Alfonso Martín Murillo ([email protected]) Página 14 de 14
java SaltoCaballo -‐n 6 -‐x 1 -‐y 5 -‐f 6x6-‐1_5.txt
java SaltoCaballo -‐n 6 -‐x 1 -‐y 6 -‐f 6x6-‐1_6.txt
java SaltoCaballo -‐n 6 -‐x 2 -‐y 1 -‐f 6x6-‐2_1.txt
java SaltoCaballo -‐n 6 -‐x 2 -‐y 2 -‐f 6x6-‐2_2.txt
java SaltoCaballo -‐n 6 -‐x 2 -‐y 3 -‐f 6x6-‐2_3.txt
java SaltoCaballo -‐n 6 -‐x 2 -‐y 4 -‐f 6x6-‐2_4.txt
java SaltoCaballo -‐n 6 -‐x 2 -‐y 5 -‐f 6x6-‐2_5.txt
java SaltoCaballo -‐n 6 -‐x 2 -‐y 6 -‐f 6x6-‐2_6.txt
java SaltoCaballo -‐n 6 -‐x 3 -‐y 1 -‐f 6x6-‐3_1.txt
java SaltoCaballo -‐n 6 -‐x 3 -‐y 2 -‐f 6x6-‐3_2.txt
java SaltoCaballo -‐n 6 -‐x 3 -‐y 3 -‐f 6x6-‐3_3.txt
java SaltoCaballo -‐n 6 -‐x 3 -‐y 4 -‐f 6x6-‐3_4.txt
java SaltoCaballo -‐n 6 -‐x 3 -‐y 5 -‐f 6x6-‐3_5.txt
java SaltoCaballo -‐n 6 -‐x 3 -‐y 6 -‐f 6x6-‐3_6.txt
java SaltoCaballo -‐n 6 -‐x 4 -‐y 1 -‐f 6x6-‐4_1.txt
java SaltoCaballo -‐n 6 -‐x 4 -‐y 2 -‐f 6x6-‐4_2.txt
java SaltoCaballo -‐n 6 -‐x 4 -‐y 3 -‐f 6x6-‐4_3.txt
java SaltoCaballo -‐n 6 -‐x 4 -‐y 4 -‐f 6x6-‐4_4.txt
java SaltoCaballo -‐n 6 -‐x 4 -‐y 5 -‐f 6x6-‐4_5.txt
java SaltoCaballo -‐n 6 -‐x 4 -‐y 6 -‐f 6x6-‐4_6.txt
java SaltoCaballo -‐n 6 -‐x 5 -‐y 1 -‐f 6x6-‐5_1.txt
java SaltoCaballo -‐n 6 -‐x 5 -‐y 2 -‐f 6x6-‐5_2.txt
java SaltoCaballo -‐n 6 -‐x 5 -‐y 3 -‐f 6x6-‐5_3.txt
java SaltoCaballo -‐n 6 -‐x 5 -‐y 4 -‐f 6x6-‐5_4.txt
java SaltoCaballo -‐n 6 -‐x 5 -‐y 5 -‐f 6x6-‐5_5.txt
java SaltoCaballo -‐n 6 -‐x 5 -‐y 6 -‐f 6x6-‐5_6.txt
java SaltoCaballo -‐n 6 -‐x 6 -‐y 1 -‐f 6x6-‐6_1.txt
Programación III – Práctica Obligatoria 2012 -‐ 2013
Alfonso Martín Murillo ([email protected]) Página 15 de 15
java SaltoCaballo -‐n 6 -‐x 6 -‐y 2 -‐f 6x6-‐6_2.txt
java SaltoCaballo -‐n 6 -‐x 6 -‐y 3 -‐f 6x6-‐6_3.txt
java SaltoCaballo -‐n 6 -‐x 6 -‐y 4 -‐f 6x6-‐6_4.txt
java SaltoCaballo -‐n 6 -‐x 6 -‐y 5 -‐f 6x6-‐6_5.txt
java SaltoCaballo -‐n 6 -‐x 6 -‐y 6 -‐f 6x6-‐6_6.txt
Saltocaballo7x7.sh Debido al tiempo de proceso que supone la ejecución de cada prueba únicamente se han generado 7 casos de prueba.
#SCRIPT PARA EJECUTAR
java SaltoCaballo -‐n 7 -‐x 1 -‐y 1 -‐f 7x7-‐1_1.txt
java SaltoCaballo -‐n 7 -‐x 1 -‐y 2 -‐f 7x7-‐1_2.txt
java SaltoCaballo -‐n 7 -‐x 1 -‐y 3 -‐f 7x7-‐1_3.txt
java SaltoCaballo -‐n 7 -‐x 1 -‐y 4 -‐f 7x7-‐1_4.txt
java SaltoCaballo -‐n 7 -‐x 1 -‐y 5 -‐f 7x7-‐1_5.txt
java SaltoCaballo -‐n 7 -‐x 1 -‐y 6 -‐f 7x7-‐1_6.txt
java SaltoCaballo -‐n 7 -‐x 1 -‐y 7 -‐f 7x7-‐1_7.txt
La salida de los diferentes casos de prueba pueden encontrarse en el directorio OUTPUT. Debido a la cantidad de información generada me ha parecido mas adecuado mantener en ficheros separados los resultados de las pruebas, en vez de incorporarlos a este documento.
Listado de código fuente completo El software lo conforman 2 ficheros fuentes, SaltoCaballo.java y EstadoPartida.Java.
• SaltoCaballo.JAVA. Contiene la función MAIN principal y el control y evaluación de parámetros de entrada.
• EstadoPartida.JAVA. Contiene la función de BackTracking y de pintado de Tablero.
SaltoCaballo.JAVA
//PAQUETES JAVA UTILIZADOS import java.io.*; import java.util.Date;;
Programación III – Práctica Obligatoria 2012 -‐ 2013
Alfonso Martín Murillo ([email protected]) Página 16 de 16
public class SaltoCaballo { //LISTA DE VARIABLES UTILIZADAS static Integer N; //Dimensión del tablero de Ajedrez. static Integer xInicio; //Posición x inicial static Integer yInicio; //Posición y inicial static Boolean modoTraza; //Establece si tenemos que imprimir todos los estados por los que pasa el tablero. static Boolean modoTodasSoluciones; //Establece si debemos de obtener todas las soluciones o únicamente la primera. static String nomFicheroSalida; //DE USO INTERNO PARA LA OBTENCIÓN DE FICHEROS DE SALIDA static int paramSalida; //Otras variables static PrintStream miConsola; //TODO Limpiar y Comentar public static void main(String[] args) throws UnsupportedEncodingException, FileNotFoundException { //variables temporales //CONFIGURACIONES POR DEFECTO DE LA APLICACIÓN N=8; xInicio=1; yInicio=1; modoTraza=false; modoTodasSoluciones=false; nomFicheroSalida=new String("salida.txt"); paramSalida=0; //POR DEFECTO LA SALIDA ES POR CONSOLA. 0 - CONSOLA 1 - FICHERO. //OBJETO FECHAHORA PARA IR GRABANDO LOS EVENTOS DE LA APLICACIÓN Date fechaHora=new Date(); // 1 - Evaluar que los parámetros enviados son los correctos. if (evalParametros(args)==false) { System.out.println("Los parametros suministrados no son correctos"); System.out.println("El programa finalizará su ejecución"); System.exit(0); }
Programación III – Práctica Obligatoria 2012 -‐ 2013
Alfonso Martín Murillo ([email protected]) Página 17 de 17
//CONFIGURACIÓN DE CONSOLA DE SALIDA if (paramSalida==0) { miConsola=new PrintStream(System.out,true,"UTF-8"); } else { File file = new File(nomFicheroSalida); FileOutputStream fos = new FileOutputStream(file); miConsola=new PrintStream(fos,true,"UTF-8"); } //CREACIÓN DE LA PARTIDA //listaSoluciones= new ArrayList<EstadoPartida>(); //COMIENZA MI PARTIDA EstadoPartida estadoInicial=new EstadoPartida(xInicio,yInicio,N,modoTraza,modoTodasSoluciones,miConsola); miConsola.println(fechaHora.toString() + " Inicio del Proceso de generación de soluciones: "); estadoInicial.evalPartida(); //MUESTRO UN MENSAJE EN AQUELLAS SITUACIONES EN LAS QUE NBO SE ENCUENTRE SOLUCIÓN if (estadoInicial.esSolucion==false) miConsola.println("No se ha encontrado un camino que satisfaga las condiciones de partida"); miConsola.println(fechaHora.toString() + " Finalización del Proceso de generación de soluciones"); //FINALIZACIÓN DEL PROGRAMA } public static Boolean evalParametros(String[] args) { //FIXME -n 5 -x 3 y 3 no funciona. controlarlo. //FIXME -p 5 -x 3 y 3 no funciona. controlarlo. //VARIABLES TEMPORALES int x=0; //RECORREMOS EL ARRAY DE PARÁMETROS Y EVALUAMOS try { //RECORRIDO DEL TOTAL DE PARÁMETROS INCORPORADOS while (x<args.length)
Programación III – Práctica Obligatoria 2012 -‐ 2013
Alfonso Martín Murillo ([email protected]) Página 18 de 18
{ //SI CAPTO -N LEO LA SIGUIENTE POSICIÓN QUE DEBE DE SER NUMÉRICA. EN CASO CONTRARIO SE OBTENDRÁ UNA EXCEPCIÓN if (args[x].toString().toLowerCase().equals("-n")) //CAPTO LA DIMENSIÓN DEL TABLERO QUE SERÁ LA SIGUIENTE POSICIÓN { N=Integer.parseInt(args[x+1]); x++; } else { if (args[x].toString().toLowerCase().equals("-x")) //CAPTO LA X { xInicio=Integer.parseInt(args[x+1]); x++; } else { if (args[x].toString().toLowerCase().equals("-y")) //CAPTO LA y { yInicio=Integer.parseInt(args[x+1]); x++; } else { //OBTENDO SI TRABAJO O NO EN MODO TRAZA if (args[x].toString().toLowerCase().equals("-t")) modoTraza=true; else { //OBTENGO SI DESEO TODAS LAS SOLUCIONES O NO if (args[x].toString().toLowerCase().equals("-a")) modoTodasSoluciones=true; else { if (args[x].toString().toLowerCase().equals("-f")) //CAPTO EL NOMBRE DEL FICHERO { paramSalida=1; //DESEO LA SALIDA POR FICHERO
Programación III – Práctica Obligatoria 2012 -‐ 2013
Alfonso Martín Murillo ([email protected]) Página 19 de 19
nomFicheroSalida=args[x+1]; x++; } } } } } } x++; } //SALIDA CORRECTA return true; } catch(Exception miExcepcion) { //SALIDA INCORRECTA return false; //ha habido algún tipo de error, por lo que debemos devolver false } } }
EstadoPartida.JAVA
import java.io.FileNotFoundException; import java.io.PrintStream; import java.io.UnsupportedEncodingException; public class EstadoPartida {
Programación III – Práctica Obligatoria 2012 -‐ 2013
Alfonso Martín Murillo ([email protected]) Página 20 de 20
//PROPIEDADES PÚBLICAS DE LA CLASE public int Tablero[][]; //MATRIZ BIDIMENSIONAL QUE REPRESENTA EL TABLERO public int lCamino;//LONGITUD DEL CAMINO. public int xActual; //POSICIÓN X EN LA QUE NOS ENCONTRAMOS public int yActual; //POSICIÓN Y EN LA QUE NOS ENCONTRAMOS public boolean modoTraza; public long numTrazas; //PARA CONOCER EL NÚMERO DE EVALUACIONES QUE LLEVAMOS REALIZADAS public boolean modotodasSoluciones; public int dimTablero; //INDICA LA DIMENSIÓN DEL TABLERO COMENZANDO POR 1 public int dimTableroidx0;//INDICA LA DIMENSIÓN DEL TABLERO COMENZANDO POR 0 public boolean esSolucion; //VARIABLE BOOLEANA QUE INDICA SI HEMOS OBTENIDO COMO MÍNIMO UNA SOLUCIÓN. public PrintStream miConsola; //VARIABLE QUE REPRESENTA LA CONSOLA DE SALIDA public int xDesp[]; //VECTOR QUE ALMACENA LOS POSIBLES DESPLAZAMIENTOS POR EL EJE X public int yDesp[]; //VECTOR QUE ALMACENA LOS POSIBLES DESPLAZAMIENTOS POR EL EJE Y public int numSoluciones; //VARIABLE QUE ALMACENA EL NÚMERO DE SOLUCIONES OBTENIDAS public int dimTableroQ2; //PARA QUE NO TENGA QUE HACER LA MULTIPLICACIÓN EN CADA LLAMADA RECURSIVA //CONSTRUCTOR POR DEFECTO. public EstadoPartida() { try { initEstadoPartida(); } catch (UnsupportedEncodingException exc) { System.out.println(exc.toString()); } catch (FileNotFoundException exc) { System.out.println(exc.toString()); } } //CONSTRUCTOR DE LA CLASE DE TIPO ESTADOPARTIDA EN BASE A
Programación III – Práctica Obligatoria 2012 -‐ 2013
Alfonso Martín Murillo ([email protected]) Página 21 de 21
PARÁMETROS NECESARIOS public EstadoPartida(int xIni,int yIni, int dim, Boolean mTraza, Boolean tSoluciones,PrintStream miConsola) { //VARIABLES TEMPORALES //CUERPO //CONVERSIÓN DE COORDENADAS A ÍNDICE 0 xActual=xIni-1; //Posición x de partida. Resto -1 para adaptarlo a matriz con índice que empieza en 0. yActual=yIni-1; //Posición y de partida. Resto -1 para adaptarlo a matriz con índice que empieza en 0. modoTraza=mTraza; modotodasSoluciones=tSoluciones; this.miConsola=miConsola; Tablero=new int[dim][dim]; //Creación de la matriz que representa el tablero; //Establezco la primera posición del caballo en el tablero Tablero[xActual][yActual]=1; dimTablero=dim; //Establezco la dimensión del Tablero lCamino=1; //llamada al constructor por defecto try { initEstadoPartida(); } catch (UnsupportedEncodingException exc) { miConsola.println(exc.toString()); } catch (FileNotFoundException exc) { miConsola.println(exc.toString()); } } //Función que focaliza todo lo común a los diferentes constructores public void initEstadoPartida() throws UnsupportedEncodingException, FileNotFoundException { //Función que focaliza todo lo común a los diferentes constructores esSolucion=false; numSoluciones=0;
Programación III – Práctica Obligatoria 2012 -‐ 2013
Alfonso Martín Murillo ([email protected]) Página 22 de 22
numTrazas=0; xDesp=new int[8]; yDesp=new int[8]; xDesp[0]=-2;xDesp[1]=-1;xDesp[2]=-2;xDesp[3]=-1;xDesp[4]=2;xDesp[5]=1;xDesp[6]=2;xDesp[7]=1; yDesp[0]=-1;yDesp[1]=-2;yDesp[2]=1;yDesp[3]=2;yDesp[4]=-1;yDesp[5]=-2;yDesp[6]=1;yDesp[7]=2; dimTableroidx0=dimTablero-1; dimTableroQ2=dimTablero*dimTablero; } //FUNCIÓN PRINCIPAL DE CARACTER RECURSIVO QUE REALIZA LA BÚSQUEDA EN PROFUNDIDAD POR EL ARBOL public EstadoPartida evalPartida() { //VARIALBES UTILIZADAS. int x; //PARA MOVERNOS POR LOS POSIBLES 8 MOVIMIENTOS int xdesptemp; int ydesptemp; int xActualAnt; int yActualAnt; //SI ESTOY EN MODO TRAZA SIEMPRE IMPRIMO TABLERO, INDEPENDIENTEMENTE DE QUE ME ENCUENTRE CON UNA SOLUCIÓN O NO if (modoTraza) { numTrazas++; miConsola.println("Traza: " + Long.toString(numTrazas)); miConsola.println("------------------------------------------------------------------"); PintarTablero(); miConsola.println(); } //ENCONTRAMOS UNA SOLUCIÓN if (lCamino==dimTableroQ2) { numSoluciones++; miConsola.println("Solución encontrada número: "+ Integer.toString(numSoluciones)); //IMPRIMO EL TABLERO ÚNICAMENTE SI NO ESTOY EN MODO TRAZA, YA QUE SI NO YA LO TENDRÍA EN PANTALLA if (modoTraza==false) {
Programación III – Práctica Obligatoria 2012 -‐ 2013
Alfonso Martín Murillo ([email protected]) Página 23 de 23
miConsola.println("Número de soluciones encontradas: "+ Integer.toString(numSoluciones)); miConsola.println("------------------------------------------------------------------"); PintarTablero(); miConsola.println(); } esSolucion=true; } //OBTENCIÓN DE NUEVAS SOLUCIONES else { for (x=0;x<8;x++) { //COMPROBAR SI HAY QUE SEGUIR GENERANDO //GENERAREMOS SIEMPRE QUE, O BIEN NO HAYAMOS ENCONTRADO UNA SOLUCIÓN, O BIEN TENGAMOS QUE ENCONTRAR //TODAS LAS SOLUCIONES if (((modotodasSoluciones==false) && (esSolucion==true))==false) { xdesptemp=xActual+xDesp[x]; ydesptemp=yActual+yDesp[x]; //COMPROBAR QUE LA NUEVA POSICIÓN ESTÁ EN RANGO Y QUE ES UNA CASILLA NO VISITADA if (xdesptemp>=0) { if (xdesptemp<=dimTableroidx0) { if (ydesptemp>=0) { if (ydesptemp<=dimTableroidx0) { //COMPROBAR QUE LA CASILLA NO HA SIDO VISITADA AÚN if (Tablero[xdesptemp][ydesptemp]==0) { //TENGO UNA CASILLA VÁLIDA //ACTUALIZO TABLERO Y BAJO EN PROFUNDIDAD xActualAnt=xActual; yActualAnt=yActual;
Programación III – Práctica Obligatoria 2012 -‐ 2013
Alfonso Martín Murillo ([email protected]) Página 24 de 24
xActual=xdesptemp; yActual=ydesptemp; lCamino++; Tablero[xActual][yActual]=lCamino; //BAJO EN PROFUNDIDAD evalPartida(); //VUELVO DE ABAJO //PONER EL TABLERO A SU SITUACIÓN ANTERIOR Tablero[xdesptemp][ydesptemp]=0; xActual=xActualAnt; yActual=yActualAnt; lCamino--; } //CIERRE IF } //CIERRE IF } //CIERRE IF } //CIERRE IF } //CIERRE IF } //CIERRE IF } //CIERRE FOR } //CIERRE ELSE return this; } //CIERRE FUNCIÓN //FUNCIÓN QUE PINTA EL TABLERO EN PANTALLA public void PintarTablero() { //VARIABLES TEMPORALES int x,y; for (y=dimTableroidx0;y>=0;y--) ////lo recorro al revés para representar que el eje X crece de abajo a arriba y no de arriba a abajo { for (x=0;x<dimTablero;x++) { if (Tablero[x][y]>9)
Programación III – Práctica Obligatoria 2012 -‐ 2013
Alfonso Martín Murillo ([email protected]) Página 25 de 25
{ miConsola.print(Integer.toString(Tablero[x][y])); } else { miConsola.print(" " + Integer.toString(Tablero[x][y])); } if (y!=dimTablero) { miConsola.print("\t"); } } miConsola.println(); //SALTO DE LINEA } } }