Sie sind auf Seite 1von 13

JUEGO 8-PUZZLE

Contenido
Estudio de la resolucin de diferentes configuraciones del 8-puzzle con diferentes heursticas .................. 2 8-Puzzle de 6 movimientos ..................................................................................................................... 2 8-Puzzle de 12 movimientos ................................................................................................................... 3 8-Puzzle de 18 movimientos ................................................................................................................... 4 Conclusiones de las pruebas de 8-puzzle .................................................................................................... 5 ALGORITMO DE PUZZLE EN JAVA ............................................................................................................... 6 CODIGO DEL 8-PUZZLE EN LISP ................................................................................................................. 12

JUEGO DEL 8-PUZZLE


Estudio de la resolucin de diferentes configuraciones del 8-puzzle con diferentes heursticas
En la implementacin del 8-Puzzle hemos creado 4 archivos diferentes en cada uno de los cuales se ha utilizado una heurstica diferente: H1 Suma total de fichas descolocadas: heurstica minorante fcil de calcular pero con resultados que distan mucho de ser ptimos. H2 Suma de distancias de Manhatan: heurstica minorante bastante efectiva. En problemas cortos es la que mejores resultados ha obtenido. H3 Suma de secuencias: heurstica no minorante, que en nuestras pruebas no ha demostrado ser excesivamente eficaz. H=H2+2*H3: heurstica no minorante que ha demostrado ser la ms eficaz de la cuatro utilizadas, puesto que aunque en tableros de 8-puzzle con una configuracin ms simple (con menor nmero de movimientos) se ha visto superada por la H2, en tableros con una complejidad elevada (18 movimientos) ha sido capaz de resolver los problemas un numero mucho ms pequeo de nodos.

Para llegar a estas conclusiones nos hemos basado en la resolucin de 3 tableros diferentes de 8-puzzle con una complejidad de 6, 12 y 18 movimientos. En todas ella se pretende llegar a la misma matriz solucin:

8-Puzzle de 6 movimientos
La primera matriz utilizada ha sido la siguiente (el 0 representa la casilla vaca):

Para resolver esta matriz de forma ptima se deben realizar 6 movimientos, los cuales son descritos a continuacin:

Para llegar a este resultado se han tenido que efectuar los 6 movimientos que acabamos de describir y que enumeramos a continuacin: Izquierda, Abajo, Izquierda, Abajo, Derecha, Arriba Todas las heursticas utilizadas llegan a una solucin optima, pero la diferencia principal radica en le cantidad de recursos que necesitan para resolver el problema. Vamos a mostrar las principales diferencias obtenidas en la resolucin del problema con las diferentes heursticas:

8-Puzzle de 12 movimientos
Para la prueba de 12 movimientos hemos utilizado la siguiente matriz:

Para este ejercicio y para el de 18 movimientos, no vamos a escribir las configuraciones de las matrices en la resolucin de este problema pues resultara muy tedioso, pero si que daremos una descripcin optima de los pasos a seguir. Una solucin ptima encontrada para la resolucin de esta matriz de forma ptima es: Arriba, Arriba, Derecha, Abajo, Izquierda, Abajo, Derecha, Arriba, Derecha, Arriba, Izquierda, Abajo. Si hacemos una comparacin entre las diferentes heursticas podremos comprobar que:

8-Puzzle de 18 movimientos
Para la prueba de 18 movimientos hemos utilizado la siguiente matriz:

Una solucin ptima encontrada para la resolucin de esta matriz de forma ptima es: Arriba, Izquierda, Abajo, Derecha, Arriba, Derecha, Abajo, Abajo, Izquierda, Arriba, Izquierda, Arriba, Derecha, Abajo, Derecha, Arriba, Izquierda, Abajo. Si hacemos una comparacin entre las diferentes heursticas podremos comprobar que:

Conclusiones de las pruebas de 8-puzzle


En problemas de complejidad pequea (nmero reducido de movimientos para resolver el problema) la heurstica ms eficaz es la de Manhattan, ya que es capaz de resolver el problema con menor consumo de memoria (utiliza menos nodos). A medida que la que la complejidad del problema va aumentando se va comprobando como la utilizacin de nodos por parte de las diferentes heursticas va aumentando en grandes cantidades. As podemos ver que la utilizacin de nodos resolviendo un problema de 18 movimientos por medio de la heurstica de Mahattan asciende a 5421, mientras que con la utilizacin de una heurstica H2+2H3 el numero de nodos se reduce a 4709. Con las otras 2 heursticas utilizadas el nmero de nodos utilizados es infinitamente mayor a estas 2 ltimas, tanto que es capaz de desbordar la memoria del ordenador impidindose as llegar a solucin alguna. De esta forma queda demostrado que la utilizacin de la heurstica H2+2H3 es la ms efectiva, no solo por la menor utilizacin de nodos, sino porque a la larga es la nica capaz de resolver problemas de este tipo con una complejidad muy elevada utilizando al hacerlo la menor cantidad de recursos posibles.

