Memoria de La Practica de Programacion III 06-07

download Memoria de La Practica de Programacion III 06-07

of 30

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