Integrantes: Maritza Echeverri Hernández cod :200010156010
Rafael Arango S cod :200020019010
Andrés Emilio Arbelaez Velasques cod :200129400010
Mauricio Muños cod:200029422010
PROBLEMA:
Imagínese que está en medio de un laberinto bidimensional compuesto por celdas cuadradas las cuales pueden o no estar llenas de roca.

Se puede mover hacia el norte, sur, este u oeste una celda cada vez. Estos movimientos son llamados "paseos".
Una de las celdas vacías contiene una caja que puede moverse a una celda adyacente, colocándose al lado de la caja y luego moviéndose en la dirección en que se encuentra la caja. Tal movimiento es llamado un "empuje". No hay otra forma de mover la caja, diferente de "empujes". Esto quiere decir que si usted empuja la caja hacia una esquina, no habrá manera de sacarla de allí.
Una de las celdas vacías está marcada como "Objetivo". Su tarea es llevar la caja a la celda objetivo mediante una serie de "paseos" y "empujes". La caja es muy pesada, así que es conveniente minimizar el número de "empujes". ¿Puede usted escribir un programa que encuentre una secuencia para lograr el objetivo?
Entrada
El archivo de entrada contiene las descripciones de varios laberintos. Cada una de ellas empieza con una línea que contiene dos enteros f y c que representan respectivamente el número de filas y columnas del laberinto.
A continuación vienen f líneas cada una de las cuales contiene c caracteres. Cada carácter describe una celda del laberinto. Una celda llena de roca se indica con un ´#´ y una celda vacía, con un ´.´. Su punto de arranque se indica con una ´S´, el punto de arranque de la caja con una ´B´ y la celda objetivo con una ´T´.El final de la entrada se indica mediante una línea contiene dos ceros para f y c
Salida
Para cada laberinto en la entrada, imprima primero el número del laberinto, como se muestra en el ejemplo. Luego, si es imposible llevar la caja a la celda objetivo, imprima "Imposible".Si no (es decir, si es posible) imprima la secuencia que lleva a la solución. Imprima la secuencia como una cadena de caracteres N, S, E, O, n, s, e, o, donde las letras en mayúscula indican "empujes" y las minúsculas, "paseos" en la dirección correspondiente (norte, sur, este, oeste).Deje una línea en blanco entre caso y caso de prueba. El formato de salida DEBE estar de acuerdo con la descripción dada.
Ejemplo de entrada:
1 7
SB....T
1 7
SB..#.T
7 11
###########
#T##......#
#.#.#..####
#....B....#
#.######..#
#.....S...#
###########
8 4
....
.##.
.#..
.#..
.#.B
.##S
....
###T
0 0
Salida Correspondiente
Laberinto #1
EEEEE
Laberinto #2
Imposible
Laberinto #3
eennooOOOOeeeeeessooooooonNN
Laberinto #4
sooonnnnnneeesssSSS
Los diferentes análisis que hemos realizado respecto al juego son:
Hicimos un análisis detenido del juego, de las posiciones de la caja, la roca, el objetivo, y el que la corre.































































Determinamos
que la persona que realiza los empujes primero debía buscar el
objetivo y determinar el camino mas viable para empezar a empujar.

Determinamos que este método para llegar al objetivo no es del todo perfecto, por lo tanto ahora estamos pensando en el modelo anterior y en el siguiente que se trata de:
El Miércoles 8 de Agosto:
La idea en base a la anterior es generar un buscador, en este caso seria la carita feliz( el que hace los empujes), que primero mire que hay delante de la caja y que este pendiente de que no hallan esquinas, para esto siempre tendrá que mirar si la caja este próxima a tres cuadros (esquina).
También, que la carita feliz( el que hace los empujes) busque primero la caja y a partir de ahí que busque el camino para los dos tanto para la caja como para el que da los empujes. Otro elemento que esta aun en análisis es que medida que el que empuja la caja vaya checando los muros que tiene de forma paralela.














Checa las esquinas





