08 Programacion Logica Teoria y Practica - Pascual Julian Iranzo Maria Alpuente (1)
Memoria de La Practica de Programacion III 06-07
Transcript of Memoria de La Practica de Programacion III 06-07
-
7/28/2019 Memoria de La Practica de Programacion III 06-07
1/30
MEMORIA DE LA PRCTICA DEPROGRAMACIN III
CURSO 2006-2007
DIEGO J. SNCHEZ CAAMAO.
CENTRO ASOCIADO DE ALBACETE
-
7/28/2019 Memoria de La Practica de Programacion III 06-07
2/30
MEMORIA PRCTICA PROGRAMACIN III DIEGO J. SNCHEZ CAAMAO
Contenido:
1. RESPUESTAS A LAS CUESTIONES PLANTEADAS EN EL
ENUNCIADO.
1.1. Caractersticas de la aplicacin del esquema al problema planteado1.2. Descripcin del grafo asociado al espacio de soluciones1.3. Funcin de coste para la seleccin del nodo ms prometedor1.4. Clculo de una cota del valor de las soluciones generadas1.5. Estructura de datos utilizada para el almacenamiento de los nodos no
explorados1.6. Pseudocdigo del esquema y de su instanciacin al problema1.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 Puzzle4.2. Clase Resuelve4.3.Clase Nodo
4.4. Clase Arbol4.5. Clase Traduce
i
-
7/28/2019 Memoria de La Practica de Programacion III 06-07
3/30
MEMORIA PRCTICA PROGRAMACIN III DIEGO J. SNCHEZ CAAMAO
1.- RESPUESTAS A LAS CUESTIONES PLANTEADAS EN ELENUNCIADO.
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 n2enteros, dado el carcter fijo del nmero de fichas de los puzzles, y la facilidad declculo 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 ordenacinentre ellos, para facilitar su bsqueda.
1.1.b.- Adaptacin del esquema general.
El esquema general de ramificacin y poda permite la utilizacin de variasestrategias 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 elinicial adoptaremos esta ltima, para reducir al mximo el nmero de nodos aanalizar. Para implementar la citada estrategia de minimizacin de costes, los
nodos generados se almacenarn en una estructura de datos que permita laseleccin del nodo de menor coste de manera eficiente, que se describir en elpunto 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 delos nodos. Si uno de los nodos del grafo de soluciones es igual a uno de susascendientes, 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 demanera 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 laaparicin de los aludidos ciclos, al generar los descendientes de cada nodo secomprobar:
que ninguno de ellos es igual a su padre, mediante el descarte del movimientoopuesto al que gener el nodo evaluado, y
que ninguno de ellos ha sido ya evaluado, por medio de la exploracin de unrbol binario de bsqueda (ordenado por el valor de las casillas de cada
puzzle comprobadas en orden ascendente). Se utiliza una estructura diferentea 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
-
7/28/2019 Memoria de La Practica de Programacion III 06-07
4/30
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 deella se desarrollan las diferentes ramas, que sern generadas expandiendo cadauno 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 movimientosaparentes del hueco podrn ser:
Arriba (norte), intercambio de posicin con el 5. Abajo (sur), intercambio de posicin con el 8. Derecha (este), intercambio de posicin con el 3. Izquierda (oeste), intercambio de posicin con el 4.
De esta manera tenemos un mximo de cuatromovimientos a partir de cada nodo. Segn hemos vistoen 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 tieneun movimiento anterior), sin tener en cuenta la posicin del nodo, que puedehacer descartar a su vez los movimientos que lo puedan sacar del tablero.
Por lo tanto, el rbol asociado al espacio de soluciones ser un rbol ternario, conla excepcin del primer nivel de descendientes, que podr ser de cuatro hijos.
1 5 2
4 3
7 8 6
1.3.- Funcin de coste para seleccionar el nodo ms prometedor.
Dado que lo que buscamos es la solucin con menos movimientos realizados, lafuncin de coste la estableceremos como la suma de dos factores, losmovimientos realizados hasta llegar al nodo evaluado y una estimacin de losmovimientos restantes hasta alcanzar la solucin.
fcoste=(movimientos realizados) + fmovimientosestimados
Para el clculo aproximado de los movimientos restantes se usar la suma de lasdistancias de Manhattan de cada ficha a su posicin final. sta se calcula ennuestro caso contando las filas y columnas que diferencian las posiciones actual yfinal de cada ficha. Dar un nmero de movimientos cercano al real pero noexacto, ya que no tiene en cuenta que al mover una ficha pueden descolocarseotras (y acercarse a su posicin final o alejarse de la misma).
2
-
7/28/2019 Memoria de La Practica de Programacion III 06-07
5/30
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 dedatos del nodo y de la solucin, respectivamente. pos/numFilasda la fila de la casilla; pos%numColumnas da la columna.
Como ejemplo presentamos el caso de prueba, resoluble en cuatro movimientos:
Valores Distancias
1 5 2 0 1 1
4 3 0 1
7 8 6 0 0 1
0 movs. hechos distancia = 4 coste = 4
Por tanto, para seleccionar el nodo ms prometedor usaremos una estrategia demnimo coste (LC), implementada en la ordenacin de la estructura de datos en laque se almacenarn los nodos an no desarrollados: la extraccin del nodo aanalizar en cada iteracin debe proporcionar el nodo de menor coste de losalmacenados.
1.4.- Clculo de una cota del valor de las soluciones que se encontrarn generandosucesores 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), 80para 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 movimientosrestantes, como acabamos de ver en 1.3.Una vez encontrada la primera solucin, se toma como cota el nmero demovimientos de la misma, para desarrollar slamente nodos con coste menor oigual que el de la solucin encontrada.
1.5.- Estructura de datos utilizada para almacenar en orden de prioridad losnodos creados y an no explorados.
Se utiliza un montculo de mnimos, implementado mediante la clasePriorityQueue de Java 5.0. La insercin y la extraccin de la raz las realiza enO(log(n)). La comprobacin de estado vaco y del nmero de nodos contenidos seobtiene en tiempo constante(4).
Para la implementacin de la estrategia LC nos bastar con extraer la raz comoseleccin del nodo ms prometedor. Tras esa extraccin, la clase automticamenterestaura la condicin de montculo de mnimos.
(1)http://mathworld.wolfram.com/15Puzzle.html(2)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
3
http://mathworld.wolfram.com/15Puzzle.htmlhttp://www.zib.de/reinefeld/bib/93ijcai.pdfhttp://www.ifor.math.ethz.ch/publications/1999_parallelsearchbenchzram.pshttp://www.ifor.math.ethz.ch/publications/1999_parallelsearchbenchzram.pshttp://www.ifor.math.ethz.ch/publications/1999_parallelsearchbenchzram.pshttp://www.ifor.math.ethz.ch/publications/1999_parallelsearchbenchzram.pshttp://www.zib.de/reinefeld/bib/93ijcai.pdfhttp://mathworld.wolfram.com/15Puzzle.html -
7/28/2019 Memoria de La Practica de Programacion III 06-07
6/30
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)
mientrasvaco (m) hacer
nodo extraer-raz
si vlido(nodo) entonces hacer
si coste (nodo) < cota-superiorentonces hacer
solucin nodo
cota-superior coste (nodo)fs i
si no
si cota-inferior (nodo) cota-superiorentonces
dev solucin
si no
paracada hijo en expandir (nodo) hacer
si condiciones-de-poda(hijo) y cota-inferior(hijo)< cota-superior
entonces aadir-nodo (hijo, m)
fs i
fpara
fs i
fs i
fmientras
ffun
En nuestro caso en particular no necesitamos el uso de una cota inferior, ya que loque buscamos es un tablero resuelto, comprobado tras la llamada a es-solucin(nodo).Como hemos comentado antes, usaremos dos estructuras para almacenar losnodos, un montculo para los nodos no visitados y otro para los que ya hemosevaluado; la funcin expandir debe comprobar que los hijos que genere no hansido ya visitados, para evitar ciclos.
Incluimos el pseudocdigo de la funcin expandir en la presentacin de lainstanciacin del problema.
4
-
7/28/2019 Memoria de La Practica de Programacion III 06-07
7/30
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)
mientrasvaco (m) hacer
nodo extraer-raz (m)
si es-solucin (nodo) entonces hacer
solucin nodo
cota-superior coste (nodo)
si cota (nodo) < cota-superiorentonces
para cada hijo en expandir (nodo, a) haceraadir (hijo, m)
fpara
fs i
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)
fs i
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 delproblema. El tamao del puzzle es siempre conocido, n = nmero de filas, ysabemos que el nmero mximo de nodos del rbol de sucesores del puzzle iniciales n2!/2(5).
La estrategia LC pretende reducir al mnimo el nmero de nodos visitados (y, porlo tanto, expandidos) dentro del citado rbol mediante el uso de una funcin
(5)http://kevingong.com/Math/SixteenPuzzle.html
5
http://kevingong.com/Math/SixteenPuzzle.htmlhttp://kevingong.com/Math/SixteenPuzzle.html -
7/28/2019 Memoria de La Practica de Programacion III 06-07
8/30
MEMORIA PRCTICA PROGRAMACIN III DIEGO J. SNCHEZ CAAMAO
heurstica h que escoge el nodo ms prometedor mediante la estimacin delnmero de movimientos necesarios. Pero no puede calcular cuntos nodos sedebern 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 dependeen ambos casos del nmero de nodos generados. Por ello calcularemos el coste delprograma con relacin a ese nmero, del que inicialmente slo conocemos suvalor mximo.
Llamando u al nmero total de nodos evaluados, m al nmero de nodos en cadamomento en el montculo y a al de los nodos en el rbol, podemos calcular sisuponemos siempre tres hijos generados:
u
T(u)= 5 +1 +(1 + log m + k1 + 1 + 3 +[3 (k2 + log a)+1]+ 3 log m + log a)+ 1i=1
Entre corchetes se presenta la llamada a la funcin expandir (mximo de tres hijos)
u
T(n)= 7 +(4 log m + k3 + 4 log a)i=1
Intentando una aproximacin mejor, tratemos de relacionarm y a con u.
Las inserciones y comprobaciones en el rbol a, de orden logartmico, se hacentras evaluar cada nodo, por lo que podemos afirmar que a valdr en cada iteracini-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 tantode 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 cadaiteracin. 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 nodosgenerados, tomando como valor mximo u = n2!/2.
6
-
7/28/2019 Memoria de La Practica de Programacion III 06-07
9/30
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, comoen 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 Analizado: Padre Montculo:{ }
Analizados: 2. Coste: 4. Podados: 0. Sin analizar: 3 Analizado: A Montculo:{D, B, C}
Analizados: 3. Coste: 4. Podados: 0. Sin analizar: 4 Analizado: AA Montculo:{AB, D, C, B}
Analizados: 4. Coste: 4. Podados: 0. Sin analizar: 4 Analizado: AAA Montculo:{D, AB, C, B}
Analizados: 5. Coste: 4. Podados: 0. Sin analizar: 5 Analizado:AAAA Mont:{AAAB,D,C,B,AB}Primera solucin encontrada, 4 movimientos. Cota= 4.
Analizados: 6. Coste: 6. Podados: 0. Sin analizar: 4 Analizado: AAAB Montculo: {AB, D, C, B}
Analizados: 7. Coste: 6. Podados: 1. Sin analizar: 3 Analizado: AB Montculo: {B, D, C}
Analizados: 8. Coste: 6. Podados: 2. Sin analizar: 2 Analizado: B Montculo: {C, D}
Analizados: 9. Coste: 6. Podados: 3. Sin analizar: 1 Analizado: C Montculo: { D}
Analizados: 10. Coste: 6. Podados: 4. Sin analizar: 0 Analizado: D Montculo: { }
Mejor solucion encontrada: 4 movimientos.
Tiempo: 0 seg. 0 mils.
Tableros generados: 9. Tableros analizados: 10. Tableros podados: 5.
1 5 2 Nodo padre. Genera cuatro hijos A,B,C,D de coste 4,6,6 y 6, respectivamente.
4 * 3 Tras insertarlos, el montculo es: {A4,B6,C6,D6}
7 8 6
1 * 2 Tras extraer A, el montculo queda: {D6,B6,C6}
4 5 3 A genera dos hijos AA, AB con coste 4 y 6, respectivamente.
7 8 6 Tras insertarlos, el montculo es: {AA4,D6,C6,B6,AB6}
1 2 * Tras extraer AA, el montculo queda: {AB6,D6,C6,B6}
4 5 3 AA genera un hijo AAA de coste 4.
7 8 6 Tras insertarlo, el montculo es: {AAA4,AB6,C6,B6,D6}
1 2 3 Tras extraer AAA, el montculo queda as: {D6,AB6,C6,B6}
4 5 * AAA genera dos hijos AAAA y AAAB, de coste 4 y 6, respectivamente.
7 8 6 Tras insertarlos, el montculo queda as: {AAAA4,D6,C6,B6,AB6,AAAB6}
1 2 3 Tras extraer AAAA, el montculo queda as: {AAAB6,D6,C6,B6,AB6}
4 5 6 Se encuentra AAAA como solucin, la cota pasa a ser 4.
7 8 * Al ir extrayendo los nodos restantes del montculo, no se expanden y se podan por ser
su coste > 4.
7
-
7/28/2019 Memoria de La Practica de Programacion III 06-07
10/30
MEMORIA PRCTICA PROGRAMACIN III DIEGO J. SNCHEZ CAAMAO
3.- ESTUDIO DEL COSTE DEL ALGORITMO.
Atendiendo exclusivamente al algoritmo principal, tomando como operacioneselementales 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)+ 1i=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 principalpublic 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
-
7/28/2019 Memoria de La Practica de Programacion III 06-07
11/30
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); //resolvemos el puzzle
}//fin main
}//fin clase 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 originalNodo 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);
9
-
7/28/2019 Memoria de La Practica de Programacion III 06-07
12/30
MEMORIA PRCTICA PROGRAMACIN III DIEGO J. SNCHEZ CAAMAO
v2=System.currentTimeMillis(); //tomamos el tiempo final
int segundos=(int)(v2-v1)/1000;
int mils=(int)(v2-v1)%1000;
if ((resultado==null)||(!resultado.esSolucion())){
//si RyP devuelve un puzzle no resueltoentrada.presentaPuzzle();
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
}else{ //si est resuelto presentamos la solucin
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 monticulo=new PriorityQueue ();
//montculo para los nodos an sin analizar
ArrayList hijos=new ArrayList(); //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 trabajocota=maxCota=6+5;break;
10
-
7/28/2019 Memoria de La Practica de Programacion III 06-07
13/30
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
-
7/28/2019 Memoria de La Practica de Programacion III 06-07
14/30
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 expandir(Nodo padre,Arbol vistos){
ArrayList lista=new ArrayList ();
//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 Nif ((movPosibles[1])&& (ultimoMov!='N')){ //mov S
12
-
7/28/2019 Memoria de La Practica de Programacion III 06-07
15/30
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')){ //mov E
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')){ //mov O
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
// 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 movimientosint contador=0;
while (contador
-
7/28/2019 Memoria de La Practica de Programacion III 06-07
16/30
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; //almacena los movimientos del hueco
private int colocadas; //n de fichas colocadas
private int movimientos; //n de movimientos realizados
private int coste; //coste de cada nodo
private int datos[]=new int[numCasillas]; //array de int con las piezas
private int posHueco; //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; //para el rbol
// constructorpublic Nodo(){
for (int a= 0;a
-
7/28/2019 Memoria de La Practica de Programacion III 06-07
17/30
MEMORIA PRCTICA PROGRAMACIN III DIEGO J. SNCHEZ CAAMAO
String relleno;
if (numCasillas10 parapresentar el puzzle
}else{
relleno=" ";
}//if numfilas
for (int a=0;a
-
7/28/2019 Memoria de La Practica de Programacion III 06-07
18/30
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 entradapublic 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 filaspublic 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 casillaspublic static void ponerNumCasillas(int casillas){
16
-
7/28/2019 Memoria de La Practica de Programacion III 06-07
19/30
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
-
7/28/2019 Memoria de La Practica de Programacion III 06-07
20/30
MEMORIA PRCTICA PROGRAMACIN III DIEGO J. SNCHEZ CAAMAO
if (posHueco/numFilas>0) {movPosibles[0]=true; //norte
}else movPosibles[0]=false;
if (posHueco/numFilas
-
7/28/2019 Memoria de La Practica de Programacion III 06-07
21/30
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
-
7/28/2019 Memoria de La Practica de Programacion III 06-07
22/30
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
-
7/28/2019 Memoria de La Practica de Programacion III 06-07
23/30
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){ //si no se ha encontrada el nmero
if (t) {
System.out.print("El "+ num + " sin colocar.");
presentaPuzzle();
}//if t
return false; //matriz errnea
}
}//for num
return true;//matriz correcta
}//fin compruebaMatriz
// Repasa toda la tabla y cuenta las fichas colocadaspublic void sumaColocadas(){
int suma=0;
for (int a=0;a 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();
21
-
7/28/2019 Memoria de La Practica de Programacion III 06-07
24/30
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
-
7/28/2019 Memoria de La Practica de Programacion III 06-07
25/30
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 (comp0){ //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
-
7/28/2019 Memoria de La Practica de Programacion III 06-07
26/30
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 ) ;
// Fallo 3= error en archivo de entrada
}
return prueba; //devolvemos un Nodo con los valores de la entrada}
24
-
7/28/2019 Memoria de La Practica de Programacion III 06-07
27/30
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 dimensiona(BufferedReader datosEntrada){
Vector entrada = new Vector ();
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
-
7/28/2019 Memoria de La Practica de Programacion III 06-07
28/30
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 aif (tamanoEntrada
-
7/28/2019 Memoria de La Practica de Programacion III 06-07
29/30
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=Nodo.devuelveMinValor())&&(proximo
-
7/28/2019 Memoria de La Practica de Programacion III 06-07
30/30
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