Vous êtes sur la page 1sur 22

PROYECTO PUZZLE 8

INVESTIGACIÓN DE OPERACIONES II

DDDDD
ING. VILLEGAS CUBAS JUAN
2018
UNIVERSIDAD NACIONAL
PEDRO RUIZ GALLO
FACULTAD DE INGENIERA CIVIL, SISTEMAS Y
ARQUITECTURA

INVESTIGACIÓN DE OPERACIONES

ALUMNOS:
-CUMPA QUESQUEN EDGARD

-GUEVARA PANTA, JUAN FRANCISCO

-SALAZAR VILLANUEVA KEVIN

-VELÁSQUEZ CAJUSOL ALEX

LAMBAYEQUE, DICIEMBRE 2017


ÍNDICE
Historia del Juego ................................................................................................................................ 1
La fiebre del taken ....................................................................................................................... 1
Modo de Juego .................................................................................................................................... 1
8-Puzzle de 6 movimientos ................................................................................................................. 2
8-Puzzle de 12 movimientos ............................................................................................................... 3
8-Puzzle de 18 movimientos ............................................................................................................... 4
ALGORITMO DE PUZZLE EN JAVA ........................................................................................................ 5
CONCLUSIONES ................................................................................................................................. 17
TABLAS

TABLA 1 PUZZLE 8 , 6 MOVIMIENTOS................................................................................................................. 3


TABLA 2 PUZZLE 8 , 12 MOVIMIENTOS............................................................................................................... 3
TABLA 3 PUZZLE 8 , 16 MOVIMIENTOS............................................................................................................... 4
PUZZLE 8

Historia del Juego


El juego ha sido durante mucho tiempo atribuido a Samuel Loyd en Estados Unidos a fines
de la década de 1870. Sin embargo, hay fuentes que dicen que su verdadero autor fue
Noyes Palmer Chapman.12
La fiebre del taken
Entre 1880 y 1882, el juego del 15 se convirtió en una verdadera plaga social que se
extendió por Estados Unidos y Europa. Sin embargo en 1882, se descubrió que de todos los
problemas propuestos en el juego, sólo la mitad tenían solución. En los periódicos se
publicaron anuncios de recompensas a quien resolviera por lo menos uno de los problemas
insolucionables y diversos diarios neoyorquinos ofrecieron 1.000 dólares al resolutor. Nadie
ganó el premio. El juego acabó por desilusionar a la población y con ello terminó la fiebre
del taken.