Checa los lados
Hoy decidimos tomar el problema desde otro punto de vista y complementarlo:
Decidimos tomar el laberinto vació de esta forma:
# # # # # # # # # # # #
# . . . # . . . . . . #
. . # . # . # # # # . #
# # # . # . . . . # . #
# . . . . # # # . # . .
# # # # . # . # . # . #
# . . # . # . # . # . #
# # . # . # . # . # . #
# . . . . . . . . # . #
# # # # # # . # # # . #
# . . . . . . # . . . #
# # # # # # # # # # # #
tomarlo como un arreglo de doble subíndice, elaboramos una algoritmo de recorrido que nos va ha garantizar la salida de el.
Que cheque a lado y lado los muros para poder moverse y así poder llegar a la meta final.
También que nunca se despegue de la pared y así llegara a la salida.
También a medida que avance marque el camino para así saber por donde esta andando.
Ya tomando el laberinto lleno es utilizaríamos el mismo recurso de no despegarnos de la pared e ir marcando el camino, buscar la caja , a partir de la caja dejarla allí y buscar el objetivo, después devolvernos y empezar a empujar la caja.
Hasta llevarla a la salida.
Por que cuando encontramos la caja marcamos el camino de ahí hasta la salida entonces cuando se devuelva a buscarla para empujarla ya sabrá por donde es el camino por que ya lo había dejado marcado.
Implementación del problema en lenguaje. C++
codigo prealfa 1
#include <iostream.h>
#include <conio.h>
#include <stdlib.h>
#include <iomanip.h>
class Sokoban{
public:
Sokoban(){}
char** construirLaberinto1();
char** construirLaberinto2();
//char** construirLaberinto3();
void solucionLaberinto(int, char**);
};
char** Sokoban :: construirLaberinto1()
{
char matriz [10][12];
int fila=0;
while (fila < 10)
{
int columna=0;
while ( columna < 12)
{
matriz [0][columna]= '#';
matriz [9][columna]='#';
if ( columna==0 )
{
matriz [fila][0]= '#';
matriz [fila][11]= '#';
}
columna++;
}
fila++;
}
matriz [1][1]='#';
matriz [1][2]='#';
matriz [1][3]='#';
matriz [1][4]='.';
matriz [1][5]='.';
matriz [1][6]='.';
matriz [1][7]='.';
matriz [1][8]='.';
matriz [1][9]='#';
matriz [1][10]='#';
matriz [2][1]='#';
matriz [2][2]='#';
matriz [2][3]='#';
matriz [2][4]='.';
matriz [2][5]='#';
matriz [2][6]='#';
matriz [2][7]='#';
matriz [2][8]='.';
matriz [2][9]='.';
matriz [2][10]='.';
matriz [3][1]='#';
matriz [3][2]='#';
matriz [3][3]='#';
matriz [3][4]='S'; //Posición donde usted se encuentra
matriz [3][5]='#';
matriz [3][6]='#';
matriz [3][7]='#';
matriz [3][8]='.';
matriz [3][9]='#';
matriz [3][10]='.';
matriz [4][1]='#';
matriz [4][2]='#';
matriz [4][3]='#';
matriz [4][4]='#';
matriz [4][5]='#';
matriz [4][6]='#';
matriz [4][7]='#';
matriz [4][8]='.';
matriz [4][9]='#';
matriz [4][10]='.';
matriz [5][1]='#';
matriz [5][2]='.';
matriz [5][3]='.';
matriz [5][4]='.';
matriz [5][5]='#';
matriz [5][6]='.';
matriz [5][7]='.';
matriz [5][8]='.';
matriz [5][9]='#';
matriz [5][10]='.';
matriz [6][1]='.';
matriz [6][2]='.';
matriz [6][3]='#';
matriz [6][4]='.';
matriz [6][5]='.';
matriz [6][6]='.';
matriz [6][7]='#';
matriz [6][8]='.';
matriz [6][9]='#';
matriz [6][10]='.';
matriz [7][1]='.';
matriz [7][2]='#';
matriz [7][3]='#';
matriz [7][4]='#';
matriz [7][5]='#';
matriz [7][6]='#';
matriz [7][7]='.';
matriz [7][8]='B'; //Posición de la caja
matriz [7][9]='.';
matriz [7][10]='.';
matriz [8][1]='.';
matriz [8][2]='.';
matriz [8][3]='.';
matriz [8][4]='.';
matriz [8][5]='.';
matriz [8][6]='.';
matriz [8][7]='.';
matriz [8][8]='.';
matriz [8][9]='#';
matriz [8][10]='T'; //Posición del objetivo
cout << "10 ";
cout << "12\n";
int i=0;
while ( i<10 )
{
int j=0;
while ( j<12 )
{
cout << matriz [i][j];
j++;
}
cout << "\n";
i++;
}
char *ptr;
ptr = matriz[0];
// return matriz;
return (char**)ptr;
}
char** Sokoban :: construirLaberinto2()
{
char matriz [20][25];
int fila=0;
while (fila < 20)
{
int columna=0;
while ( columna < 25)
{
matriz [0][columna]= '#';
matriz [24][columna]='#';
if ( columna==0 )
{
matriz [fila][0]= '#';
matriz [fila][19]= '#';
}
columna++;
}
fila++;
}
int i=1;
while ( i < 17 )
{
matriz[i][1]='#';
matriz[i][2]='.';
matriz[i][3]='#';
matriz[i][4]='#';
matriz[i][5]='#';
matriz[i][6]='#';
matriz[i][7]='.';
matriz[i][8]='.';
matriz[1][9]='#';
matriz[i][10]='#';
matriz[i][11]='#';
matriz[i][12]='#';
matriz[i][13]='#';
matriz[i][14]='.';
matriz[i][15]='#';
matriz[i][16]='.';
matriz[1][17]='#';
matriz[i][18]='#';
matriz[i][19]='#';
matriz[i][20]='#';
matriz[i][21]='.';
matriz[i][22]='#';
matriz[i][23]='.';
}
matriz [1][2]='T'; //Posición donde se encuentra el objetivo
matriz [2][7]='B'; //Posición de la caja
matriz [1][23]='S'; //Posición de "usted"
cout << "20 ";
cout << "25 \n";
i=0;
while ( i<20 )
{
int j=0;
while ( j<25 )
{
cout << matriz [i][j];
j++;
}
cout << "\n";
i++;
}
char *ptr;
ptr = matriz[0];
// return matriz[0];
return (char**) ptr;
}
void solucionLaberinto ( int opcion, char **matriz )
{
int fila=0;
int columna=0;
int i;
int j;
int filaUsted=0;
int columnaUsted=0;
switch (opcion){
case '1': fila=10;
columna=12;
i=0;
while ( i<fila )
{
j=0;
while ( j<columna )
{
if ( matriz[i][j]=='S' )
{
filaUsted = i;
columnaUsted = j;
}
j++;
}
i++;
}
break;
case '2': fila=20;
columna=25;
i=0;
while ( i<fila )
{
j=0;
while ( j<columna )
{
if ( matriz[i][j]=='S' )
{
filaUsted = i;
columnaUsted = j;
}
j++;
}
i++;
}
break;
default: cout << "Opción incorrecta, por favor intente nuevamente: ";
getch();
break;
}
char direccion=' ';
int sw=0;
while ( (direccion != 'q') && (sw==0) && (matriz[filaUsted-1][columnaUsted]=='.') )
{
cout << "\n presione; i para norte, m para sur, j para oeste, k para el este"
<< "\n o presione q para salir\n";
cin >> direccion;
switch ( direccion ){
case 30: if ( matriz[filaUsted-1][columnaUsted]=='.' )
{
matriz[filaUsted-1][columnaUsted]='S';
matriz[filaUsted][columnaUsted]='.';
filaUsted=(filaUsted-1);
}
i=0;
while ( i<fila )
{
int j=0;
while ( j<columna )
{
cout << matriz [i][j];
j++;
}
cout << "\n";
i++;
}
getch();
break;
case 31: if ( matriz [filaUsted+1][columnaUsted]=='.' )
{
matriz[filaUsted+1][columnaUsted]='S';
matriz[filaUsted][columnaUsted]='.';
filaUsted=filaUsted+1;
}
i=0;
while ( i<fila )
{
int j=0;
while ( j<columna )
{
cout << matriz [i][j];
j++;
}
cout << "\n";
i++;
}
getch();
break;
case 29: if ( matriz [filaUsted][columnaUsted-1]=='.' )
{
matriz[filaUsted][columnaUsted-1]='S';
matriz[filaUsted][columnaUsted]='.';
columnaUsted=columnaUsted-1;
}
i=0;
while ( i<fila )
{
int j=0;
while ( j<columna )
{
cout << matriz [i][j];
j++;
}
cout << "\n";
i++;
}
getch ();
break;
case 28: if ( matriz [filaUsted][columnaUsted+1]=='.' )
{
matriz[filaUsted][columnaUsted+1]='S';
matriz[filaUsted][columnaUsted]='.';
columnaUsted=columnaUsted+1;
}
i=0;
while ( i<fila )
{
int j=0;
while ( j<columna )
{
cout << matriz [i][j];
j++;
}
cout << "\n";
i++;
}
getch();
break;
default: cout << "Opción incorrecta, por favor intente nuevamente: ";
getch();
break;
}
}
while ( (direccion != 'q') && (sw==0) && ((filaUsted-1)=='#') &&
((filaUsted+1)=='#') && ((columnaUsted-1)=='#') && ((columnaUsted+1)=='#') )
{
cout << "\n presione; i para norte, m para sur, j para oeste, k para el este"
<< "\n o presione q para salir\n";
cin >> direccion;
switch ( direccion ){
case 30: if (filaUsted-1=='#')
{
matriz[filaUsted][columnaUsted]='S';
}
if ( matriz[filaUsted-1][columnaUsted]=='.' )
{
matriz[filaUsted-1][columnaUsted]='S';
matriz[filaUsted][columnaUsted]='.';
filaUsted=(filaUsted-1);
}
i=0;
while ( i<fila )
{
int j=0;
while ( j<columna )
{
cout << matriz [i][j];
j++;
}
cout << "\n";
i++;
}
getch();
break;
case 31: if (filaUsted+1=='#')
{
matriz[filaUsted][columnaUsted]='S';
}
if ( matriz [filaUsted+1][columnaUsted]=='.' )
{
matriz[filaUsted+1][columnaUsted]='S';
matriz[filaUsted][columnaUsted]='.';
filaUsted=filaUsted+1;
}
i=0;
while ( i<fila )
{
int j=0;
while ( j<columna )
{
cout << matriz [i][j];
j++;
}
cout << "\n";
i++;
}
getch();
break;
case 29: if (columnaUsted-1=='#')
{
matriz[filaUsted][columnaUsted]='S';
}
if ( matriz [filaUsted][columnaUsted-1]=='.' )
{
matriz[filaUsted][columnaUsted-1]='S';
matriz[filaUsted][columnaUsted]='.';
columnaUsted=columnaUsted-1;
}
i=0;
while ( i<fila )
{
int j=0;
while ( j<columna )
{
cout << matriz [i][j];
j++;
}
cout << "\n";
i++;
}
getch ();
break;
case 28: if (columnaUsted+1=='#')
{
matriz[filaUsted][columnaUsted]='S';
}
if ( matriz [filaUsted][columnaUsted+1]=='.' )
{
matriz[filaUsted][columnaUsted+1]='S';
matriz[filaUsted][columnaUsted]='.';
columnaUsted=columnaUsted+1;
}
i=0;
while ( i<fila )
{
int j=0;
while ( j<columna )
{
cout << matriz [i][j];
j++;
}
cout << "\n";
i++;
}
getch();
break;
default: cout << "Opción incorrecta, por favor intente nuevamente: ";
getch();
break;
}
}
while ( (direccion != 'q') && (sw==0) && ((filaUsted-1)=='B') &&
((filaUsted+1)=='B') && ((columnaUsted-1)=='B') && ((columnaUsted+1)=='B')
&& ((filaUsted-1)=='T') && ((filaUsted+1)=='T') && ((columnaUsted-1)=='T')
&& ((columnaUsted+1)=='T') && (filaUsted >= 5) )
{
cout << "\n presione; i para norte, m para sur, j para oeste, k para el este"
<< "\n o presione q para salir\n";
cin >> direccion;
switch ( direccion ){
case 30: if (filaUsted-1=='B')
{
matriz[filaUsted-2][columnaUsted]='B';
matriz[filaUsted-1][columnaUsted]='S';
matriz[filaUsted][columnaUsted]='.';
filaUsted=filaUsted-1;
}
else
{
if ( (matriz[filaUsted-2][columnaUsted]=='#') && ( (matriz[filaUsted-1][columnaUsted-1]=='#') || (matriz[filaUsted-1][columnaUsted+1]=='#') ) )
{
cout << "\n Es imposible ";
sw=1;
}
else
{
if ( matriz [filaUsted-2][columnaUsted]=='T' )
{
matriz[filaUsted-2][columnaUsted]='B';
matriz[filaUsted-1][columnaUsted]='S';
matriz[filaUsted][columnaUsted]='.';
cout << "\n Ha ganado ";
sw=1;
}
}
}
i=0;
while ( i<fila )
{
int j=0;
while ( j<columna )
{
cout << matriz [i][j];
j++;
}
cout << "\n";
i++;
}
getch();
break;
case 31: if (filaUsted+1=='B')
{
matriz[filaUsted+2][columnaUsted]='B';
matriz[filaUsted+1][columnaUsted]='S';
matriz[filaUsted][columnaUsted]='.';
filaUsted=filaUsted+1;
}
else
{
if ( (matriz[filaUsted+2][columnaUsted]=='#') && ( (matriz[filaUsted+1][columnaUsted-1]=='#') || (matriz[filaUsted+1][columnaUsted+1]=='#') ) )
{
cout << "\n Es imposible ";
sw=1;
}
else
{
if ( matriz [filaUsted+2][columnaUsted]=='T' )
{
matriz[filaUsted+2][columnaUsted]='B';
matriz[filaUsted+1][columnaUsted]='S';
matriz[filaUsted][columnaUsted]='.';
cout << "\n Ha ganado ";
sw=1;
}
}
}
i=0;
while ( i<fila )
{
int j=0;
while ( j<columna )
{
cout << matriz [i][j];
j++;
}
cout << "\n";
i++;
}
getch();
break;
case 29: if (columnaUsted-1=='B')
{
matriz[filaUsted][columnaUsted-2]='B';
matriz[filaUsted][columnaUsted-1]='S';
matriz[filaUsted][columnaUsted]='.';
columnaUsted=columnaUsted-1;
}
else
{
if ( (matriz[filaUsted][columnaUsted-2]=='#') && ( (matriz[filaUsted-1][columnaUsted-1]=='#') || (matriz[filaUsted+1][columnaUsted-1]=='#') ) )
{
cout << "\n Es imposible ";
sw=1;
}
else
{
if ( matriz [filaUsted][columnaUsted-2]=='T' )
{
matriz[filaUsted][columnaUsted-2]='B';
matriz[filaUsted][columnaUsted-1]='S';
matriz[filaUsted][columnaUsted]='.';
cout << "\n Ha ganado ";
sw=1;
}
}
}
i=0;
while ( i<fila )
{
int j=0;
while ( j<columna )
{
cout << matriz [i][j];
j++;
}
cout << "\n";
i++;
}
getch();
break;
case 28: if (columnaUsted+1=='B')
{
matriz[filaUsted][columnaUsted+2]='B';
matriz[filaUsted][columnaUsted+1]='S';
matriz[filaUsted][columnaUsted]='.';
columnaUsted=columnaUsted+1;
}
else
{
if ( (matriz[filaUsted][columnaUsted+2]=='#') && ( (matriz[filaUsted-1][columnaUsted+1]=='#') || (matriz[filaUsted+1][columnaUsted+1]=='#') ) )
{
cout << "\n Es imposible ";
sw=1;
}
else
{
if ( matriz [filaUsted][columnaUsted+2]=='T' )
{
matriz[filaUsted][columnaUsted+2]='B';
matriz[filaUsted][columnaUsted+1]='S';
matriz[filaUsted][columnaUsted]='.';
cout << "\n Ha ganado ";
sw=1;
}
}
}
i=0;
while ( i<fila )
{
int j=0;
while ( j<columna )
{
cout << matriz [i][j];
j++;
}
cout << "\n";
i++;
}
getch();
break;
default: cout << "Opción incorrecta, por favor intente nuevamente: ";
getch();
break;
}
}
clrscr();
}
void main()
{
Sokoban s;
int seleccion=0;
char **laberinto;
while ( seleccion!='4' )
{
clrscr();
cout << "Sokobán\n"
<< "\nSeleccione una opción entre 1 y 4:\n"
<< "\n1. Laberinto 1"
<< "\n2. Laberinto 2"
//<< "\n3. Laberinto 3"
<< "\n4. Salir\n"
<< "\nTeclee su selección: ";
cin >> seleccion;
switch (seleccion){
case '1': laberinto = s.construirLaberinto1();
s.solucionLaberinto( seleccion, laberinto );
getch();
break;
case '2': laberinto = s.construirLaberinto2();
s.solucionLaberinto( seleccion, laberinto );
getch();
break;
//case '3': laberinto = s.construirLaberinto3();
// a.solucionLaberinto( seleccion, laberinto );
// getch();
// break;
case '4': clrscr();
cout << "Gracias por jugar nuestro juego. Hasta Luego!";
getch ();
break;
default: cout << "El número que digitó es incorrecto, por favor intente nuevamente: ";
getch();
break;
}
}
}
codigo beta 1
#include
<iostream.h>
#include <fstream.h>
#include
<vector>
#include <string>
typedef struct
_celda{
char tipo='#';
int pasos=-1;
} celda;
class
laberinto{
public:
laberinto(ifstream &ent);
string
solucion();
private:
vector<vector<celda>>
lab;
};
laberinto::laberinto(ifstream &ent){
int
f,c;
int celdas=0;
ent>>f>>c;
for (int
i=0;i<f;i++){
vector<celda> tmp;
for (int j=0;j<c;j++){
celda
t;
ent>>t.tipo;
tmp.push_back(t);
if (t.tipo!='#')
celdas++;
}
lab.push_back(tmp);
}
}
string
laberinto::solucion(){
/*
Identifica las posiciones de la caja,
cara y objetivo
*/
int csf,csc,cbf,cbc,ctf,ctc;
for (int
i=0;i<lab.size();i++){
for (int j=0;j<lab[0].size();j++){
switch (lab[i][j].tipo){
case 'S':
csf=i;
csc=j;
break;
case
'B':
cbf=i;
cbc=j;
break;
case
'T':
ctf=i;
ctc=j;
break;
}
}
}
/*
Encuentra
el camino para llegar al objetivo
*/
int
pasos=0;
lab[cbf][cbc].pasos=0;
do{
}while(lab[ctf][ctc].pasos==-1);
}
int
main(int argc, char **argv){
ifstream ent("entrada.txt");
ofstream sal("salida.txt");
unsigned short
cont=0;
while(!ent.eof()){
laberinto lab(ent);
sal<<"Laberinto
#"<<cont<<endl;
sal<<lab.solucion()<<endl<<endl;
}
sal.close();
ent.close();
}
Depuración de errores
Otros analisis de posibles soluciones
El
primero es a partir de la posicion inicial de la caja hacer un
rastreo de todas las posibles lugares donde puede ser movida con
un
paso, luego con 2 luego con 3 y sucesivamente hasta que la
posicion
destino tenga el numero minimo de movimientos para
llegar, como se
hace... pues de cada cuadro se identifica si se
puede mover hacia los
adyacentes y si es posible se marcan con el
siguiente numero de paso,
aunque no lo hace si es posible llegar
a esa posicion con un numero
menor, luego para obtener el camino
simplemente se hace un retroceso
desde el destino hasta el origen
en sentido inverso moviendose a traves
de los cuadros adyacentes
con un paso menor, cualquier camino es
posible. Si por algun caso
no hay forma de llegar al destino es
imposible la solucion. Tiene
un pequeno defecto y es que no tiene en
cuenta si es capaz de
hacer un movimiento el jugador desde su estado
inicial hasta los
pasos necesarios para el empuje, mejor dicho no es
capas de
llegar al cuadro donde se debe empujar.
La siguiente solucion
es tomar cada celda como un nodo y por medio de un
algoritmo de
caminos minimos como disktra o floyd identificar la ruta
del
origen al destino y luego los movimientos necesarios del muneco para
moverse. Tiene el mismo inconveniente del anterior.
Otra
solucion es hallar por medios recursivos todos los posibles caminos
de la caja a su destino, y despues verificar si es posible que el
movimiento, en el caso de que encuentre un camino lo debe
almacenar y
despues seguir comparando para identificar el minimo,
este algoritmo
tiene un nivel de complejidad alto. Tambien para
reducir un poco el
costo del algoritmo se pude hacer el mismo
algoritmo pero en una
busqueda por profundidad con la perdida de
memoria en tal caso.
Soluciones heuristicas podemos tener el
hecho de subdividir el
laberintos en zonas necesarias e
inecesarias para minimizar el tiempo de
busqueda de los
algoritmos con la concecuente perdidad de certeza.