You are on page 1of 30

MEMORIA DE LA PRCTICA DE PROGRAMACIN III CURSO 2006-2007

DIEGO J. SNCHEZ CAAMAO.

CENTRO ASOCIADO DE ALBACETE

MEMORIA PRCTICA PROGRAMACIN III

DIEGO J. SNCHEZ CAAMAO

Contenido:
1. RESPUESTAS A LAS CUESTIONES PLANTEADAS EN EL ENUNCIADO.
1.1. 1.2. 1.3. 1.4. 1.5. Caractersticas de la aplicacin del esquema al problema planteado Descripcin del grafo asociado al espacio de soluciones Funcin de coste para la seleccin del nodo ms prometedor Clculo de una cota del valor de las soluciones generadas Estructura de datos utilizada para el almacenamiento de los nodos no explorados 1.6. Pseudocdigo del esquema y de su instanciacin al problema 1.7. Coste computacional del programa desarrollado 2. EJEMPLO DE EJECUCIN PARA EL CASO DE PRUEBA.

3. ESTUDIO DEL COSTE DEL ALGORITMO. 4. LISTADO DEL CDIGO FUENTE COMPLETO.
4.1. Clase Puzzle 4.2. Clase Resuelve 4.3. Clase Nodo 4.4. Clase Arbol 4.5. Clase Traduce

MEMORIA PRCTICA PROGRAMACIN III

DIEGO J. SNCHEZ CAAMAO

1.- RESPUESTAS A LAS CUESTIONES PLANTEADAS EN EL ENUNCIADO.


1.1.- Caractersticas particulares de la aplicacin del esquema al problema planteado. 1.1.a.- Estructura de datos asociada al puzzle. Como estructura de datos para almacenar las fichas se ha elegido un array de n2 enteros, dado el carcter fijo del nmero de fichas de los puzzles, y la facilidad de clculo de la posicin relativa de las fichas respecto a la posicin final requerida. El uso de un array permite tambin una identificacin rpida de identidad entre puzzles (con la comparacin en secuencia de sus datos) e incluso la ordenacin entre ellos, para facilitar su bsqueda. 1.1.b.- Adaptacin del esquema general. El esquema general de ramificacin y poda permite la utilizacin de varias estrategias a la hora de generar los nodos. Para la eleccin del nodo a expandir podemos seguir un recorrido del grafo de soluciones en anchura o en profundidad. O bien podemos utilizar un clculo previo de una funcin de coste que nos permita seleccionar el nodo en principio ms prometedor, el de menor coste. Debido al alto nmero de nodos diferentes posibles obtenidos al modificar el inicial adoptaremos esta ltima, para reducir al mximo el nmero de nodos a analizar. Para implementar la citada estrategia de minimizacin de costes, los nodos generados se almacenarn en una estructura de datos que permita la seleccin del nodo de menor coste de manera eficiente, que se describir en el punto 1.5. 1.1.c.- Consideraciones en la expansin del grafo de soluciones. Debemos tener en cuenta la posibilidad de aparicin de ciclos en la generacin de los nodos. Si uno de los nodos del grafo de soluciones es igual a uno de sus ascendientes, generar en una de sus ramas un grafo igual al que se desarrolla a partir de ese antecesor repetido, lo que multiplicar los nodos a investigar de manera superflua, ya que este subgrafo, si contiene la solucin, siempre tendr un camino de mayor longitud que la de aquel del que se deriva. Para evitar la aparicin de los aludidos ciclos, al generar los descendientes de cada nodo se comprobar:

que ninguno de ellos es igual a su padre, mediante el descarte del movimiento opuesto al que gener el nodo evaluado, y que ninguno de ellos ha sido ya evaluado, por medio de la exploracin de un rbol binario de bsqueda (ordenado por el valor de las casillas de cada puzzle comprobadas en orden ascendente). Se utiliza una estructura diferente a la de la seleccin del nodo ms prometedor debido al diferente criterio de bsqueda a utilizar: ordenados por coste en la seleccin del nodo (varios nodos diferentes pueden tener el mismo coste) y por el valor de las casillas (que pretendemos que nunca sea igual). 1

MEMORIA PRCTICA PROGRAMACIN III

DIEGO J. SNCHEZ CAAMAO

1.2.- Descripcin del grafo asociado al espacio de soluciones. Las soluciones se distribuyen en un rbol cuya raz es el puzzle inicial. A partir de ella se desarrollan las diferentes ramas, que sern generadas expandiendo cada uno de los nodos. Los hijos de un nodo se generan al ir moviendo las fichas del puzzle padre; tomando como referencia el caso de prueba, los movimientos aparentes del hueco podrn ser: Arriba (norte), intercambio de posicin con el 5. Abajo (sur), intercambio de posicin con el 8. 1 5 2 Derecha (este), intercambio de posicin con el 3. Izquierda (oeste), intercambio de posicin con el 4. 4 3 De esta manera tenemos un mximo de cuatro movimientos a partir de cada nodo. Segn hemos visto en el punto 1.1.c, debemos rechazar siempre al menos uno de los movimientos posibles del hueco, aquel que deshaga el ltimo realizado. Esto nos da un mximo de tres hijos para cada nodo distinto del raz (que no tiene un movimiento anterior), sin tener en cuenta la posicin del nodo, que puede hacer descartar a su vez los movimientos que lo puedan sacar del tablero. 7 8 6 Por lo tanto, el rbol asociado al espacio de soluciones ser un rbol ternario, con la excepcin del primer nivel de descendientes, que podr ser de cuatro hijos.

1.3.- Funcin de coste para seleccionar el nodo ms prometedor. Dado que lo que buscamos es la solucin con menos movimientos realizados, la funcin de coste la estableceremos como la suma de dos factores, los movimientos realizados hasta llegar al nodo evaluado y una estimacin de los movimientos restantes hasta alcanzar la solucin. fcoste=(movimientos realizados) + fmovimientos estimados Para el clculo aproximado de los movimientos restantes se usar la suma de las distancias de Manhattan de cada ficha a su posicin final. sta se calcula en nuestro caso contando las filas y columnas que diferencian las posiciones actual y final de cada ficha. Dar un nmero de movimientos cercano al real pero no exacto, ya que no tiene en cuenta que al mover una ficha pueden descolocarse otras (y acercarse a su posicin final o alejarse de la misma). 2

MEMORIA PRCTICA PROGRAMACIN III

DIEGO J. SNCHEZ CAAMAO

