lunes, 21 de mayo de 2007

p4: ¿se pueden hacer pruebas sin ficheros?

Sí.

En DijkstraTestBasico se usan ficheros sistemáticamente; por ejemplo

public void testCaminoLargo() {
try {
File f = new File(ficheroPrueba);
FileWriter writer = new FileWriter(f);
BufferedWriter salida = new BufferedWriter(writer);
salida.write("3");
salida.newLine();
salida.write("0 1 50");
salida.newLine();
salida.write("0 2 5");
salida.newLine();
salida.write("2 1 5");
salida.newLine();
salida.close();
g.leeGrafo(ficheroPrueba);
CaminoMinimo d = new Dijkstra(g);
assertEquals(10, d.getCaminoMinimo(0, 1));
}
catch (Exception e) {
fail("No debería haber saltado ninguna Excepción");
}
}

exactamente el mismo caso de prueba se puede escribir como

public void testCaminoLargo() {
try {
Grafo grafo= new Grafo(3);
grafo.setArco(0, 1, 50);
grafo.setArco(0, 2, 5);
grafo.setArco(2, 1, 5);
CaminoMinimo d = new Dijkstra(grafo);
assertEquals(10, d.getCaminoMinimo(0, 1));
}
catch (Exception e) {
fail("No debería haber saltado ninguna Excepción");
}
}

Y ¿qué forma es mejor?
Es indiferente: usa lo que te parezca más claro.

jueves, 17 de mayo de 2007

se me ha ocurrido un algoritmo óptimo para p4 que ...

No quiero ni verlo: olvídalo.

Es que Edsger Dijkstra era matemático e inventó el algoritmo hace muchos años
y desde entonces está mas que absolutamente requeteprobado
(por ejemplo, es el que se usa en Internet para comunicar nodos
y parece que funciona).

Si tu asunto es aspirar al premio Nobel, sigue inventando algoritmos;
pero si quieres un consejo para esta asignatura
LIMITATE A PASAR EL ALGORITMO DE CASTELLANO A JAVA

Este es un curso de programación, no de algoritmos.
Ya tendrás tiempo de inventar ... cuando hayas aprobado.

jueves, 10 de mayo de 2007

p4: ese infinito me está volviendo loc@

Lo primero,
no pongas "0", pon "Grafo.INFINITO"
donde necesites referirte a infinito.

Lo segundo, infinito no es ni menor ni mayor que nada,
así que si quieres comparar dos cantidades que pueden valer infinito
if (a < b)
puede ser una buena idea hacer un método privado que haga lo lógico
a == infinito -> falso
b == infinito -> cierto
compara a < b normalmente

Y si necesitas sumarle algo a infinito,
ves con cuidadito, porque
infinito + x = infinito
x + infinito = infinito
también puede ser buena idea un método auxiliar

espero que se veas por qué confundir infinito con cero llevará a resultados demenciales.

viernes, 4 de mayo de 2007

p5: no me pasa las pruebas, ¿qué hago mal?

La respuesta tradicional es "pon trazas".
El comportamiento del simulador es lo bastante complejo como para que
uno se pierda con facilidad.
Sólo unas trazas enfocadas en cada cosa pueden ayudar a "ver".

Por ejemplo, en Zorro,
puede ser muy útil tener una traza específica para el método encontrarComida

private final static Logger LOGGER_COMIDA =
Logger.getLogger("mundovirtual.Zorro.encontrarComida");

Aunque hay mucha libertad,
este podría ser un ejemplo de trazas cuando se ejecuta el TestAnimal

mundovirtual.Zorro.encontrarComida [info]: zorro <5, 5> [1] :: encontrarComida(..., %lt;5, 5>)
mundovirtual.Zorro.encontrarComida [finer]: busca en <6, 5>
mundovirtual.Zorro.encontrarComida [finer]: busca en <6, 4>
mundovirtual.Zorro.encontrarComida [finer]: busca en <4, 4>
mundovirtual.Zorro.encontrarComida [fine]: encontrado: conejo <4, 4> [0]
mundovirtual.Zorro.encontrarComida [finer]: busca en <6, 6>
mundovirtual.Zorro.encontrarComida [finer]: busca en <4, 5>
mundovirtual.Zorro.encontrarComida [finer]: busca en <4, 6>
mundovirtual.Zorro.encontrarComida [finer]: busca en <5, 6>
mundovirtual.Zorro.encontrarComida [finer]: busca en <5, 4>
mundovirtual.Zorro.encontrarComida [info]: encontrarComida devuelve <4, 4>