Modo de Juego
En la Implementación del 8-Puzzle hemos creado 4 archivos diferentes en cada uno de los
cuales se ha utilizado una heurística diferente:
% H1 ó Suma total de fichas descolocadas: heurística minorante fácil de calcular pero con
resultados que distan mucho de ser óptimos.
% H2 ó Suma de distancias de Manhattan: heurística minorante bastante efectiva. En
problemas cortos es la que mejores resultados ha obtenido.
% H3 ó Suma de secuencias: heurística no minorante, que en nuestras pruebas no ha
demostrado ser excesivamente eficaz.
% H=H2+2*H3: heurística no minorante que ha demostrado ser la más eficaz de la cuatro
utilizadas, puesto que aunque en tableros de 8-puzzle con una configuración más simple
(con menor número 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 más pequeño de nodos.

[1]
Para llegar a estas conclusiones nos hemos basado en la resolución 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 solución:

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

Para resolver esta matriz de forma óptima se deben realizar 6 movimientos, los cuales son

descritos a continuación:

Para llegar a este resultado se han tenido que efectuar los 6 movimientos que acabamos
[2]
de describir y que enumeramos a continuación:
Izquierda, Abajo, Izquierda, Abajo, Derecha, Arriba
Todas las heurísticas utilizadas llegan a una solución 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 resolución del problema con las
diferentes heurísticas:

H1 =5 N° de movimientos = 6 Nodos generados =21


H2 =6 N° de movimientos = 6 Nodos generados =18
H3 =11 N° de movimientos = 6 Nodos generados =20
H= H2+ 2H3 = 28 K" de movimientos = 6 Nodos generados = 8
Tabla 1 PUZZLE 8 , 6 MOVIMIENTOS

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 resolución de este problema pues resultaría muy tedioso, pero si
que daremos una descripción optima de los pasos a seguir.
Una solución óptima encontrada para la resolución de esta matriz de forma óptima es:

Arriba, Arriba, Derecha, Abajo, Izquierda, Abajo, Derecha, Arriba, Derecha, Arriba,

Izquierda, Abajo.

Si hacemos una comparación entre las diferentes heurísticas podremos comprobar que:

H1 =6 N° de movimientos = 12 Nodos generados =917


H2 =10 N° de movimientos = 12 Nodos generados =38
H3 =15 N° de movimientos = 12 Nodos generados =101
H= H2+ 2H3 = 40 N° de movimientos = 12 Nodos generados = 40
Tabla 2 PUZZLE 8 , 12 MOVIMIENTOS

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

Una solución óptima encontrada para la resolución 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 comparación entre las diferentes heurísticas podremos comprobar que:

H1 =5 N° de movimientos = ¿? Nodos generados =¿?


H2 =10 N° de movimientos = 18 Nodos generados =5421
H3 =14 N° de movimientos = ¿? Nodos generados =¿?
H= H2+ 2H3 = 38 N° de movimientos = 18 Nodos generados =4709
Tabla 3 PUZZLE 8 , 16 MOVIMIENTOS

[4]
ALGORITMO DE PUZZLE EN JAVA

package puzzleJAVA;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.ImageIcon;
import javax.swing.JOptionPane;
import pieza.btnPieza;

public class Game implements ActionListener{

private String game="game2";


private int fila = 3;
private int columna = 3;
//posicion ganador del juego
//Posicion ganadora "game1"
//private int[] win = {1,2,3,4,5,6,7,8,-1}; // -1 = casilla vacia
//Posicion ganadora "game2"
private int[] win = {1,2,3,4,5,6,-1,8,9}; // -1 = casilla vacia
//array para controlar el desarrollo del juego
private int[] pos_juego = new int[win.length];
//matriz de controles
/* 0 | 1 | 2
*3|4|5
*6|7|8
*/
private btnPieza matriz[] = new btnPieza[ fila * columna ];

public Game()
{
System.out.println("Creado por jc-Mouse");
}

//carga imagenes de nuevo juego


public void NewGame(btnPieza m[])
{
this.matriz = m;
llenar_tablero(win, true);
}
[5]

//Inicia el juego
public void Comenzar()
{
//habilita controles
for ( int i=0; i < win.length; i++ )
matriz[i].setEnabled(true);
//desordena puzzle
int[] tmp = win;
int count = 0;
int numRandom;
for ( int i=0; i < pos_juego.length ; i++ )
pos_juego[i]=0;
do{
//obtiene numero aleatorio
numRandom = (int)( Math.random() * win.length );
//Si elemento en la posicion de numRandom es diferente de 0
if( pos_juego[numRandom]== 0)
{
pos_juego[numRandom] = tmp[count];
count++;
}
}while( count < pos_juego.length);

llenar_tablero(pos_juego,false);
}

//Finaliza el juego :)
public void Terminar()
{
for ( int i=0; i < win.length; i++ )
{
matriz[i].setDisabledIcon( new ImageIcon(getClass().getResource("/pieza/rec/logo.jpg")) );
matriz[i].setEnabled(false);
}
}

//Llena la matriz de controles con imagenes dado un array numerico con las posiciones de las mismas
¿se entendio?
private void llenar_tablero(int[] m , boolean band)
{
for ( int i=0; i < win.length; i++ )
{
if( m[i] > -1 )
{
matriz[i].setIcon( new ImageIcon(getClass().getResource("/puzzle/"+ game +"/" + m[i] + ".jpg")) [6]
);
matriz[i].setDisabledIcon( new ImageIcon(getClass().getResource("/puzzle/"+ game +"/" + m[i] +
".jpg")) );
}
else if (band)
{
matriz[i].setIcon( new ImageIcon(getClass().getResource("/puzzle/"+ game +"/" + (i+1) + ".jpg"))
);
matriz[i].setDisabledIcon( new ImageIcon(getClass().getResource("/puzzle/"+ game +"/" + (i+1) +
".jpg")) );
}
else
{
matriz[i].setIcon( new ImageIcon(getClass().getResource("/pieza/rec/vacio.jpg")) );
matriz[i].setDisabledIcon( new ImageIcon(getClass().getResource("/pieza/rec/vacio.jpg")) );
}
}
}

public int getFila(){ return this.fila;}


public int getColumna() { return this.columna;}

//Atento a las acciones del usuario


public void actionPerformed(ActionEvent ev) {
//Captura en String el comando accionado por el usuario
String comando = ev.getActionCommand();

//Calcula posiciones de casillas vecinas y realiza movimiento


/* a | b | c
*d|_|e
*f|g|h
*/
int[] pos = new int[8];
if( Integer.valueOf(comando)== columna-1 )//esquina superior derecha
{
pos[0] = -1;
pos[1] = -1;
pos[2] = -1;
pos[3] = Integer.valueOf(comando) - 1 ;
pos[4] = -1;
pos[5] = Integer.valueOf(comando) + ( columna - 1);
pos[6] = Integer.valueOf(comando) + columna;
pos[7] = -1;
}
else if(Integer.valueOf(comando) == (fila * columna - columna))//esquina inferior izquierda [7]
{
pos[0] = -1;
pos[1] = Integer.valueOf(comando) - columna;
pos[2] = Integer.valueOf(comando) - (columna - 1 );
pos[3] = -1;
pos[4] = Integer.valueOf(comando) + 1;
pos[5] = -1;
pos[6] = -1;
pos[7] = -1;
}
else if(Integer.valueOf(comando) == (fila * columna - 1) )//esquina inferior derecha
{
pos[0] = Integer.valueOf(comando) - ( columna + 1 );
pos[1] = Integer.valueOf(comando) - columna;
pos[2] = -1;
pos[3] = Integer.valueOf(comando) - 1 ;
pos[4] = -1;
pos[5] = -1;
pos[6] = -1;
pos[7] = -1;
}
else if(Integer.valueOf(comando)%columna == 0 )//primera columna
{
pos[0] = -1;
pos[1] = Integer.valueOf(comando) - columna;
pos[2] = Integer.valueOf(comando) - (columna - 1 );
pos[3] = -1;
pos[4] = Integer.valueOf(comando) + 1;
pos[5] = -1;
pos[6] = Integer.valueOf(comando) + columna;
pos[7] = Integer.valueOf(comando) + (columna + 1);
}
else if( (Integer.valueOf(comando)+1)%columna == 0 )//ultima columna
{
pos[0] = Integer.valueOf(comando) - ( columna + 1 );
pos[1] = Integer.valueOf(comando) - columna;
pos[2] = -1;
pos[3] = Integer.valueOf(comando) - 1 ;
pos[4] = -1;
pos[5] = Integer.valueOf(comando) + ( columna - 1);
pos[6] = Integer.valueOf(comando) + columna;
pos[7] = -1;
}
else //cualquier otra casilla
{
pos[0] = Integer.valueOf(comando) - ( columna + 1 ); [8]
pos[1] = Integer.valueOf(comando) - columna;
pos[2] = Integer.valueOf(comando) - (columna - 1 );
pos[3] = Integer.valueOf(comando) - 1 ;
pos[4] = Integer.valueOf(comando) + 1;
pos[5] = Integer.valueOf(comando) + ( columna - 1);
pos[6] = Integer.valueOf(comando) + columna;
pos[7] = Integer.valueOf(comando) + (columna + 1);
}
//realiza el movimiento
for ( int i=0; i < pos.length ; i++ )
if( mover( pos[i] , Integer.valueOf(comando) ) )
break;
//vuelve a pintar las imagenes
llenar_tablero(pos_juego,false);
//Movimientos de las casillas en el juego
//for ( int i=0; i < game.length ; i++ )
// System.out.print( game[i] + "," );
//System.out.println( );
//despues de cada movida reviza si las casillas estan ordenadas
if( gano() )
{
llenar_tablero(win,true);
JOptionPane.showMessageDialog(null, "Muchas Felicidades. Usted Ganó");
Terminar();
}
}

private boolean mover(int value, int index)


{
int tmp;
//si posicion existe dentro del array
if( value >=0 && value < fila*columna )
{
//si casilla esta vacia -> realiza el cambio
if( pos_juego[value] == -1 )
{
tmp = pos_juego[value];
pos_juego[value]=pos_juego[index];
pos_juego[index]=tmp;
return true;
}
}
return false;
}
//funcion que recorre el array de juego y de movidas para determinar si son iguales
private boolean gano() [9]
{
for ( int i=0; i < win.length ; i++ )
{
if( win[i]!=pos_juego[i])
return false;
}
return true;
}
}

[10]
package puzzleJAVA;

public class Main {

public static void main(String[] args) {


new frmPrincipal().setVisible(true);
}

[11]
package puzzleJAVA;
import pieza.btnPieza;

public class frmPrincipal extends javax.swing.JFrame {


//variables
private Game juego = new Game();
private btnPieza matriz[] = new btnPieza[ juego.getFila() * juego.getColumna() ];

/** Creates new form frmPrincipal */


public frmPrincipal() {
initComponents();
this.setLocationRelativeTo(null);
this.setTitle("Puzzle Java");
//tablero
this.jpCuerpoPuzzle.setSize(600, 450);
this.jpCuerpoPuzzle.setLayout(new java.awt.GridLayout(juego.getFila(), juego.getColumna(), 0,
0));//alineacion
construir_matriz();
this.repaint();
this.menuPlay.setEnabled(false);
this.menuEnd.setEnabled(false);
}

private void construir_matriz(){


for ( int i=0; i < (juego.getFila()*juego.getColumna()); i++ )
{
matriz[i] = new btnPieza();//Se crea la pieza
matriz[i].setActionCommand( String.valueOf(i) );//se añade un nombre de accion
matriz[i].addActionListener(juego);
matriz[i].setEnabled(false);
this.jpCuerpoPuzzle.add(matriz[i]);//se añade al tablero
}
}

@SuppressWarnings("unchecked")
// <editor-fold defaultstate="collapsed" desc="Generated Code">
private void initComponents() {

jpCuerpoPuzzle = new javax.swing.JPanel();


menu = new javax.swing.JMenuBar();
jMenu1 = new javax.swing.JMenu();
menuNewGame = new javax.swing.JMenuItem(); [12]
menuPlay = new javax.swing.JMenuItem();
menuEnd = new javax.swing.JMenuItem();
jMenu2 = new javax.swing.JMenu();

setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);

jpCuerpoPuzzle.setBorder(javax.swing.BorderFactory.createLineBorder(new java.awt.Color(0, 0,
0)));
/*
Programador: jc Mouse
Pais: Bolivia
*/

javax.swing.GroupLayout jpCuerpoPuzzleLayout = new javax.swing.GroupLayout(jpCuerpoPuzzle);


jpCuerpoPuzzle.setLayout(jpCuerpoPuzzleLayout);
jpCuerpoPuzzleLayout.setHorizontalGroup(
jpCuerpoPuzzleLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGap(0, 384, Short.MAX_VALUE)
);
jpCuerpoPuzzleLayout.setVerticalGroup(
jpCuerpoPuzzleLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGap(0, 318, Short.MAX_VALUE)
);

jMenu1.setText("Archivo");

menuNewGame.setText("Nuevo Juego");
menuNewGame.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
menuNewGameActionPerformed(evt);
}
});
jMenu1.add(menuNewGame);