distancia=Math.abs((pos/numFilas)-(posfinal/numFilas)) + Math.abs((pos%numFilas)-(posfinal%numFilas));
pos, posfinal: son las posiciones de la ficha dentro del array de datos del nodo y de la solucin, respectivamente. pos/numFilas da la fila de la casilla; pos%numColumnas da la columna.

Como ejemplo presentamos el caso de prueba, resoluble en cuatro movimientos: Valores 1 4 7 8 5 2 3 6 distancia = 4 0 0 0 0 Distancias 1 1 1 1

0 movs. hechos

coste = 4

Por tanto, para seleccionar el nodo ms prometedor usaremos una estrategia de mnimo coste (LC), implementada en la ordenacin de la estructura de datos en la que se almacenarn los nodos an no desarrollados: la extraccin del nodo a analizar en cada iteracin debe proporcionar el nodo de menor coste de los almacenados. 1.4.- Clculo de una cota del valor de las soluciones que se encontrarn generando sucesores a un determinado nodo. Inicialmente tomaremos como cota un nmero de movimientos que depende de la magnitud de n; tomaremos 1 para n=1 (trivial), 6 para n=2 (1) , 31 para n=3 (2) , 80 para n=4 (3) y 1000 para n>4. A esta cota le aadimos un margen de trabajo de 2, dado que a veces la funcin de coste sobreestima ligeramente los movimientos restantes, como acabamos de ver en 1.3. Una vez encontrada la primera solucin, se toma como cota el nmero de movimientos de la misma, para desarrollar slamente nodos con coste menor o igual que el de la solucin encontrada. 1.5.- Estructura de datos utilizada para almacenar en orden de prioridad los nodos creados y an no explorados. Se utiliza un montculo de mnimos, implementado mediante la clase PriorityQueue de Java 5.0. La insercin y la extraccin de la raz las realiza en O(log(n)). La comprobacin de estado vaco y del nmero de nodos contenidos se obtiene en tiempo constante (4) . Para la implementacin de la estrategia LC nos bastar con extraer la raz como seleccin del nodo ms prometedor. Tras esa extraccin, la clase automticamente restaura la condicin de montculo de mnimos.
(1) (2)

http://mathworld.wolfram.com/15Puzzle.html http://www.zib.de/reinefeld/bib/93ijcai.pdf (3) http://www.ifor.math.ethz.ch/publications/1999_parallelsearchbenchzram.ps (4) Java 2.0 Platform Standard Edition 5.0 API Specification

MEMORIA PRCTICA PROGRAMACIN III

DIEGO J. SNCHEZ CAAMAO

1.6.- Pseudocdigo correspondiente al esquema y a su instanciacin al problema. El esquema general es el siguiente:


fun ramificacin-y-poda (ensayo) dev ensayo m montculo-vaco cota-superior cota-superior-inicial solucin solucin-vaca aadir-elemento (ensayo, m) mientras vaco (m) hacer nodo extraer-raz si vlido(nodo) entonces hacer si coste (nodo) < cota-superior entonces hacer solucin nodo cota-superior coste (nodo) fsi si no si cota-inferior (nodo) cota-superior entonces dev solucin si no para cada hijo en expandir (nodo) hacer si condiciones-de-poda(hijo) y cota-inferior(hijo)< cota-superior entonces aadir-nodo (hijo, m) fsi fpara fsi fsi fmientras ffun

En nuestro caso en particular no necesitamos el uso de una cota inferior, ya que lo que buscamos es un tablero resuelto, comprobado tras la llamada a es-solucin (nodo). Como hemos comentado antes, usaremos dos estructuras para almacenar los nodos, un montculo para los nodos no visitados y otro para los que ya hemos evaluado; la funcin expandir debe comprobar que los hijos que genere no han sido ya visitados, para evitar ciclos. Incluimos el pseudocdigo de la funcin expandir en la presentacin de la instanciacin del problema.

MEMORIA PRCTICA PROGRAMACIN III

DIEGO J. SNCHEZ CAAMAO

Esquema adaptado al problema:


fun RyP (ensayo) dev ensayo m montculo-vaco a rbol-vaco cota-superior cota-superior-inicial solucin solucin-vaca aadir-elemento (ensayo, m) mientras vaco (m) hacer nodo extraer-raz (m) si es-solucin (nodo) entonces hacer solucin nodo cota-superior coste (nodo) si cota (nodo) < cota-superior entonces para cada hijo en expandir (nodo, a) hacer aadir (hijo, m) fpara fsi aadir (nodo, a) fmientras dev solucin ffun fun expandir (ensayo, a) dev lista lista lista-vaca para cada movimiento vlido hacer si generar-ensayo(movimiento) a entonces hijo generar ensayo(movimiento) lista insertar (hijo) fsi fpara dev lista ffun

1.7.- Anlisis del coste computacional del programa desarrollado. Para el clculo del coste existe la dificultad de no conocer a priori el tamao del problema. El tamao del puzzle es siempre conocido, n = nmero de filas, y sabemos que el nmero mximo de nodos del rbol de sucesores del puzzle inicial es n2!/2 (5) . La estrategia LC pretende reducir al mnimo el nmero de nodos visitados (y, por lo tanto, expandidos) dentro del citado rbol mediante el uso de una funcin
(5)

http://kevingong.com/Math/SixteenPuzzle.html

MEMORIA PRCTICA PROGRAMACIN III

DIEGO J. SNCHEZ CAAMAO

heurstica h que escoge el nodo ms prometedor mediante la estimacin del nmero de movimientos necesarios. Pero no puede calcular cuntos nodos se debern visitar para encontrar la solucin. Las llamadas ms costosas son las realizadas al montculo (insercin y extraccin de la raz) y al rbol de nodos visitados (insercin y bsqueda), y su coste depende en ambos casos del nmero de nodos generados. Por ello calcularemos el coste del programa con relacin a ese nmero, del que inicialmente slo conocemos su valor mximo. Llamando u al nmero total de nodos evaluados, m al nmero de nodos en cada momento en el montculo y a al de los nodos en el rbol, podemos calcular si suponemos siempre tres hijos generados:
u

T(u)= 5 + 1 +