no olvides que la búsqueda es aleatoria:
en cada llamada se visitan las posiciones adyacentes en un orden diferente

¿Qué pruebas debo hacer?

Aunque está explicado en los apuntes,
quizás convenga una breve chuleta resumen de lo que hay que hacer:

http://jungla.dit.upm.es/~pepe/doc/lprg/PreparacionPruebas.pdf

jueves, 3 de mayo de 2007

p5: ¿hay que cambiar el constructor de Simulador?

Sí.
ArrayList<Object> -- pasa a -- List<Animal>

Algo así

/**
* Crea un simulador que trabajará con una serie de especies que se pasan como parámetro y que empieza en
* el primer paso de la simulación con una lista de animales prefijada.
*
* @param especies Lista con las clases que representan las distintas especies que se considerarán en el simulador.
* @param colores Lista con los colores a asignar a cada una de las especies que se indicó en el parámetro anterior, "especies".
* @param animales Lista con los animales a incluir en el campo y con los que se iniciará la simulación. Cada animal ha de tener correctamente prefijada su localización.
*/
public Simulador(List<Class> especies, List<Color> colores, List<Animal> animales) {

lunes, 16 de abril de 2007

p4: ¿qué trazas pongo?

Por lo menos

traza INFO
cada vez que se mete un nodo en el conjunto S

traza FINE
cada vez que se recalcula (y cambia) la distancia a un nodo
como consecuencia de meter otro en S

puedes usar como inspiración
http://jungla.dit.upm.es/~pepe/doc/lprg/trazas-p4.txt
que son las trazas cuando se ejecuta
DijkstraTestBasico

p4: ¿cómo se usa una lista como un conjunto?

Sea
List S= new ArrayList();

Para meter
S.add(w);
(pueden aparecer duplicados, pero en p4 no importa)

Para ver si pertenece
S.contains(w)

p4: ¿qué campos necesito?

Necesitar, lo que se dice necesitar, sólo necesitas el grafo

private final Grafo grafo;

Salvo justificación muy justificada, dudo que necesites nada más.

En particular v0, destino y S deben ser variables locales de los métodos.

p4: ¿Cómo se tienen conjuntos en java?

Lo más exacto es
java.util.Set
ver
http://jungla.dit.upm.es/~pepe/libros/vademecum/html/ejemplodeuso_9.html

También se puede usar una lista
java.util.List
(aunque quede un poco rarito)

O se puede utilizar un simple array
para apuntar si el nodo pertenece al conjunto o no
boolean[] S= new boolean[grafo.getNumeroNodos()];

jueves, 29 de marzo de 2007

e3: tamaño incorrecto

> Al cifrar me salen ficheros demasiado grandes. He escrito esto: ..."
> int nDatos = entrada.read(datos);
> while (nDatos > 0) {
> String texto = codificador.codifica(datos);

pues muy mal: sólo puedes codificar "nDatos";
repasa los métodos de la clase base64.Codificador.

> Al descifrar me salen ficheros demasiado grandes. He escrito esto: ..."
> int nDatos = entrada.read(datos);
> while (nDatos > 0) {
> String criptograma = new String(datos);
> String mensaje = descifrador.descifra(criptograma);

pues muy mal: sólo puedes descifrar "nDatos";
repasa los constructores de la clase String.

miércoles, 28 de marzo de 2007

e3: ¿cómo funciona read()?

Con bytes.
Si tenemos un lector de bytes
InputStream in= new FileInputStream("fichero");

necesitamos un sitio donde leer bytes: un array de tamaño T
byte[] datos= new byte[T];

Cada vez que llamamos a "read()" le pasamos el sitio donde queremos cargar bytes
int n= in.read(datos)

"read()" hace 2 cosas
1. carga bytes en el array "datos" (hasta un máximo de T, si lo hay)
2. nos devuelve en "n" cuántos bytes ha logrado cargar

Por eso, si "n <= 0" es que no hay nada que cargar: se ha acabado el fichero.

Y si "n > 0", podemos usar "n" datos: entre las posiciones "0" y "n-1" del array.

"read()" nunca lee dos veces los mismos datos, sino que en cada llamada va
avanzando por el fichero y lee los datos que hay a continuación.
De esta forma, llamando a "read()" dentro de un bucle,
vamos obteniendo los bytes sucesivos que contiene el fichero.

Con caracteres.
Lo mismo, pero cambiando "InputStream" por "Reader"
y "byte[]" por "char[]".

martes, 27 de marzo de 2007

e3: exactamente ¿cuántos datos leo?

Si haces algo así

byte[] datos= new byte[1024];
int n= inputStream.read(datos);

n puede ser cualquier número entre -1 y 1024.

Si es <=0, es que no hay nada que leer:
lo has leido todo y puedes acabar.

Si n > 0 has leído n datos, que están en las primeras n posiciones del array.

Para codificarlo, no puedes hacer
String codificada= codificador(datos);
sino que tendrás que usar otro método de la clase que sólo codifique n bytes

http://www.lab.dit.upm.es/~lprg/curso/e3/doc/base64/Codificador.html

--------------------
Algo parecido ocurre al descifrar,
int n= reader.read(datos);

De los n caracteres válidos en datos, hay que hacer una String,
mira los constructores disponibles:

http://java.sun.com/j2se/1.5.0/docs/api/java/lang/String.html

e3: ¿qué eso de termina() del codificador?

Ocurre que para pasar a base64 se necesita un múltiplo entero de 3 bytes.
Si los datos que pasas a codificar no son un múltiplo entero de 3,
pues el decodificador sólo codifica los grupos de 3 que encuentra
y se guarda el resto para cuando le mandes codificar más
(empezará con los que tiene como restos de la última llamada).

Eso va muy bien mientras hay más bytes que leer,
pero cuando el fichero de entrada se acaba
hay que decirle al codificador que ya no guarde más,
sino que vacie los restos.

Para eso, al acabar, se llama a
String restos= codificador.termina();

... y esos restos hay que cifrarlos y escribirlos en la salida cifrada.

Aunque probablemente no lo necesites conocer en detalle,
si tienes curiosidad por eso del base64
puedes ilustrarte en la wikipedia:

http://en.wikipedia.org/wiki/Base64

para hacer el ejercicio basta con usar las clase del paquete base64.

lunes, 26 de marzo de 2007

e3: ¿dónde están los ficheros?

Todo se hace a partir del sitio donde hayas puesto en ejercicio,
el código java y los ficheros de prueba.

Saco una foto de mi ordenador:

http://jungla.dit.upm.es/~pepe/doc/lprg/e3_msdos.png

e3: ya lo he escrito todo pero ni funciona ni compila, ¿qué hago?

Salvo que tengas mucha experiencia, escribirlo todo y luego intentar compilar
puede ser bastante mala idea.

Lo ideal es escribir un poquito, poner trazas, compilar y ejecutar
(con trazas y, si ya es posible, con un caso de pruebas).

Cuando funcione un poquito, haces otro poquito y así, paso a paso,
acabarás mucho antes que con todo de golpe.

Bueno, nunca hay dos experiencias iguales; es un consejo.

domingo, 25 de marzo de 2007

e3: ¿cómo escribo caracteres en el fichero?

Esto está bien:

String cifrado= cifrador.cifra(...);
char[] caracteres= cifrado.toCharArray();
writer.write(caracteres);

Esto está también bien, y es más directo:

String cifrado= cifrador.cifra(...);
writer.write(cifrado);

e3: ¿por dónde empiezo?

Por el principio, por supuesto. Y vas añadiendo funciones poco a poco, compilando y comprobando que lo hecho funciona bien antes de pasar a lo siguiente. Para "ver" si va bien necesitarás trazas y usar los casos de prueba publicados.

1. Crea la clase cifrador.ui.CifradorFicheros
importando los cifradores y descifradores incrementales,
así como los codificadores y descodificadores base64

2. Crea un Logger con el nombre del enunciado
(puedes crear loggers tuyos con otros nombres)

3. Crea el método main
copiando el javadoc del enunciado

4. Captura los argumentos y escribe la traza que se pide

ya puedes empezar a compilar y ver si funciona ...

5. Usa el primer argumento para decidir si tienes que cifrar o que descifrar
y actua en consecuencia, siempre trazando para comprobar que vas bien

e3: sobre el nombre de los ficheros

Los nombres de los ficheros serán los que aparezcan al llamar al programa,
exactamente como se le pasan al llamar al programa.

Por ejemplo si le llamas como

$> java cifrador.ui.CifradorFicheros -c evalc cita.txt cita-cifrada

se utilizará la clave "evalc" para leer el fichero "cita.txt" y escribir el fichero "cita-cifrada".

Nosotros hemos puesto parejas de ficheros de prueba, por ejemplo

CancionDelPirata.txt y CancionDelPirata.vgn

Si los vas a usar como prueba, tienes que hacer algo así

...> java cifrador.ui.CifradorFicheros -c AEIOU CancionDelPirata.txt cifrado

...> java ComparaFicheros cifrado CancionDelPirata.vgn
cifrado y CancionDelPirata.vgn son idénticos

...> java cifrador.ui.CifradorFicheros -d AEIOU CancionDelPirata.vgn descifrado

...> java ComparaFicheros descifrado CancionDelPirata.txt
descifrado y CancionDelPirata.txt son idénticos

jueves, 22 de marzo de 2007

e3: java no se sabe ejecutar "if (args[0] == "-c") ..."

Normal,
para comparar String hay que usar equals().

Mira
http://jungla.dit.upm.es/~pepe/doc/fprg/vademecum.pdf
equals (método) public boolean equals(Object)
Igualdad (==)
String (clase) java.lang.String

e3: ¿puedo poner algunos métodos provados?

Sin duda: su puedes.

Aunque no es obligatorio, la verdad es que queda muy bien si pones
un método para cifrar y otro para descifrar,
así en el main, con un IF decides a cual llamar
y en cada método te centras en lo que tiene que hacer.

miércoles, 21 de marzo de 2007

e3: ¿se necesita un nuevo array en cada lectura?

No.
Lo normal es crear un array (de bytes o caracteres, según necesites)
antes del bucle de lectura.
Al principio el array está lleno de ceros.
Cada vez que lees se cargan nuevos valores en las primeras posiciones,
machacando los valores anteriores.

Ojo con lo que devuelven los métodos de lectura,
sólo son buenos los primeros valores,
los demás son restos de otra época.

e3: al cifrar, ¿necesito un char[]?

Es cierto que el cifrador devuelve una String,
puedes pasarla a un char[] para guardarla en el disco:

String criptograma= cifrador.cifra(...);
char[] chars= criptograma.toCharArray();
writer.write(chars);

o puedes hacerlo directamente

String criptograma= cifrador.cifra(...);
writer.write(criptograma);

viernes, 16 de marzo de 2007

e2: al descifrar me salen códigos negativos ¿qué pasa?

Es normal, y debes tenerlo en cuenta.

Si ctc es el código del texto cifrado (criptograma)
y ccl es el código de la clave,
debes hacer algo así al descifrar

while (ctc < ccl) ctc+= ALFABETO.length;
ctd= (ctc - ccl) % ALFABETO.length;

siendo ctd el código del texto descifrado.

jueves, 15 de marzo de 2007

e2:¿qué pasa si no entrego el viernes?

Bueno, el ejercicio es obligatorio y debes hacerlo antes de junio;
si no, no podremos aprobarte la asignatura.

Para los ejercicios no aceptados en la primera entrega,
habilitaremos fechas de repesca.

No obstante, la nota no será la misma si se entrega en la repesca.
Mira los criterios de evaluación.

¿qué pasa si mi código es como el de un compañero?

Sistemáticamente pasamos un detector de copias.
Si dos entregas son iguales, consideramos que ambos habeis copiado
y os suspendemos a los dos en junio.

Suena duro,
pero es que la evaluación es individual y no podemos hacer otra cosa.

miércoles, 14 de marzo de 2007

e2: es un ejercicio de arrays, ¿verdad?

Pues puedes hacerlo con arrays o no.

Si quieres hacerlo con arrays, pasarás de String a array usando "charAt()" o "toCharArray()"
y volverás de array a String usando "new String(array)".

Si no quieres usar arrays, puedes acceder a los String con "charAt()",
añadiendo cosas con "+".
Incluso puedes optimizar el código usando un "StringBuilder()".

¿Qué es un StringBuilder?
mira el vademecum
http://jungla.dit.upm.es/~pepe/doc/fprg/vademecum.pdf

e2: esto que he hecho, ¿está bien?

¿Pasa las pruebas que preparaste en el ejercicio e1?

sábado, 10 de marzo de 2007

e2: hasta que no funcione no pongo trazas con Logger

Tu estás tonto (por decirlo finamente).

Las trazas son para poner a punto el programa y localizar rápidamente los fallos.

Poner trazas sólo cuando funcione comprendo que es necesario para que te aprobemos
el ejercicio, pero realmente estás perdiendo tu tiempo.

Si te sobra el tiempo, sigue buscando errores a ciegas.
Pero si tienes cosas más interesantes que hacer en la vida,
pon trazas en los programas según escribes el código
y así lo pondrás a punto mucho más rápidamente.

Para que no interfiera con las trzas que te has pedido,
a tus trazas ponles otro nombre
MI_LOG= Logger.getLogger("cifrador.MiCifrador.mis_trazas");

Y NO LAS QUITES CUANDO LO ENTREGUES.

e2: hasta que no funcione no documento ...

Pues muy mal hecho.

Lo primero que hay que hacer es escribir lo que tiene que hacer un método.
No deberías poner ni una línea de código hantes de
tener perfectamente claro
* los argumentos que recibe,
* lo que significan,
* el resultado que debe devolver
* y las posibles excepciones

e2: ¿vale poner métodos privados?

Sí, por supuesto.

Es más, yo diría que necesitarás definir algunos métodos privados
para que el código quede legible.

No olvides documentar con javadoc los métodos privados.
/** ... */

miércoles, 28 de febrero de 2007

¿Vale decodificar caracteres?

¿Qué? Se decodifican enteros, no caracteres.

Es que si pongo
cifrador.descodifica('x')
las pruebas ejecutan.

Sí; pero realmente no sabes qué estás probando
pues java pasa el carácter 'x' a su código UNICODE y sigue.

¿Sabes el código UNICODE?
Como sospecho que no, pues concluyo que no sabes qué pruebas. Mal.

¿Te importaría poner números, sólo números y nada más que números? Gracias.

¿Cómo puedo hacer pruebas de caja blanca?

En e1: no puedes porque no conoces el código fuente de CifradorReferencia.java.

Para ser precisos, las pruebas son pruebas,
ni de caja blanca ni de caja negra.

De las pruebas que hagas,
puedes calcular la cobertura como caja negra;
pero no puedes calcular la cobertura como caja blanca.

En el ejercicio e2, cuando programes tu versión de MiCifrador.java,
podrás clacular la cobertura como caja blanca que has conseguido en el ejercicio e1.

Al DrJava no le gustan mis pruebas ...

Si estás usando la versión estable de

http://www.lab.dit.upm.es/~lprg/entorno/mipc/drjava/index.html

debés usar la versión JDK 6 de

http://www.lab.dit.upm.es/~lprg/entorno/mipc/jdk/index.html

por aquello de la compatibilidad.

¿Hay realmente un fallo en CifradorReferencia que tenemos que encontrar?

No voy a decirte ni que sí, ni que no.

Puede que sí, puede que no.

Para tu tranquilidad, la nota no depende de que lo encuentres o no.

La nota depende de la cobertura de caja negra que logres
y de la documentación de las pruebas.

¿Hay que probar con cadenas raras?

¿Te refieres a usar claves y mensajes estrambóticos como ...?

"ñ; É"
Supongo que es una cadena tan válida como cualquier otra;
pero realmente consigues lo mismo con una cadena normal

"Con diez cañones por banda, viento en popa a toda vela, ..."


Por favor, cuida tus ojos, y los nuestros :-]

¿Vale probar descifra(cifra(x)) == x?

La verdad es que parece más gracioso que razonable.

Hay que probar los métodos por separado.
Nadie ha pedido probar combinaciones de métodos.

Un programa podría cifrar y descifrar de cualquier forma
(perfectamente incorrecta)
y sin embargo pasar esa prueba porque es incorrecto pero coherente consigo mismo.

¿Vale hacer un bucle para probar todos los caracteres?

Parece un error de concepto.

En una prueba debes saber TU (no el programa) qué código debe salir.
Por tanto, debes poner el resultado esperado a mano.

Además, para tener una cobertura del 100% de caja negra del método codificar basta hacer
- el primer carácter
- el último carácter
- algún carácter de enmedio
- un carácter fuera del alfabeto

Si en vez de 4 pruebas (ponle 5 o 6 cosas originales que se te ocurran) haces 95
creo que no sabes muy bien por donde está el norte.

No quiero ni pensar qué pasará si eso del bucle para probarlo todo se lo pretendes aplicar algún día a un programa de verdad: ¿varios meses ejecutando pruebas?

¿Cómo preparo un texto cifrado para programar una prueba?

Siempre puedes hacerlo a mano siguiendo las indicaciones de la www

http://www.lab.dit.upm.es/~lprg/curso/e123/vigenere.htm

aunque hay un truco:
usa el applet que hay en esa página al final.

¿Qué clave le meto al CifradorReferencia?

Depende.

Para pruebas de codificar y descodificar, cualquier clave vale
por ejemplo, "AEIOU"

Para pruebas del constructor, debes probar con una clave normal
y con las claves que dar errores.
Mira la www

http://www.lab.dit.upm.es/~lprg/curso/e1/faq.htm

Para pruebas de cifrar y descifrar,
coge una clave válida cualquiera
por ejemplo, "AEIOU"
y prepara mensajes más cortos / más largos que la clave elegida.

Mi programa ¿tiene que estar bonito?

Sí, por favor.
es más fácil de corregir para nosotros
(y tu verás antes los errores)

Si llevas tiendo tocando aquí y allá y está todo descolocado,

1. sal del ide (bluej, drjava o lo que uses)
2. pásalo por jalopy
http://www.lab.dit.upm.es/~lprg/tools/jalopy.htm

gracias

¿Vale usar caracteres raros para probar el codificador?

Define "caracteres raros".

Yo utilizaría sólo caracteres normales de un teclado en español.

Si vas a empezar con cosas raras como '€', ruso, árabe, chino, japonés, ...
te vas a encontrar con problemas para poder meter dichos caracteres
y el resultado va a ser arbitario.

¿Quieres un consejo?

El carácter '$' no está en el alfabeto, ¿correcto?
pues ya te llega.

¿Puedo cambiar la contraseña de mi cuenta del laboratorio?

Sí.

Ves a la página del laboratorio

http://www.lab.dit.upm.es/

concretamente a

https://maestro.lab.dit.upm.es/cgi-bin/passwd.html

¿Necesito una cuenta para LPRG?

Sí.

es la única forma de entregar las prácticas.

Tienes que ir al laboratorio y pedir que te abrán una cuenta.
Si ya tienes una de otra asignatura,
tienes que ir para que quede registrado que la vas a usar en LPRG.

¿he hecho bastantes pruebas ya?

Eso lo deberías saber tu mismo:
¿qué cobertura de caja negra crees que has alcanzado con tus pruebas?

Debes probar todo lo que se dice en el enunciado y en el javadoc de Vigenere.java y CifradorReferencia.java.
Y cada una de esas cosas debes probarla con
- 1 dato "normal"
- datos extermos (caracteres primero y último del alfabeto, códigos antes, dentro y después del rango [0..94])
- algún otro caso que te parezca sospechoso

No encuentro CifradorReferencia

¿Seguro que has puesto los ficheros donde hemos indicado?

en algún sitio del PC crea un directorio
... / e1

en ese directorio, crea un subdirectorio
... / e1 / cifrador

pon ahí los ficheros de la web
... / e1 / cifrador / Vigenere.java
... / e1 / cifrador / CifradorReferencia.class

si usas BlueJ,
dile que abra un fichero en ese sitio
http://www.lab.dit.upm.es/~lprg/curso/e1/e1_open.png

cuando crees tu batería de pruebas
... / e1 / cifrador / CifradorTest.java

el BlueJ debe tener esta pinta
http://www.lab.dit.upm.es/~lprg/curso/e1/e1_cifrador.png

Si usas DrJava, el asunto es aún más fácil:
ves directamente al directorio
... / e1 / cifrador
y abre el fichero; el solito se aclara con los paquetes.