ALGORITMO DE PUZZLE EN JAVA


/** * * Juego del puzzle en el que hay varias piezas y un hueco. */ import java.util.LinkedList; import java.awt.Point; /** * Juego del puzzle. Mantiene el tablero y permite mover las piezas si el * movimiento es correcto. * Las piezas van de 1 en adelante. El hueco es el 0. */ public class Puzzle { public Puzzle (int numeroFilas, int numeroColumnas) { int i, j; int contador = 1; /* Se comprueban los parmetros de entrada */ if (numeroFilas > 0) this.numeroFilas = numeroFilas; if (numeroColumnas > 0) this.numeroColumnas = numeroColumnas; /* Se crea el array que representa el tablero */ tablero = new int [numeroFilas][numeroColumnas]; /* Se ponen las piezas en la posicin inicial */ for (i=0; i<numeroFilas; i++) for (j=0; j<numeroColumnas; j++) { tablero [i][j] = contador; contador++; } /* Se situa el hueco en la posicin inicial */ tablero [numeroFilas -1][numeroColumnas -1] = HUECO; this.filaHueco = numeroFilas -1; this.columnaHueco = numeroColumnas -1; } /** * Mueve la pieza en fila,columna al hueco. Devuelve true si se * efectuar el movimiento. false si esa pieza no se puede mover * tiene el hueco al lado o porque se da una fila,columna fuera * tablero. */ public boolean mueve (int fila, int columna) { /* Se comprueba que las coordenadas caen dentro del tablero if (!compruebaCoordenadas(fila, columna)) return false;

ha podido porque no del

*/

/* Si no es la primera fila, se mira a ver si el hueco est encima * de la pieza */ if (fila != 0) if (tablero[fila-1][columna] == HUECO) { /* Se hace el movimiento de la pieza a la fila superior */ mueve (fila, columna, fila-1, columna); return true; }

/* Si la fila no es la litma, se mira a ver si el hueco est en la * fila de abajo de la pieza */ if (fila != (numeroFilas -1)) if (tablero[fila+1][columna] == HUECO) { /* Se hace el movimiento hacia abajo */ mueve (fila, columna, fila+1, columna); return true; } /* Si la columna no es la de la izquierda, se mira a ver si el hueco * est a la izquierda de la pieza */ if (columna != 0) if (tablero[fila][columna-1] == HUECO) { /* Se hace el movimiento hacia la izquierda */ mueve (fila, columna, fila, columna-1); return true; } /* Si la columna no es la de la derecha del todo, se mira a ver si el * hueco est a la derecha de la pieza */ if (columna != (numeroColumnas-1)) if (tablero[fila][columna+1] == HUECO) { /* Se hace el movimiento hacia la derecha */ mueve (fila, columna, fila, columna+1); return true; } /* Si se llega hasta aqu, es que la pieza no tiene el hueco alrdedor y * por tanto no se puede mover */ return false; } /** * Devuelve la pieza que est en la fila, columna indicadas. -1 si * fila,columna est fuera del tablero. */ public int damePieza (int fila, int columna) { /* Si fila,columna no est dentro del tablero, se devuelve -1 */ if (!compruebaCoordenadas (fila, columna)) return -1; /* Se devuelve la pieza en fila,columna */ return tablero[fila][columna]; } /** * Aade el observador que se le pasa a la lista de observadores. */ public void anhadeObservador (ObservadorMovimiento nuevoObservador) { if (nuevoObservador != null) observadores.add (nuevoObservador); } /** * Se elimina el observador que se le pasa de la lista de observadores */ public void quitaObservador (ObservadorMovimiento unObservador) { if (unObservador != null) { observadores.remove (unObservador); }

} /** * Devuelve el nmero de filas del tablero */ public int dameFilas() { return numeroFilas; } /** * Devuelve el nmero de columnas del tablero */ public int dameColumnas() { return numeroColumnas; } /** * Devuelve el numero de piezas que se pueden mover. */ public int dameNumeroPosiblesMovimientos() { int numeroPosiblesMovimientos = 4; /* * * if Si el hueco est en la primera fila o en la ltima fila, hay un movimiento menos. No se puede mover la pieza desde fuera del tablero. */ ((this.filaHueco == 0) || (this.filaHueco == numeroFilas-1)) numeroPosiblesMovimientos--;

/* Idem si es primera o ltima columna */ if ((this.columnaHueco == 0) || (this.columnaHueco == numeroColumnas-1)) numeroPosiblesMovimientos--; return numeroPosiblesMovimientos; } /** * Devuelve un array con las posiciones de las piezas que se pueden mover. */ public Casilla[] damePosiblesMovimientos () { /* Array auxiliar para poner las posiciones de las piezas que se pueden * mover y devolverlo */ Casilla [] aux = new Casilla[dameNumeroPosiblesMovimientos()]; int i=0; /* Si el huecho no esta en la primera fila, se puede bajar la pieza que * est encima del hueco. */ if (this.filaHueco != 0) { aux[i] = new Casilla (this.filaHueco-1, this.columnaHueco); i++; } /* Si el hueco no est en la ltima fila, se puede subir la pieza que * est debajo del hueco. */ if (this.filaHueco != (numeroFilas -1)) { aux[i] = new Casilla (this.filaHueco+1, this.columnaHueco); i++; } /* si el hueco no est en la primera columna, se puede mover la pieza * que est a la izquierda del hueco. */

if (this.columnaHueco != 0) { aux[i] = new Casilla (this.filaHueco, this.columnaHueco-1); i++; } /* Si el hueco no est en la ltima columna, se puede mover la pieza * que est a la derecha del hueco */ if (this.columnaHueco != (numeroColumnas -1)) { aux[i] = new Casilla (this.filaHueco, this.columnaHueco+1); i++; } return aux; } /** * Devuelve true si el puzzle est ordenado. false en caso contrario. * * Se inicializa un contador con el valor de pieza 1, que debe estar en * la posicin 1,1. Se incrementa el contador y se pasa a la siguiente * casilla. Comparando el contador con el contenido de la casilla, se sabe * si el puzzle est ordenado. */ public boolean estaOrdenado() { /* Para recorrer el tablero */ int fila, columna; /* Para ver la pieza que toca en cada casilla */ int contador = 1; /* Bucle doble para cada fila y columna, recorriendo as todo el * tablero */ for (fila=0; fila < numeroFilas; fila++) for (columna=0; columna < numeroColumnas; columna++) { /* Tratamiento especial para el hueco en la ltima posicin * del tablero. Si hemos llegado hasta la ltima posicin del * tablero, todas las dems piezas estn en su sitio. La ltima * posicin estar ocupada por el hueco (el 0) y no por la pieza * nmero filas*columnas, que no existe. */ if (contador == numeroFilas*numeroColumnas) return true; /* Si la pieza no es la que debe, se devuelve false */ if (tablero[fila][columna] != contador) return false; /* Se pone en contador el valor de la siguiente pieza del * del puzzle */ contador++; } /* Si se llega hasta aqu, el puzzle est ordenado */ return true; } /** * Mueve una pieza al hueco. Presupone que los parmetros que se le pasan * son correctos y no los verifica. * Notifica del movimiento a los observadores de movimiento de piezas. * Verifica si el puzzle ya est ordenado para avisar a los observadores. */ private void mueve (int fila, int columna, int filaHueco, int columnaHueco) { /* Se realiza el movimiento */

tablero [filaHueco][columnaHueco] = tablero[fila][columna]; tablero [fila][columna] = HUECO; /* Se actuliazan las variables que mantienen la posicin actual del * hueco */ this.filaHueco=fila; this.columnaHueco=columna; /* Notifica del movimiento a los suscriptores de movimientos de pieza */ notificaMovimiento (fila, columna, filaHueco, columnaHueco); /* Verifica si est ordenado para notificar a los suscriptores de * tablero ordenado */ if (estaOrdenado()) notificaOrdenado(); } /** * Notifica a los suscriptores el movimiento de una pieza. */ private void notificaMovimiento ( int filaVieja, int columnaVieja, int filaNueva, int columnaNueva) { int i; /* Variable auxiliar para hacer el cast ms cmodo */ ObservadorMovimiento aux; /* Bucle para cada observador */ for (i=0; i<observadores.size(); i++) { aux =(ObservadorMovimiento)observadores.get(i); /* Se notifica el movimiento */ aux.tomaMovimiento ( filaVieja, columnaVieja, filaNueva, columnaNueva); } } /** * Notifica a los observadores que el puzzle est ordenado */ private void notificaOrdenado() { int i; /* Variable auxiliar para hacer ms cmodo el cast */ ObservadorMovimiento aux; /* Bucle para cada observador */ for (i=0; i<observadores.size(); i++) { aux =(ObservadorMovimiento)observadores.get(i); /* Se notifica que est ordenado */ aux.ordenado(); } } /** * Devuelve true si la fila,columna cae dentro del tablero. false en * caso contario */ private boolean compruebaCoordenadas (int fila, int columna) { // Si la fila, columna no es del tablero, se devuelve false y no se // hace nada. if ( (fila < 0) || (fila >= numeroFilas) || (columna < 0) || (columna >=numeroColumnas))

return false; return true; } /** Nmero de filas del puzzle. Por defecto 3 */ private int numeroFilas = 3; /** Nmero de columnas del puzzle. Por defecto 3 */ private int numeroColumnas = 3; /** Array bidimensional que representa el tablero. Las piezas sern enteros * 1, 2, 3, etc. El Hueco es el 0 */ private int [][] tablero; /* Fila en la que est el hueco */ private int filaHueco; /* Columna en la que est el hueco */ private int columnaHueco; /** Entero que representa el hueco en el puzzle */ static public final int HUECO=0; /** Lista de observadores */ private LinkedList observadores = new LinkedList(); }