(1 + log m + k
i=1

+ 1 + 3 +[3 (k2 + log a)+1]+ 3 log m + log a + 1

Entre corchetes se presenta la llamada a la funcin expandir (mximo de tres hijos)


u

T(n)= 7 +

i=1

(4 log m + k

+ 4 log a

Intentando una aproximacin mejor, tratemos de relacionar m y a con u. Las inserciones y comprobaciones en el rbol a, de orden logartmico, se hacen tras evaluar cada nodo, por lo que podemos afirmar que a valdr en cada iteracin i-1. Realizando los clculos tenemos que la serie de los log a vale: log 0 + log 1 + ... + log (u-1) . Dado que la primera insercin es sobre un rbol vaco, por lo tanto de coste constante, podemos sustituir ese log 0 por k. Por tanto, k + log 1 + ... + log (u-1); por las propiedades de los logaritmos, k + log (1 * 2 * ... * (u-1))=k + log ((u-1)!) Para el clculo de las operaicones sobre m, de coste tambin logartmico, debemos tener en cuenta que este valor ir modificndose a lo largo de las pasadas por el bucle while, insertando entre 0 y 3 nodos y extrayendo uno por cada iteracin. En cada momento m valdr u-a = u-(i-1). Sustituyendo tenemos log u + log (u-1) + ... + log 1 = log (u!). Por ello T(n)= 7 + 4 log (u !) + k3 u + 4 (k4 + log ((u-1)!)). Aplicando la regla del mximo, T(u) es de O(u), siendo u el nmero de nodos generados, tomando como valor mximo u = n2!/2.

MEMORIA PRCTICA PROGRAMACIN III

DIEGO J. SNCHEZ CAAMAO

2.- EJEMPLO DE EJECUCIN PARA EL CASO DE PRUEBA.


Se presenta a continuacin la salida en modo traza del ejemplo de prueba, modificada para presentar datos cada nodo evaluado en lugar de cada 2000, como en una ejecucin estndar. Tambin se comenta para ilustrar el trabajo en el montculo de nodos sin visitar.
Archivo: prueba.txt Traza activada. Solucionable. N= 3. Cota= 36. Analizados: 1. Coste: 4. Podados: 0. Sin analizar: 0 Analizados: 2. Coste: 4. Podados: 0. Sin analizar: 3 Analizados: 3. Coste: 4. Podados: 0. Sin analizar: 4 Analizados: 4. Coste: 4. Podados: 0. Sin analizar: 4 Analizados: 5. Coste: 4. Podados: 0. Sin analizar: 5 Primera solucin encontrada, 4 movimientos. Cota= 4. Analizados: 6. Coste: 6. Podados: 0. Sin analizar: 4 Analizados: 7. Coste: 6. Podados: 1. Sin analizar: 3 Analizados: 8. Coste: 6. Podados: 2. Sin analizar: 2 Analizados: 9. Coste: 6. Podados: 3. Sin analizar: 1 Analizados: 10. Coste: 6. Podados: 4. Sin analizar: 0

Analizado: Padre Montculo:{ } Analizado: A Montculo:{D, B, C} Analizado: AA Montculo:{AB, D, C, B} Analizado: AAA Montculo:{D, AB, C, B} Analizado:AAAA Mont:{AAAB,D,C,B,AB} Analizado: AAAB Montculo: {AB, D, C, B} Analizado: AB Montculo: {B, D, C} Analizado: B Montculo: {C, D} Analizado: C Montculo: { D} Analizado: D Montculo: { }

Mejor solucion encontrada: 4 movimientos. Tiempo: 0 seg. 0 mils. Tableros generados: 9. Tableros analizados: 10. Tableros podados: 5. 152 4*3 786 1*2 453 786 12* 453 786 123 45* 786 123 456 78* Nodo padre. Genera cuatro hijos A,B,C,D de coste 4,6,6 y 6, respectivamente. Tras insertarlos, el montculo es: {A4,B6,C6,D6}

Tras extraer A, el montculo queda: {D6,B6,C6} A genera dos hijos AA, AB con coste 4 y 6, respectivamente. Tras insertarlos, el montculo es: {AA4,D6,C6,B6,AB6} Tras extraer AA, el montculo queda: {AB6,D6,C6,B6} AA genera un hijo AAA de coste 4. Tras insertarlo, el montculo es: {AAA4,AB6,C6,B6,D6} Tras extraer AAA, el montculo queda as: {D6,AB6,C6,B6} AAA genera dos hijos AAAA y AAAB, de coste 4 y 6, respectivamente. Tras insertarlos, el montculo queda as: {AAAA4,D6,C6,B6,AB6,AAAB6} Tras extraer AAAA, el montculo queda as: {AAAB6,D6,C6,B6,AB6} Se encuentra AAAA como solucin, la cota pasa a ser 4. Al ir extrayendo los nodos restantes del montculo, no se expanden y se podan por ser su coste > 4.

MEMORIA PRCTICA PROGRAMACIN III

DIEGO J. SNCHEZ CAAMAO

3.- ESTUDIO DEL COSTE DEL ALGORITMO.


Atendiendo exclusivamente al algoritmo principal, tomando como operaciones elementales las relacionadas con las estructuras de datos, tenemos :
n

T(n)= 5 + 1 +

(1 + 1 + 1 + 1 + 3 +[3 (1 + 1)+1]+ 3 * 1+ 1)+ 1


i=1

Es decir, coste lineal, siendo n el nmero de nodos desarrollados por el algoritmo.

4.- LISTADO DEL CDIGO FUENTE COMPLETO.


4.1.- Clase puzzle
// Clase principal public class puzzle { // parmetros de entrada public static boolean t=false,a=false,h=false,fichero=false; public static Nodo inicio=new Nodo(); //Puzzle inicial public static String nombreArchivo=""; //almacena el nombre del archivo public static void main(String[] args) { //comprobacin de los argumentos pasados int parametros=args.length; //n de parmetros if (( parametros>4)) { //si hay 0 ms de 4 parmetros Traduce.ayuda(); //presentamos la ayuda (con la sintaxis) System.exit( 2 ) ; //Fallo 2=argumentos mal }//if parametros for (int c=0;c<parametros;c++){ //leemos los parmetros if (args[c].equalsIgnoreCase("-h")) h=true; else if (args[c].equalsIgnoreCase("-a")) a=true; else if (args[c].equalsIgnoreCase("-t")) t=true; else { //suponemos que si no es h,a,t es el archivo fichero=true;nombreArchivo=args[c]; }//if else }//for c if (h) Traduce.ayuda(); //si se pas h, presentamos la ayuda

if (!fichero){ //si no se pasa un archivo de entrada inicio=Traduce.pasaATipoNodo(); //leemos la entrada estndar }else{ //si se proporciona el archivo inicio=Traduce.pasaATipoNodo(nombreArchivo); //lo leemos

MEMORIA PRCTICA PROGRAMACIN III

DIEGO J. SNCHEZ CAAMAO

}//if else if (t){ //si se pas t, comprobamos la matriz de entrada if(!inicio.compruebaMatriz(t)){ //si no es correcta System.out.println ( "Matriz de entrada incorrecta."); System.exit(1); }else if (parametros==1){ //si slo se pasa t System.out.println ( "Matriz de entrada correcta."); System.exit(0); }//if !inicio

}//if t // si se pasa a, activamos traza y lo ponemos en pantalla if (fichero && a) System.out.println("Archivo: " + nombreArchivo); if (a) System.out.println ( "Traza activada."); Resuelve.puzzle(inicio, a); }//fin main }//fin clase puzzle //resolvemos el puzzle

4.2.- Clase Resuelve


//clase que contiene los algoritmos Ramificacin y poda y expandir, //los contadores y la presentacin de resultados import java.util.*; public class Resuelve { static long v1,v2; static int numAnalizados=0,numGenerados=0,numPodados=0; static int maxCota,cota; public static void puzzle (Nodo entrada, boolean traza) { //candidato es un clon de entrada, para no modificar el puzzle original Nodo candidato=new Nodo(); candidato= entrada; candidato.actualizaPuzzle(); boolean tienesol=candidato.tieneSolucion(); if ((traza)&&(tienesol)) System.out.println("Solucionable."); else if (traza) System.out.println("No solucionable."); v1=System.currentTimeMillis(); //tomamos tiempo al inicio //llamamos a Ramificacin y Poda Nodo resultado=RyP(candidato,traza);

MEMORIA PRCTICA PROGRAMACIN III

DIEGO J. SNCHEZ CAAMAO

v2=System.currentTimeMillis(); int segundos=(int)(v2-v1)/1000; int mils=(int)(v2-v1)%1000; if ((resultado==null)||(!resultado.esSolucion())){ //si RyP devuelve un puzzle no resuelto entrada.presentaPuzzle();

//tomamos el tiempo final

System.out.println("\nNo se ha encontrado solucion."); if (traza){ //comentarios si traza=true System.out.println("Tiempo: " + segundos + " seg. " + mils + " mils."); System.out.println("Tableros analizados: " + numAnalizados + ".\nTableros podados: " + numPodados + "."); }//if traza System.exit(0); //salimos del programa //si est resuelto presentamos la solucin

}else{

if (traza){ //comentarios si traza=true System.out.println(); System.out.println("Mejor solucion encontrada: " + resultado.devuelveMovimientos()+ " movimientos."); System.out.println("Tiempo: " + segundos + " seg. " + mils + " mils."); System.out.println("Tableros generados: " + numGenerados + ".\nTableros analizados: " + numAnalizados + ".\nTableros podados: " + numPodados + "."); }//if traza presentaSolucion(candidato,resultado.devuelveCamino()); }//if candidato }//fin de puzzle // algoritmo Ramificacin y Poda public static Nodo RyP(Nodo candidato, boolean traza){ Arbol vistos=new Arbol(); //rbol de bsqueda para los nodos ya vistos PriorityQueue <Nodo> monticulo=new PriorityQueue <Nodo>(); //montculo para los nodos an sin analizar ArrayList <Nodo> hijos=new ArrayList<Nodo>(); //almacena los hijos Nodo n,solucion=candidato; monticulo.offer(candidato); //aadimos candidato al montculo switch (Nodo.devuelveNumFilas()){ //ajusta la cota segn n al case 1: //nmero mximo de movimientos cota=maxCota=1;break; //segn el nmero de casillas case 2: //ms un margen de trabajo cota=maxCota=6+5;break;

10

MEMORIA PRCTICA PROGRAMACIN III

DIEGO J. SNCHEZ CAAMAO

case 3: cota=maxCota=31+5;break; case 4: cota=maxCota=80+5;break; default: cota=maxCota=1000;break; }//switch if (traza){ System.out.println("N= " + Nodo.devuelveNumFilas() + ". Cota= " + cota + "."); }//if traza while (!monticulo.isEmpty()){ //mientras haya nodos sin analizar n=monticulo.poll(); numAnalizados++; if ((traza)&&(numAnalizados%2000==0)){ //comentarios si traza=true System.out.println("Analizados: " + numAnalizados + ". Coste: " + n.devuelveCoste()+ ". Podados: " + numPodados + ". Sin analizar: " + monticulo.size()); }//if traza if (n.esSolucion()){ //si n es solucin solucion=n; cota=solucion.devuelveMovimientos(); //ajustamos la cota al nmero de movimientos de la solucin //para la poda posterior if (traza){ //comentarios si traza=true System.out.println("Primera solucion encontrada, " + n.devuelveMovimientos() + " movimientos. Cota= " + cota + "."); }//if traza }else if (n.esAceptable(cota)){ //si n es aceptable hijos=expandir(n,vistos); //expandimos el rbol //hijos= el array de hijos de n que devuelve 'expandir' while (!hijos.isEmpty()){ //insertamos en el montculo, ordenados segn el coste try { monticulo.offer(hijos.remove(0)); } catch (OutOfMemoryError e) { System.out.println("Error al insertar un nodo.2 +"Falta memoria."); System.exit(2); }//try catch }//while }else{ numPodados++; //poda si no es aceptable n

11

MEMORIA PRCTICA PROGRAMACIN III

DIEGO J. SNCHEZ CAAMAO

//(ocurre tras el ajuste de la cota con la primera solucin) }//if n.esSolucion try { //se aade n al rbol de nodos ya vistos ordenados segn los datos vistos.insertarPorDatos(n); } catch (OutOfMemoryError e) { System.out.println("Error al insertar un nodo. " + "Falta memoria."); System.exit(2); }//try catch }//while return solucion; //Devuelve la mejor solucin encontrada hasta llegar al lmite. //Dar error "Solucin no encontrada" si devuelve el nodo inicial. }//RyP // // // // // desarrolla los hijos factibles del nodo padre, y los inserta en la lista de posibles soluciones si no han sido ya comprobados (mediante el rblo vistos) y si son viables (mediante esAceptable se comprueba que su coste estimado no sobrepasa la cota) devuelve la lista de hijos generados para introducir en 'nuevos' public static ArrayList <Nodo> expandir(Nodo padre,Arbol vistos){ ArrayList <Nodo> lista=new ArrayList <Nodo>(); //Array para devolver los hijos generados char ultimoMov; String historia = padre.devuelveCamino(); int tamao=historia.length(); if (tamao!=0){ //localiza el ltimo movimiento hecho ultimoMov=historia.charAt(tamao-1); }else{ ultimoMov='J'; //si es el tablero inicial } boolean[] movPosibles=padre.devuelveMovPosibles(); if ((movPosibles[0]) && (ultimoMov!='S')){ //mov N Nodo hijo=(Nodo) padre.clone(); hijo.mueveN(); if ((!vistos.buscar(hijo))&&(hijo.esAceptable(cota))){ lista.add(hijo); numGenerados++; }else{ numGenerados++; numPodados++; } }//mov N if ((movPosibles[1])&& (ultimoMov!='N')){ //mov S

12

MEMORIA PRCTICA PROGRAMACIN III

DIEGO J. SNCHEZ CAAMAO

Nodo hijo=(Nodo) padre.clone(); hijo.mueveS(); if ((!vistos.buscar(hijo))&&(hijo.esAceptable(cota))){ lista.add(hijo); numGenerados++; }else{ numGenerados++; numPodados++; }//mov S if ((movPosibles[2])&& (ultimoMov!='O')){ Nodo hijo=(Nodo) padre.clone(); hijo.mueveE(); if ((!vistos.buscar(hijo))&&(hijo.esAceptable(cota))){ lista.add(hijo); numGenerados++; } else{ numGenerados++; numPodados++; }//mov E if ((movPosibles[3])&& (ultimoMov!='E')){ Nodo hijo=(Nodo) padre.clone(); hijo.mueveO(); if ((!vistos.buscar(hijo))&&(hijo.esAceptable(cota))){ lista.add(hijo); numGenerados++; }else{ numGenerados++; numPodados++; }//mov O return lista; }//expandir // //

} //mov E

} //mov O

presenta la solucin desde el tablero inicial, mediante el movimiento del hueco segn el camino almacenado public static void presentaSolucion(Nodo inicio, String camino){ inicio.presentaPuzzle(); //presenta el nodo inicial int tope=camino.length(); //n de movimientos int contador=0; while (contador<tope){ char movimiento=camino.charAt(contador); switch (movimiento){ //mueve y presenta segn el movimiento ledo case 'N': inicio.mueveN();inicio.presentaPuzzle();break; case 'S': inicio.mueveS();inicio.presentaPuzzle();break; case 'E': inicio.mueveE();inicio.presentaPuzzle();break; case 'O':

13

MEMORIA PRCTICA PROGRAMACIN III

DIEGO J. SNCHEZ CAAMAO

inicio.mueveO();inicio.presentaPuzzle();break; } contador++; }//while }//presentaSolucion }//resuelve