menuPlay.setText("Jugar");
menuPlay.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
menuPlayActionPerformed(evt);
}
});
jMenu1.add(menuPlay);

menuEnd.setText("Terminar");
menuEnd.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
menuEndActionPerformed(evt); [13]
}
});
jMenu1.add(menuEnd);

menu.add(jMenu1);

jMenu2.setText("Ayuda");
menu.add(jMenu2);

setJMenuBar(menu);

javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());


getContentPane().setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addComponent(jpCuerpoPuzzle, javax.swing.GroupLayout.PREFERRED_SIZE,
javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addContainerGap(222, Short.MAX_VALUE))
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addComponent(jpCuerpoPuzzle, javax.swing.GroupLayout.PREFERRED_SIZE,
javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addContainerGap(136, Short.MAX_VALUE))
);

pack();
}// </editor-fold>

private void menuNewGameActionPerformed(java.awt.event.ActionEvent evt) {


juego.NewGame(matriz);
this.menuPlay.setEnabled(true);
this.menuNewGame.setEnabled(false);
}

private void menuPlayActionPerformed(java.awt.event.ActionEvent evt) {


juego.Comenzar();
this.menuPlay.setEnabled(false);
this.menuNewGame.setEnabled(false);
this.menuEnd.setEnabled(true);
}