CODIGO DEL 8-PUZZLE EN LISP


(defparameter *goal-state* (make-array '(3 3) :initial-contents '((1 2 3)(4 5 6)(7 8 space)))) (defun copy-board(board) (let ((new-board (make-array '(3 3)))) (loop for i from 0 to 2 do (loop for j from 0 to 2 do (setf (aref new-board i j) (aref board i j) ))) new-board)) (defun print-board(board) (format t "~%-------") (loop for i from 0 to 2 do (format t "~%|") (loop for j from 0 to 2 do (format t "~A|" (if (eq (aref board i j) 'space) "" (aref board i j)))) (format t "~%-------"))) (defun find-square(x board) "return a list with the x y coordinates of the piece x in board" (loop for i from 0 to 2 thereis (loop for j from 0 to 2 thereis (when (eq (aref board i j) x) (list i j))))) (defun move-up(state) (let* ((at-space (find-square 'space state)) (i (first at-space)) (j (second at-space)) (new-state (copy-board state))) (when (> i 0) (setf (aref new-state i j) (aref new-state (- i 1) j)) (setf (aref new-state (- i 1) j) 'space) new-state))) (defun move-down(state) (let* ((at-space (find-square 'space state)) (i (first at-space)) (j (second at-space)) (new-state (copy-board state))) (when (< i 2) (setf (aref new-state i j) (aref new-state (+ i 1) j)) (setf (aref new-state (+ i 1) j) 'space) new-state))) (defun move-left(state) (let* ((at-space (find-square 'space state)) (i (first at-space)) (j (second at-space)) (new-state (copy-board state))) (when (> j 0) (setf (aref new-state i j) (aref new-state i (- j 1))) (setf (aref new-state i (- j 1)) 'space) new-state)))

(defun move-right(state) (let* ((at-space (find-square 'space state)) (i (first at-space)) (j (second at-space)) (new-state (copy-board state))) (when (< j 2) (setf (aref new-state i j) (aref new-state i (+ j 1))) (setf (aref new-state i (+ j 1)) 'space) new-state)))

(defun random-move(state) "randomly pick one of 4 operators. If it returns nil, choose again" (let ((r (random 4))) (or (cond ((= r 0)(move-left state)) ((= r 1) (move-right state)) ((= r 2) (move-up state)) ((= r 3) (move-down state))) (random-move state)))) (defun random-moves (n state) "make N random moves" (loop for i from 1 to n do (setq state (random-move state))) state) (defparameter *start-state* (random-moves 20 *goal-state*)) (defun solution-state?(state) "A state description is the solution if it matches the goal state" (equalp state *goal-state*)) (defparameter *eight-puzzle-operators* '(move-up move-down move-left move-right)) (defun estimated-distance-from-goal (board) "Compute Manhattan distance for each tile (except space)" (loop for i from 1 to 8 summing (manhattan-distance (find-square i board) (find-square i *goal-state*)))) (defun manhattan-distance (p1 p2) "given two lists of x-y coords, sum the difference between x's and y's" (+ (abs (- (first p1) (first p2))) (abs (- (second p1) (second p2))))) (defun cost-of-applying-operator (state operator) 1)

Das könnte Ihnen auch gefallen