4.3.- Clase Nodo.


//clase que almacena los datos de los puzzles y los mtodos para su manipulacin public class Nodo implements Comparable, Cloneable { // constantes definidas a partir de la entrada (excepto minValor) private static int numFilas; private static int numColumnas; private static int numCasillas; private static int minValor=1; //si se introduce un cero, error private static int topeValor; //rango de valores de 1 a n^2-1 private static int blanco;

// atributos de instancia private String camino; private int colocadas; private int movimientos; private int coste; private int datos[]=new int[numCasillas]; private int posHueco;

//almacena los movimientos del hueco //n de fichas colocadas //n de movimientos realizados //coste de cada nodo //array de int con las piezas //posicin del hueco en el array

private boolean movPosibles[]=new boolean[4]; //array de booleanos con // los movimientos posibles del hueco en orden Norte, Sur, Este, Oeste. public Nodo izda, dcha; // constructor public Nodo(){ for (int a= 0;a<numCasillas;a++){ datos[a]=0; }//for a movimientos=0; camino=""; }//fin del constructor de Nodo //para el rbol

//rellena de ceros las casillas

//

imprime en pantalla public void presentaPuzzle(){

14

MEMORIA PRCTICA PROGRAMACIN III

DIEGO J. SNCHEZ CAAMAO

String relleno; if (numCasillas<10){ relleno=""; }else{ relleno=" "; }//if numfilas

//define el caracter de relleno si hay //nmeros >10 para presentar el puzzle

for (int a=0;a<numCasillas;a++){ if (a%numFilas==0) System.out.println(); int numero=datos[a]; if (numero==blanco) { System.out.print(relleno + "* "); //sustituye n^2 por '*' }else{ if (numero<10){ System.out.print(relleno + numero + " " ); }else{ System.out.print(numero + " " ); }//if numero<10 }//if numero==blanco }//for a System.out.println(); //lnea en blanco por debajo del puzzle }//fin de presentaPuzzle // devuelve el nmero de casillas rellenas public int devuelveColocadas(){ return colocadas; }//fin de devuelveColocadas // devuelve un String que almacena el camino segn los movimientos del hueco public String devuelveCamino(){ return camino; }//devuelveCamino devuelve un array de booleanos con los movimientos posibles del hueco en orden Norte, Sur, Este, Oeste. public boolean[] devuelveMovPosibles(){ return movPosibles; }//devuelveMovPosibles dvuelve un entero con el nmero de movimientos realizados public int devuelveMovimientos(){ return movimientos; }//devuelveMovimientos devuelve un entero con el nmero de filas del puzzle

// //

//

//

15

MEMORIA PRCTICA PROGRAMACIN III

DIEGO J. SNCHEZ CAAMAO

public static int devuelveNumFilas(){ return numFilas; }//devuelveNumFilas // devuelve un entero con el nmero de columnas del puzzle public static int devuelveNumColumnas(){ return numColumnas; }//devuelveNumColumnas devuelve un entero con el nmero total de casillas del puzzle public static int devuelveNumCasillas(){ return numCasillas; }//devuelveNumCasillas devuelve un entero el mnimo valor que puede tener una casilla. Es 1. Se usa en la comprobacin del archivo de entrada public static int devuelveMinValor(){ return minValor; }//devuelve minValor devuelve un entero con el mximo valor que puede tener una casilla. Es n^2-1 Se usa en la comprobacin del archivo de entrada public static int devuelveTopeValor(){ return topeValor; }//devuelveTopeValor devuelve el int coste public int devuelveCoste(){ return coste; }//devuelveCoste devuelve el array de enteros con las casillas public int[] devuelveDatos(){ return datos; }//devuelveDatos se cambia el nmero de filas public static void ponerNumFilas(int filas){ numFilas=filas; }//ponerNumFilas se cambia el nmero de columnas public static void ponerNumColumnas(int columnas){ numColumnas=columnas; }//ponerNumColumnas se cambia el nmero de casillas public static void ponerNumCasillas(int casillas){

//

// //

// //

//

//

//

//

//

16

MEMORIA PRCTICA PROGRAMACIN III

DIEGO J. SNCHEZ CAAMAO

numCasillas=casillas; }//ponerNumCasillas // se cambia el valor mximo de casilla public static void ponerTopeValor(int valor){ topeValor=valor; }//ponerTopeValor se cambia el valor del blanco. Es n^2 public static void ponerBlanco(int valor){ blanco=valor; }//ponerBlanco calcula el coste del nodo. Los movimientos realizados hasta el momento mas la suma de las distancias Manhattan de las casillas (devuelta por calculaDistancias) public void actualizaCoste(){ coste=movimientos+calculaDistancias(); }//actualizaCoste devuelve true si el coste del nodo es inferior a la cota public boolean esAceptable(int cota){ if (this.coste>=cota) return false; else return true; }//esAceptable compara los valores de las casillas del nodo con el array de enteros 'datos' devuelve 1 si 'datos' es mayor casilla a casilla que el nodo; -1 si es menor y 0 si es igual. Se usa para la construccin y bsqueda en el rbol binario. public int compara(int[] datos){ for (int i=0;i<numCasillas;i++){ if (this.datos[i]<datos[i]) return 1; else if (this.datos[i]>datos[i]) return -1; } return 0; }//compara

//

// // //

//

// // //

//inserta una ficha en una casilla public void inserta(int posit, int dato){ datos[posit]=dato; }//fin inserta // actualiza los datos de cada tablero, se usa tras mover el hueco public void actualizaPuzzle(){ sumaColocadas(); //cuenta las casillas en posicin correcta actualizaCoste(); //recalcula el coste posHueco=devuelvePosHueco(); //actualiza el array de booleanos movPosibles

17

MEMORIA PRCTICA PROGRAMACIN III

DIEGO J. SNCHEZ CAAMAO

if (posHueco/numFilas>0) {movPosibles[0]=true; //norte }else movPosibles[0]=false; if (posHueco/numFilas<numFilas-1) {movPosibles[1]=true;//sur }else movPosibles[1]=false; if (posHueco%numColumnas<numColumnas-1) {movPosibles[2]=true;//este }else movPosibles[2]=false; if ((posHueco%numColumnas>0) ){movPosibles[3]=true;//oeste }else movPosibles[3]=false; }//actualizaPuzzle // devuelve la posicin del hueco public int devuelvePosHueco(){ for (int a=0;a<numCasillas;a++){ int valor=datos[a]; if (valor==blanco){ return a; }//if valor }//for a return blanco; }//devuelvePosHueco

//ndices de fila

//si lo encontramos, devuelve la fila

// //

calcula y devuelve las distancias Manhattan de cada ficha. Para el clculo del coste public int calculaDistancias(){ int distancia=0,distanciaA,distanciaB,dato; for (int pos=0;pos<numCasillas;pos++){ dato=this.datos[pos]; if ((dato!=blanco)&&(dato!=pos+1)){ //se compara con pos+1 al ir el array de 0 a n^2 distanciaA=(((pos/numFilas))-((dato-1)/numFilas)); distanciaB=(pos%numFilas)-((dato-1)%numFilas); distancia=distancia+Math.abs(distanciaA)+Math.abs(distanciaB); }//if dato }//for return distancia; }//calculaDistancias

//

calcula y devuelve las inversiones en cada tablero. public int calculaInversiones(){ int inversiones=0,dato,datoB; for (int pos=0;pos<numCasillas;pos++){ dato=this.datos[pos]; if (dato!=blanco) { for (int y=pos+1;y<numCasillas;y++){ datoB=this.datos[y]; if ((datoB!=blanco)&&(datoB<dato))inversiones++; }//for

18

MEMORIA PRCTICA PROGRAMACIN III

DIEGO J. SNCHEZ CAAMAO

}//if dato }//for if (numFilas%2==0){ int filaHueco=(this.devuelvePosHueco()/numFilas)+1; return inversiones+filaHueco; }else return inversiones; }//calculaInversiones // Devuelve true si el tablero tiene solucin posible public boolean tieneSolucion(){ return this.calculaInversiones()%2==0; }

//

movimientos del hueco public void mueveN(){ if (movPosibles[0]){ inserta(posHueco,datos[posHueco-numFilas]); inserta(posHueco-numFilas,blanco); //intercambio de posiciones posHueco=posHueco-numFilas; //actualiza posHueco movimientos++; //incrementa movimientos camino=camino+"N"; //actualiza el camino actualizaPuzzle(); //actualiza los datos del tablero }else{ System.out.println("Error: movimiento al N fuera de tablero." + "No se realiza."); //si no se puede realizar el movimiento }//if }//fin mueveN public void mueveS(){ if (movPosibles[1]){ inserta(posHueco,datos[posHueco+numFilas]); inserta(posHueco+numFilas,blanco); posHueco=posHueco+numFilas; movimientos++; camino=camino+"S"; actualizaPuzzle(); }else{ System.out.println("Error: movimiento al S fuera de tablero. " + "No se realiza."); }//if }//fin mueveS public void mueveE(){ if (movPosibles[2]){ inserta(posHueco,datos[posHueco+1]); inserta(posHueco+1,blanco); posHueco++; movimientos++;

19

MEMORIA PRCTICA PROGRAMACIN III

DIEGO J. SNCHEZ CAAMAO

camino=camino+"E"; actualizaPuzzle(); }else{ System.out.println("Error: movimiento al E fuera de tablero." + "No se realiza."); }//if }//fin mueveE public void mueveO(){ if (movPosibles[3]){ inserta(posHueco,datos[posHueco-1]); inserta(posHueco-1,blanco); posHueco--; movimientos++; camino=camino+"O"; actualizaPuzzle(); }else{ System.out.println("Error: movimiento al O fuera de tablero." + "No se realiza."); }//if }//fin mueveO // devuelve true si el nodo es solucion, si todas sus casillas estn colocadas public boolean esSolucion(){ if (this.colocadas==numCasillas){ return true; }else return false; }//esSolucion devuelve 'true' si no hay valores repetidos y estn definidas todas las casillas. Devuelve 'False' si hay error. Se le pasa como parmetro el booleano 't', que indica si se est en modo traza; si es as, se presenta el mensaje de error (si lo hubiera) public boolean compruebaMatriz(boolean t){ //comprueba si todos los nmeros estn presentes for (int a=0;a<numCasillas;a++){ //ndices de fila int valor=datos[a]; if (valor==0){ if (t) System.out.println("Falta un numero de ficha."); return false; }//if valor }//for a //comprueba si hay nmeros repetidos o si falta alguno for (int num=1;num<topeValor+1;num++){ boolean presente=false; for (int a=0;a<numCasillas;a++){

// // // // //

//ndices de fila

20

MEMORIA PRCTICA PROGRAMACIN III

DIEGO J. SNCHEZ CAAMAO

int valor=datos[a]; if ((presente)&&(valor==num)){ //si num ya est presente if (t) { //informacin extra si traza activada System.out.println("El "+ num + " repetido."); presentaPuzzle(); }// if t return false; //matriz errnea }else if (valor==num){ presente=true; }//if presente }//for a if (!presente){ if (t) { //si no se ha encontrada el nmero System.out.print("El "+ num + " sin colocar."); presentaPuzzle(); }//if t return false; } }//for num return true; //matriz correcta }//fin compruebaMatriz // Repasa toda la tabla y cuenta las fichas colocadas public void sumaColocadas(){ int suma=0; for (int a=0;a<numCasillas;a++){ if (datos[a]==a+1) suma++; }//for a colocadas=suma; }//fin sumaColocadas // implementacin de compareTo public int compareTo (Object nodo){ //ordena inicialmente por el coste int costeActual = this.devuelveCoste(); int costeNuevo = ((Nodo)nodo).devuelveCoste(); int valor = costeActual > costeNuevo ? 1 : costeActual==costeNuevo ? 0 : -1; //a igualdad de coste, favorece al de menos movimientos hechos if (valor==0){ int movActual=this.devuelveMovimientos(); int movNuevo=((Nodo)nodo).devuelveMovimientos(); //matriz errnea

21

MEMORIA PRCTICA PROGRAMACIN III

DIEGO J. SNCHEZ CAAMAO

return movActual > movNuevo ? -1 : movActual==movNuevo ? 0 : 1; } return valor; }//compareTo // // sobreescritura de Object.clone para evitar variar los datos al manipular la copia de un puzzle public Object clone() { Nodo temp; try { //para capturar posibles fallos de memoria al clonar temp = new Nodo(); for (int a=0;a<numCasillas;a++){ int dato=this.datos[a]; //insertamos los datos uno a uno temp.inserta(a,dato); }//for a temp.actualizaPuzzle(); temp.camino=this.camino; temp.movimientos=this.movimientos; return temp; } catch (OutOfMemoryError e) { System.out.println("Error al crear un nodo. Falta memoria."); System.exit(2); return null; }//trycatch }//fin clone

}//fin clase Nodo

4.4.- Clase Arbol


// Clase que implementa un rbol binario de bsqueda y los mtodos //necesarios para su manejo public class Arbol { public Nodo raiz; public int numNodos; // Constructor public Arbol(){ raiz=null; numNodos=0; }//Arbol() devuelve true si se encuentra el nodo pedido

//

22

MEMORIA PRCTICA PROGRAMACIN III

DIEGO J. SNCHEZ CAAMAO

public boolean buscar(Nodo nodo){ boolean encontrado=false; Nodo actual=raiz; //comenzamos por la raiz int []datosNodo=nodo.devuelveDatos(); while ((!encontrado)&&(actual!=null)){ //mientras queden nodos por ver int comp=actual.compara(datosNodo); if (comp>0){ //si el nuevo es mayor que actual, busca dcha actual=actual.dcha; }else if (comp<0){ //si el nuevo es menor que actual, busca izda actual=actual.izda; } else encontrado=true; //si es igual, encontrado }//while return encontrado; }//buscar // // inserta ordenando por los datos del nodo (usado para el rbol de nodos ya evaluados) public boolean insertarPorDatos(Nodo nodo){ boolean insertado=false; Nodo actual=raiz; //comenzamos en la raz if (actual==null){ //si el rbol est vaco, insertamos como raz raiz=nodo;return true; } int []datosNodo=nodo.devuelveDatos(); while ((!insertado)&&(actual!=null)){ //mientras queden nodos por ver int comp=actual.compara(datosNodo); if (comp>0){ //si el nodo actual es menor if (actual.dcha!=null){ //si tiene hijo dcho,sigue bsqueda dcha actual=actual.dcha; }else{ actual.dcha=nodo; //si no tiene hijo dcho,inserta dcha insertado=true;break; }//if actual.dcha }else if (comp<0){ //si actual es menor if (actual.izda!=null){ //si tiene hjo izdo, busca izda actual=actual.izda; }else{ actual.izda=nodo; //si no, inserta izda insertado=true;break; }//if actual.dcha } else { //si el nodo es igual no se inserta break; }//if comp }//while if (insertado) numNodos++;

23

MEMORIA PRCTICA PROGRAMACIN III

DIEGO J. SNCHEZ CAAMAO

return insertado; }//insertar por datos // devuelve true si el rbol est vaco public boolean esVacio(){ return (raiz==null); }//esVacio devuelve el nmero de nodos del rbol public int devuelveNumNodos(){ return numNodos; }//devuelveNumNodos

//

}//clase Arbol

4.5.- Clase Traduce


//Contiene los mtodos para extraer los datos del archivo inicial (o pipeline) //y los introduce en la matriz de datos si estn dentro de lmites. import java.io.*; import java.util.Vector; public class Traduce { // Si en la entrada se pasa un parmetro con el nombre del archivo public static Nodo pasaATipoNodo(String nombreArchivo){ Nodo prueba=new Nodo(); try { //abrimos el archivo FileReader entrada = new FileReader(nombreArchivo) ; BufferedReader datosEntrada=new BufferedReader((entrada)); prueba=traduce(datosEntrada); entrada.close(); // cerramos el archivo } catch ( IOException io ) { // si hay error al abrir el archivo System.out.println( "Error E/S. El archivo '" + nombreArchivo + "' no es valido o no esta en el directorio del programa." ) ; System.exit( 3 ) ; // } return prueba; } //devolvemos un Nodo con los valores de la entrada Fallo 3= error en archivo de entrada

24

MEMORIA PRCTICA PROGRAMACIN III

DIEGO J. SNCHEZ CAAMAO

//

Si es a travs de entrada estndar o pipeline no se le pasan argumentos. public static Nodo pasaATipoNodo(){ BufferedReader datos=new BufferedReader (new InputStreamReader (System.in)); // abrimos el lector de entrada estndar try{ if (System.in.available()==0){ //si la entrada estandar esta vaca System.out.println("Entrada estandar o por 'pipe' vacia."); System.exit( 3 ) ; //Fallo 3= error en archivo de entrada } } catch ( IOException io ) { //si hay error en la entrada estandar System.out.println("Fallo en la entrada estandar o pipe."); System.exit( 3 ) ; //Fallo 3= error en archivo de entrada } return traduce(datos); //devolvemos un TipoSudoku con los valores de la entrada }

// //

Dimensiona el array de datos con respecto al nmero de filas de la entrada y fija las variables de Nodo referidas a n. Devuelve un vector public static Vector<String> dimensiona(BufferedReader datosEntrada){ Vector <String> entrada = new Vector <String>(); int tamanoEntrada=0; try{ String fila=datosEntrada.readLine(); while ( fila != null ) { //aadimos al vector todas las lneas no vacas if ((fila.length()!=0)&&(fila.charAt(0)!='#')){ entrada.addElement(fila); } //y leemos la siguiente lnea fila = datosEntrada.readLine(); }//while //Definimos el tamao del puzzle con las primera lnea de la entrada for (int a=0;a<entrada.size();a++){ String linea = (String)entrada.elementAt(a); //linea es un string con la fila while ((linea.length()!=0)&&(linea.charAt(0)==' ')){ linea=linea.replaceFirst(" ", ""); //elimina los espacios iniciales }//while

25

MEMORIA PRCTICA PROGRAMACIN III

DIEGO J. SNCHEZ CAAMAO

if (linea.length()==0){ errorEntrada("Una lnea slo contiene espacios."); } String [] numero=linea.split("\\s+"); //dividimos la linea tamanoEntrada=numero.length; }// for a if (tamanoEntrada<1) errorEntrada("No hay lneas vlidas."); Nodo.ponerNumFilas(tamanoEntrada); Nodo.ponerNumColumnas(tamanoEntrada); Nodo.ponerNumCasillas(tamanoEntrada*tamanoEntrada); Nodo.ponerTopeValor((tamanoEntrada*tamanoEntrada)-1); Nodo.ponerBlanco(tamanoEntrada*tamanoEntrada); if (tamanoEntrada==1) { Nodo.ponerTopeValor(1); Nodo.ponerBlanco(0); } //caso especial de tamao 1

} catch ( IOException io ) { //si hay error al abrir la entrada System.out.println( "Error al procesar los datos de entrada." ) ; System.exit( 2 ) ; //Fallo 2= error en entrada }//try catch return entrada; }//fin dimensiona // // // si la matriz de entrada es correcta (nmero de filas y columnas iguales, los dgitos son de 1 a n^2-1 o asteriscos y las lneas que empiezan por '#' son comentarios) devuelve una matriz de int Nodo. public static Nodo traduce(BufferedReader datosEntrada){ Vector <String> entrada; entrada=dimensiona(datosEntrada); //fija los lmites Nodo prueba=new Nodo(); boolean yaHayBlanco=false; int filasEntrada=entrada.size(); for (int a=0;a<filasEntrada ;a++){ String linea = (String)entrada.elementAt(a); //linea es un string con la fila while ((linea.length()!=0)&&(linea.charAt(0)==' ')){ linea=linea.replaceFirst(" ", "");//elimina los espacios iniciales }//while if (linea.length()==0){ errorEntrada("Una lnea slo contiene espacios."); }

26

MEMORIA PRCTICA PROGRAMACIN III

DIEGO J. SNCHEZ CAAMAO

String [] numero=linea.split("\\s+"); //dividimos la linea if (numero.length!=Nodo.devuelveNumColumnas()) { errorEntrada("Incorrecto numero de datos en la fila " + (a+1) + ":\nDeberia haber " + Nodo.devuelveNumColumnas() + "."); }//if for (int bb=0;bb<numero.length;bb++){ if (numero[bb].equals("*")){ if (!yaHayBlanco){ prueba.inserta((a*Nodo.devuelveNumFilas())+ bb,Nodo.devuelveTopeValor() +1); yaHayBlanco=true; }else{ errorEntrada("Mas de un blanco en el puzzle."); }//if yaHayBlanco } else { //si no es asterisco try{ int proximo=Integer.parseInt(numero[bb]); if ((proximo>=Nodo.devuelveMinValor())&& (proximo<Nodo.devuelveTopeValor()+1)){ prueba.inserta((a*Nodo.devuelveNumF ilas())+bb,proximo); }else{ //fuera de rango errorEntrada("Valor fuera de rango: " + proximo + ". Debe estar entre " + Nodo.devuelveMinValor() + " y " + Nodo.devuelveTopeValor()+"." ); } }catch(Exception e){ //si fallo en conversion a int errorEntrada("Valor extrao en la " + "entrada: '" + numero[bb] + "'"); }//try catch }//if numero }//for bb }//for a return prueba; }//fin traduce //sale del programa con el mensaje recibido en el String 'error' public static void errorEntrada(String error){ System.out.println("Matriz de entrada incorrecta:\n" + error); System.exit(1); //Fallo 1= matriz de entrada incompleta o incorrecta }//fin errorEntrada

27

MEMORIA PRCTICA PROGRAMACIN III

DIEGO J. SNCHEZ CAAMAO

// //

Muestra los crditos y la sintaxis. Se han evitado los acentos para evitar conflictos entre la codificacin UNICODE del java y el ASCII de la consola public static void ayuda(){ System.out.println("Puzzle."); System.out.println("DIEGO J. SANCHEZ CAAMAO. DNI 12385191-J"); System.out.println("Centro Asociado de Albacete."); System.out.println(); System.out.println("Formato de la linea de parametros: " + "java puzzle [-t] [-a] [-h] [fichero]"); System.out.println(); System.out.println("-t: Realiza un test de correccion al puzzle de " + "entrada."); System.out.println(" Si es incompleto o incorrecto, devuelve 1." + "\n En caso contrario, devuelve 0."); System.out.println(); System.out.println("-a: Modo traza. "); System.out.println(" Muestra toda la secuencia de tableros que se "+ "van generando\n hasta alcanzar la solucion con menor " + "numero de movimientos."); System.out.println(); System.out.println("-h: Modo ayuda. Muestra sintaxis y creditos."); System.out.println(); System.out.println("fichero: archivo con la matriz de entrada."); System.out.println(); }//fin ayuda

}//fin clase Traduce

28

You might also like