private void menuEndActionPerformed(java.awt.event.ActionEvent evt) {


juego.Terminar(); [14]
this.menuNewGame.setEnabled(true);
this.menuPlay.setEnabled(false);
this.menuEnd.setEnabled(false);
}

/**
* @param args the command line arguments
*/
public static void main(String args[]) {
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
new frmPrincipal().setVisible(true);
}
});
}

// Variables declaration - do not modify


private javax.swing.JMenu jMenu1;
private javax.swing.JMenu jMenu2;
private javax.swing.JPanel jpCuerpoPuzzle;
private javax.swing.JMenuBar menu;
private javax.swing.JMenuItem menuEnd;
private javax.swing.JMenuItem menuNewGame;
private javax.swing.JMenuItem menuPlay;
// End of variables declaration

[15]
package pieza;
import java.awt.Dimension;
import javax.swing.Icon;
import javax.swing.ImageIcon;

public class btnPieza extends javax.swing.JButton {

private Icon image1 = new ImageIcon(getClass().getResource("/pieza/rec/logo.jpg"));

public btnPieza()
{
this.setPreferredSize(new Dimension(200,150));
this.setContentAreaFilled(false);
this.setBorder(javax.swing.BorderFactory.createEmptyBorder(1, 1, 1, 1));
this.setIcon(image1);
this.setDisabledIcon(image1);
this.setVisible(true);
}

[16]
CONCLUSIONES
En problemas de complejidad pequeña (número reducido de movimientos para resolver el problema) la heurística
más 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 utilización de
nodos por parte de las diferentes heurísticas va aumentando en grandes cantidades. Así podemos ver que la
utilización de nodos resolviendo un problema de 18 movimientos por medio de la heurística de Mahattan asciende
a 5421, mientras que con la utilización de una heurística H2+2H3 el numero de nodos se reduce a 4709. Con las
otras 2 heurísticas utilizadas el número de nodos utilizados es infinitamente mayor a estas 2 últimas, tanto que
es capaz de desbordar la memoria del ordenador impidiéndose así llegar a solución alguna.

De esta forma queda demostrado que la utilización de la heurística H2+2H3 es la más efectiva, no solo por la
menor utilización 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.

[17]

Vous aimerez peut-être aussi