viernes, 28 de febrero de 2014

Primer contacto con punteros.

Buenas. Ésta no es una práctica en sí, sino que son ejercicios que nos puso el profesor para "tantear" los punteros desde el inicio. Éste es el enunciado:


1) Definir dos variables enteras e implementar un procedimiento que incremente en una cantidad cada una de las variables. Mostrar el contenido de las variables en el programa principal.  
2) Definir dos variables y dos punteros que hagan referencia a cada una de ellas. Definir un procedimiento para que muestre el contenido de esas variables pero a traves de los punteros. 
3) Definir un array de enteros de 10 posiciones.Definir una variable puntero que haga referencia a la primera posición del array.Hacer dos procedimientos, uno para rellenar el array y otro para mostrar su contenido. (De las dos formas, pasando como parametro puntero y pasando como parámetro el array)  
4) Completar el anterior definiendo un procedimiento que pida un indice y un valor y modifique el array con ese valor en ese índice.

Y aquí teneis los resultados:

Ejercicio 1:
#include <stdio.h>
#include <stdlib.h>

void incrementar(int *a, int*b){
 *a = *a +100;
 *b = *b + 100;
}

int main1(void) {

 int x;
 int y;


 // Pide las dos variables enteras
 printf("Introduce dos variable enteras x e y: ");
 fflush(stdout);
 scanf("%d %d", &x, &y);

 //Incremento
 incrementar(&x, &y);

 //Imprimo las variables ya incrementadas
 printf("x = %d \ny = %d\n", x, y);

 fflush(stdout);


 system("PAUSE");
 return EXIT_SUCCESS;
}

Ejercicio 2:
#include<stdio.h>
#include<stdlib.h>

void mostrar(int *m, int *n) {
 printf("Los datos son %d y %d \n \n", *m, *n);
 fflush(stdout);
}

int main2(void) {
 int a;
 int b;

 //Escaneo los datos
 printf("Introduzca los datos: \n");
 fflush(stdout);
 scanf("%d %d", &a, &b);
 printf("\n");

 //Creo los punteros
 int *x = &a;
 int *y = &b;

 //Llamo al procedimiento.
 mostrar(x, y);

 system("PAUSE");
 return EXIT_SUCCESS;
}

Ejercicio 3:
#include <stdio.h>
#include <stdlib.h>

void rellenarConArray(int *a[]) {
 int i;
 for(i = 0; i < 10; i++) {
  scanf("%d ", a[i]);
 }
}
void rellenarConPunte(int *ptr) {
 int i;
 int *aux = ptr;
 for(i = 0; i < 9; i++) {
  scanf("%d ", aux);
  aux++;
 }
}

void imprimirConArray(int *a[]) {
 int i;
 for(i = 0; i < 10; i++) {
   printf("%d ", a[i]);
 }
}
void imprimirConPunte(int *ptr) {
 int i;
 int *aux = ptr;
 for(i = 0; i < 10; i++) {
  printf("%d ", *aux);
  aux++;
 }
}



int main(void) {
 //main del tercero
 int z[10];
 int *a = &z[0];
 rellenaConArray(z);
 mostrarConArray(z);
 rellenaConPuntero(a);
 mostrarConPuntero(a);
        system("PAUSE");
        return EXIT_SUCCESS;
}

Ejercicio 4:
void setArray(int a[], int i, int v) {
 a[i] = v;
}
void setPuntero(int *a, int i, int v) {
 int *aux = a + i;
 *aux= v;
}

int main(void) {
 //main del cuarto
 int z[10];
 int *a = &z[0];
 rellenaConArray(z);
 //Aquí los cambios
 setArray(z, 4, 150);
 //
 mostrarConArray(z);


 rellenaConPuntero(a);
 //Aquí los cambios
 setPuntero(a, 6, 400);
 //
 mostrarConPuntero(a);
}

Disfrutadlos y si tenéis alguna duda/pega/sugerencia/amenaza no dudeis en comentarla aquí abajo. Todos podemos mejorar ;)

Salud

miércoles, 26 de febrero de 2014

Práctica de Alumnos, Notas y Asignaturas.

Buenas gente, aqui vuelvo con un nuevo ejercicio ;)
Esta vez vamos a crear una aplicación para anotar las calificaciones obtenidas por alumnos en una asignatura. Para ello se crearán las clases Alumno, Asignatura y AlumnoException:

• Crear la excepción comprobada AlumnoException para manejar situaciones excepcionales que podrán producirse en las siguientes clases. 
• La clase Alumno mantiene información de un alumno del cual se conocen el nombre (String), el dni (String) y la calificación obtenida en una asignatura (double). La clase tendrá dos constructores, uno en el que se proporcionan el nombre, el dni y la calificación y otro con solo el nombre y el dni siendo en este caso la calificación igual a cero. Si la calificación dada es negativa se deberá lanzar una excepción AlumnoException. Dos alumnos son iguales si coinciden sus nombres y sus dni. La letra del dni podrá estar indistintamente en mayúsculas o minúsculas. Crear también métodos para conocer el nombre, (String getNombre()), el dni (String getDni()) y la calificación (double getCalificacion()). La representación de un alumno debe mostrar el nombre y el dni pero no la calificación. 

• Crear la clase Asignatura. Una asignatura se crea a partir del nombre de la misma y de un array de String en la que cada elemento del array contendrá toda la información para crear un alumno con el siguiente formato (deben aparecer siempre los tres tokens separados por ;). Por ejemplo: 55343442L;Godoy Molina, Marina;6.31 
El constructor deberá crear, si es posible, el alumno con el nombre, dni y calificación dadas y almacenarlo en un array de alumnos. Si no fuera posible, deberá almacenar esta entrada en otro array de String (llamado malos) precedido de un comentario que indique cual ha sido el problema por lo que no se ha podido crear el alumno. Por ejemplo, ante la entrada: "342424f2J;Fernandez Vara, Pedro;tr"
Se incluirá en malos el siguiente String: "ERROR. Nota no numérica: 342424f2J;Fernandez Vara, Pedro;tr". 
La clase Asignatura incluirá el método: double getCalificacion(Alumno al) throws AlumnoException que devuelve la calificación del alumno al dado si es que existe. Si no existe se lanzará una excepción AlumnoException. También tendrá dos métodos, uno que devuelve el array de alumnos (Alumno[] getAlumnos()) y otro que devuelve al array de entradas malas (String [] getMalos()). 
Además incluirá un método que proporcione la media de las calificaciones de los alumnos de la asignatura (double getMedia()). Por último dispondrá de una representación de los objetos de la clase como la que se muestra en el ejemplo (usar StringBuilder para crear la representación).

Mucho que leer pero no es tanto, verdad? ;) Aquí teneis el test para probarlo:

public class Main {
  static String[] als = {
  "25653443S;Garcia Gomez, Juan;8.1",
  "23322443K;Lopez Turo, Manuel;4.3",
  "24433522M;Merlo Martinez, Juana;5.3",
  "53553421D;Santana Medina, Petra;-7.1",
  "55343442L,Godoy Molina, Marina;6.3",
  "342424f2J;Fernandez Vara, Pedro;2.l",
  "42424312G;Lopez Gama, Luisa;7.1" };

  public static void main(String[] args) {
    Asignatura algebra = new Asignatura("Algebra", als);
    try {
      Alumno al1 = new Alumno("Lopez Turo, Manuel", "23322443k");
      Alumno al2 = new Alumno("Fernandez Vara, Pedro", "342424f2J");
      System.out.println("Calificacion de " + al1 + ": "
        + algebra.getCalificacion(al1));
      System.out.println("Calificacion de " + al2 + ": "
        + algebra.getCalificacion(al2));
    } catch (AlumnoException e) {
      System.err.println(e.getMessage());
    }

    System.out.printf("Media %4.2f\n", algebra.getMedia());

    System.out.println("Alumnos...");

    for (Alumno alumno : algebra.getAlumnos()) {
      System.out.println(alumno + ": " + alumno.getCalificacion());
    }
    System.out.println("Malos...");
    for (String malo : algebra.getMalos()) {
      System.out.println(malo);
    }
    System.out.println(algebra);
  }
}

Y este debe ser el resultado que os salga ;)

Calificacion de Lopez Turo, Manuel 23322443k: 4.3
El alumno Fernandez Vara, Pedro 342424f2J no se encuentra
Media 6,20
Alumnos...
Garcia Gomez, Juan 25653443S: 8.1
Lopez Turo, Manuel 23322443K: 4.3
Merlo Martinez, Juana 24433522M: 5.3
Lopez Gama, Luisa 42424312G: 7.1
Malos...
ERROR. Calificación Negativa: 53553421D;Santana Medina, Petra;-7.1
ERROR. Faltan datos: 55343442L,Godoy Molina, Marina;6.3
ERROR. Calificación no numérica: 342424f2J;Fernandez Vara, Pedro;2.l
Algebra : {[Garcia Gomez, Juan 25653443S, Lopez Turo, Manuel 23322443K, Merlo
Martinez, Juana 24433522M, Lopez Gama, Luisa 42424312G], [ERROR. Calificación
Negativa: 53553421D;Santana Medina, Petra;-7.1, ERROR. Faltan datos:
55343442L,Godoy Molina, Marina;6.3, ERROR. Calificación no numérica:
342424f2J;Fernandez Vara, Pedro;2.l]}
Aquí os doy el resultado de las clases:
Si queréis descargarlo, aquí teneis AlumnoException, Alumno y Asignatura, en otro caso...

 Primero AlumnoException:

public class AlumnoException extends Exception{
 /**
  * 
  */
 private static final long serialVersionUID = 1L;
 public AlumnoException() {
  super();
 }
 public AlumnoException(String e) {
  super(e);
 }
} 
Luego Alumno:
public class Alumno {
 private String nombre;
 private String dni;
 private double nota;
 
 public Alumno (String n, String d, double not) throws AlumnoException{
  this.nombre = n;
  this.dni = d;
  if(not <0) throw new AlumnoException("Nota negativa");
  this.nota = not;
 }
 public Alumno (String n, String d) {
  this.nombre = n;
  this.dni = d;
  this.nota = 0;
 }
 
 public String getNombre()   { return this.nombre;}
 public String getDni()   { return this.dni;}
 public double getCalificacion() {return this.nota;}
 
 public boolean equals(Object o) {
  return o instanceof Alumno && 
    nombre.equals(((Alumno)o).nombre) &&
    dni.equalsIgnoreCase(((Alumno)o).dni);
 }
 public int hashCode() {
  return nombre.hashCode() + dni.toLowerCase().hashCode();
 }

 public String toString() {
  return this.dni + ";" + this.nombre;
 }
 
}


Y ya por último Asignatura:

import java.util.Arrays;
import java.util.InputMismatchException;
import java.util.Locale;
import java.util.NoSuchElementException;
import java.util.Scanner;


public class Asignatura {
 private String nombre;
 private Alumno[] alumnos;
 private String[] malos;
 
 public Asignatura (String n, String[] entradas) {
  nombre = n;
  Alumno[] alumnosAux = new Alumno[entradas.length];
  int correctos = 0;
  String[] erroresAux = new String[entradas.length];
  int erroneos = 0;
  
  for(String linea: entradas) {
   Scanner sc = new Scanner(linea);
   try{ 
    sc.useDelimiter("[;]");
    sc.useLocale(Locale.ENGLISH);
    String dniAlumno = sc.next();
    String nombreAlumno = sc.next();
    double notaAlumno = sc.nextDouble();
    Alumno alumno = new Alumno(dniAlumno, nombreAlumno, notaAlumno);
    alumnosAux[correctos] = alumno;
    correctos++;
   }
     catch(InputMismatchException e) {
    erroresAux[erroneos] = "ERROR. Calificacion no numerica" + linea;
    erroneos++;
   } catch(NoSuchElementException e) {
    erroresAux[erroneos] = "ERROR. Faltan Datos" + linea;
    erroneos++;
   } catch(AlumnoException e) {
    erroresAux[erroneos] = "ERROR."+ e.getMessage() + ":" + linea;
    erroneos++;
   } finally {
    sc.close();
   }
  } //fin for
  
  alumnos = Arrays.copyOf(alumnosAux, correctos);
  malos = Arrays.copyOf(erroresAux, erroneos);
 }

  public double getCalificacion(Alumno al) throws AlumnoException {
  int i = 0;
  while(i<alumnos.length && !(alumnos[i].equals(al))) {
   i++;
  }
  if(i==alumnos.length){
   String std = "El alumno "+ al + " no se encuentra.";
   throw new AlumnoException(std);
  }
  return alumnos[i].getCalificacion();
 }

  public Alumno[] getAlumnos() {
   return alumnos;
  }
  public String[] getMalos() {
   return malos;
  }

  public double getMedia() {
   double sum = 0;
   for(int i = 0; i < alumnos.length; i++) {
    sum += alumnos[i].getCalificacion();
   }
   return sum/alumnos.length;
  }
  
  public String toString() {
   StringBuilder ss = new StringBuilder(nombre);
   ss.append(": {");
   ss.append(Arrays.toString(alumnos));
   ss.append(",");
   ss.append(Arrays.toString(malos));
   ss.append("}");
   return ss.toString();
  }
}


lunes, 24 de febrero de 2014

Ejercicios de Introducción a C++.

Aquí unos ejercicios muy sencillos en C++ para los que estén empezando con este lenguaje.

Escriba un programa que lea por teclado una cantidad en pesetas y muestre su correspondencia en euros (1€=166.386 ptas.).

#include <iostream>
using namespace std;
const double cambio = 166.386;

int main() {
 double pesetas, euros;
 cout << "Introduzca una determinada cantidad de pesetas:";
 cin >> pesetas;
 euros = pesetas / cambio;
 cout << "Esa cantidad de pesetas equivale a "<< euros <<" euros.";
 return 0;
}

Escriba un programa que visualice por pantalla el tamaño en bytes que ocupan todos y cada uno de los tipos básicos vistos en clase: int, long, char, etc. Para ello debe usarse el operador sizeof.

#include <iostream>
using namespace std;
int main() {
 cout << "Tamaño en bytes que ocupan los tipos básicos." << endl;
 cout << "bool -> \t"<< sizeof(bool) << " bytes." << endl;
 cout << "char ->\t \t"<< sizeof(char) << " bytes."<< endl;
 cout << "short ->"<< "\t" << sizeof(short) << " bytes." << endl;
 cout << "int -> \t \t"<< sizeof(int) << " bytes." << endl;
 cout << "unsigned ->"<< "\t" << sizeof(unsigned) << " bytes." << endl;
 cout << "long ->" << "\t"  << "\t" << sizeof(long) << " bytes."<< endl;
 cout << "float ->" << "\t" << sizeof(float) << " bytes." << endl;
 cout << "double ->"<< "\t" << sizeof(double) << " bytes." << endl;
 return 0;
}
Escriba un programa que lea cuatro letras por teclado, y posteriormente escriba dichas letras de manera que cada una de ellas se encuentre codificada sustituyéndola por aquel carácter que le sigue en la tabla de código ASCII. Por ejemplo, ante la entrada SETO debe producir la salida TFUP.

#include <iostream>
using namespace std;

int main() {
 char a, b, c, d;
 cout << "Introduce cuatro letras: ";
 cin >> a >> b >> c >> d;
 cout << "La palabra codificada es: " << char(a +1) << char(b+1) << char(c+1) << char(d+1);
 return 0;
}

Escribir un programa que dado un número en bytes, obtenga una magnitud equivalente expresada en Mbytes, Kbytes y bytes.

#include <iostream>
using namespace std;
const double cambio = 1024;


int main() {
 double bytes, mbytes, aux, kbytes;
 cout << "Introduce un número de bytes: " ;
 cin >> bytes;
 mbytes = bytes / (cambio * cambio);
 aux = mbytes - int(mbytes);
 mbytes = int(mbytes);
 kbytes = aux * cambio;
 aux = kbytes - int(kbytes);
 kbytes = int(kbytes);
 bytes = aux * cambio;

 cout << "Equivale a "<< mbytes << " MB, "<< kbytes << " KB y "<< bytes<< " B.";

 return 0;
}

Escribir un programa que calcula la longitud y el área de un círculo.
#include <iostream>
using namespace std;

const double PI=3.1416;

int main(){
 double longitud,area;
 int radio;
 cout << "Radio = ";
 cin >> radio;
 longitud = 2*PI*radio;
 area = PI*(radio*radio);
 cout << "area = "<< area << endl;
 cout << "long = "<< longitud << endl;
 return 0; 
}

Escriba un programa que lea una palabra de cuatro letras minúsculas por teclado y a continuación la escriba en mayúsculas.

#include <iostream>
using namespace std;

int main() {
 char a, b ,c, d;

 do{
 cout << "Introduce una palabra de cuatro letras minúsculas: ";
 cin >> a >> b >> c >> d;
 }while( a < 97 || a > 122 || b < 97 || b > 122 || c < 97 || d < 97 || c > 122 || d > 122  );

 cout << "En mayúscula: ";
 cout << char(a - 32) << char(b-32) << char(c-32) << char(d-32);
 return 0;
}

Escriba un programa que calcule la nota final de una asignatura. Éste habrá de leer por teclado la nota de la parte de teoría y la nota de la parte de problemas, y habrá de calcular la nota final considerando que la parte de teoría vale un 70% de la nota final y la de práctica un 30%

#include <iostream>
using namespace std;
const double PRACTICA = 0.3;
const double TEORIA = 0.7;

int main() {
 double teo, prac, final;
 cout << "Programa que calcula la nota final de una asignatura." << endl;
 cout << "Introduce la nota de la parte teórica: ";
 cin >> teo;
 cout << "Introduce la nota de la parte de problemas: ";
 cin >> prac;

 final = PRACTICA*prac + TEORIA * teo;

 cout << "La nota final de la asignatura es "<< final <<".";

 return 0;
}

domingo, 23 de febrero de 2014

WellBalanced - Cadenas balanceadas en Java y Haskell

A continuación resuelvo un ejercicio sencillo tanto en Java como en Haskell en el que se utiliza una pila o stack. Este nos pide que escribamos una función qu permita determinar si una cadena de caracteres está bien balanceada o equilibrada en lo que se refiere a los paréntesis, corchetes y llaves que contiene. El resto de caracteres no interesan. Por ejemplo la cadena "v(hg(jij)hags{ss[dd]dd})" está balanceada pero no así la cadena "ff(h([sds)sds]ss)hags". Para ello se utilizará una pila en la que cada vez que aparezca un signo de apertura, se introduce en la pila y cada vez que aparece un signo de cierre se extrae la cima de la pila y se comprueba que corresponde al signo de apertura correspondiente. Si al finalizar de recorrer la cadena la pila está vacía entonces la expresión está equilibrada.

JAVA

Para realizar esta clase debemos importar al proyecto las bibliotecas en las que tenemos las implementación LinkedStack (aunque puede ser otra implementación
de la interfaz Stack sin ningún problema). Recuerdo cómo se hacía esto en Eclipse, que siempre suele pasar que se nos olvidan este tipo de cosas:

1. Project -> Properties -> Java Build Path -> Libraries
2. Seleccionamos la opción oportuna (Add external jar, add library...)

public class WellBalanced {
 private final static String OPEN_PARENTHESES ="{[(";
 private final static String CLOSED_PARENTHESES = "}])";
 public static void main(String [] args) {
  String prueba = "vv(hg(jij)hags{ss[dd]dd})"; //con el que probamos
  Stack<Character > pila = new LinkedStack<Character >();
  System.out.println(wellBalanced(prueba, pila)); // Se muestra por pantalla si prueba está balanceada (true) o no (false)
  
 }
 public static boolean wellBalanced(String exp, Stack <Character > stack) {
  for(int i=0; i < exp.length(); i++){
   char c = exp.charAt(i);
   if (isOpenParentheses(c)){
    stack.push(c);
   }else if (isClosedParentheses(c)){
    if (match (stack.top(), c) )  {
     stack.pop();
    } else{
     return false;
    }
   }
  }
  
  return stack.isEmpty();

 }
 public static boolean isOpenParentheses(char c) {
  return OPEN_PARENTHESES.indexOf(new Character(c).toString()) >= 0;
 }
 public static boolean isClosedParentheses(char c) {
  return CLOSED_PARENTHESES.indexOf(new Character(c).toString()) >= 0;
 }
 public static boolean match(char x, char y) {
  return OPEN_PARENTHESES.indexOf(new Character(x).toString()) ==
    CLOSED_PARENTHESES.indexOf(new Character(y).toString());
 }
}

HASKELL


wellBalanced :: String -> Bool

wellBalanced xs = wellBalanced' xs empty


wellBalanced' :: String -> Stack Char -> Bool

wellBalanced' [] s = isEmpty s

wellBalanced' (x:xs) s
   
 | isOpen x   = wellBalanced' xs (push x s)

   
 | isClosed x = if (match (top s) x ) then wellBalanced' xs (pop s) else False
   
 | otherwise = wellBalanced' xs s



isOpen x = elem x "([{"

isClosed x = elem x ")]}"



match '(' ')' = True

match '[' ']' = True

match '{' '}' = True

match _ _ = False

viernes, 21 de febrero de 2014

EXAMEN Febrero 2014 Estructuras de datos. Resolución Segunda Parte. Java

¿Al fin viernes no? Primer fin de semana del segundo cuatrimestre para los de Ingeniería Informática. ¿Sabeis ya todas las notas? Espero que todo bien ;)

Bueno, aquí os traigo la segunda parte del examen de ED de este año. La parte de Java. El enunciado lo teneis aquí.

El archivo resultado .java lo teneis aqui para descargar, si no quereis andar copiando y pegando.

Aquí os dejo el code ;)


package dataStructures.graph;

import java.util.Iterator;

import dataStructures.list.List;
import dataStructures.set.Set;
import dataStructures.set.HashSet;

public class SCCDiGraph {

  /* 
   * apartado A
   */
   public static  DiGraph reverseDiGraph(DiGraph g){
   DiGraph reversedDiGraph = new DictionaryDiGraph();
   for(V v : g.vertices()){ //Introduce los vértices
    reversedDiGraph.addVertex(v);
   }
   
   for(V v : g.vertices()){ //Introduce las aristas
    for(V w : g.vertices()) {
     if(g.successors(v).isElem(w)) {
      reversedDiGraph.addDiEdge(w, v);
     }
    }
   }
   
   return reversedDiGraph;
  }

   /* 
    * apartado B
    */
  public static  DiGraph restrictDiGraph(DiGraph g, Set vs){

   DiGraph restrictedGraph = new DictionaryDiGraph();
   for(V v : vs) {
    restrictedGraph.addVertex(v);
   }
   
   
   for(V v : vs) {
    for(V w : vs) {
     if(g.successors(v).isElem(w)) {
      restrictedGraph.addDiEdge(v, w);
     }
    }
   }
   
   return restrictedGraph;
  }

  /* 
    * apartado C
    */
  public static  Set sccOf (DiGraphg, V src) {
   Set vertices = new HashSet<>();
   
   DepthFirstTraversal busqueda = new DepthFirstTraversal(g, src); //1)
   vertices =  iterableToSet(busqueda.vertices());
   
   DiGraph  restricted = restrictDiGraph(g, vertices); //2)
   DiGraph  inversed = reverseDiGraph(restricted); //3)
   
   DepthFirstTraversal acabada = new DepthFirstTraversal(inversed, src); //4)
   
   Set vertices2 = iterableToSet(acabada.vertices());
   
   return vertices2;
  }

  
  /* 
    * apartado D
    */
  public static <V> Set<Set<V>> stronglyConnectedComponentsDiGraph(DiGraph<V> graph) {
   Set<Set<V>> components  = new HashSet<Set<V>>();
   Set<V> auxiliar = graph.vertices();
   for(V v : graph.vertices()) {
    if(auxiliar.isElem(v)) {
     Set<V> aux2 = sccOf(graph, v);
     components.insert(aux2);
     for(V w : aux2) {
      auxiliar.delete(w);
     }
     
    }
    
   }
   return components;
  }

 static  Set iterableToSet(Iterable it) {
  Set set = new HashSet();
  for(V v : it)
   set.insert(v);
  return set;  
 }
 
 

}
De todos modos aquí os dejo un main de testeo para que veais si el vuestro está bien.
public static void main(String[] args) {
 // TODO Auto-generated method stub
  DiGraph graph = new DictionaryDiGraph<>();
    graph.addVertex('A');
    graph.addVertex('B');
    graph.addVertex('C');
    graph.addVertex('D');
    graph.addVertex('E');
    graph.addVertex('F');
    graph.addVertex('G');
    graph.addVertex('H');

    graph.addDiEdge('A', 'B');
    graph.addDiEdge('B', 'E');
    graph.addDiEdge('E', 'A');
    graph.addDiEdge('B', 'F');
    graph.addDiEdge('E', 'F');
    graph.addDiEdge('F', 'G');
    graph.addDiEdge('G', 'F');
    graph.addDiEdge('C', 'G');
    graph.addDiEdge('H', 'G');
    graph.addDiEdge('C', 'D');
    graph.addDiEdge('D', 'C');
    graph.addDiEdge('D', 'H');
    graph.addDiEdge('H', 'D');
    
    
    System.out.println(graph);
    System.out.println(reverseDiGraph(graph));
    Set vertices = new HashSet<>();
    vertices.insert('A');
    vertices.insert('B');
    vertices.insert('E');
    vertices.insert('F');
    vertices.insert('G');
    System.out.println(restrictDiGraph(graph, vertices));
    
    System.out.println(stronglyConnectedComponentsDiGraph(graph));
    
 }

miércoles, 19 de febrero de 2014

EXAMEN Febrero 2014 Estructuras de datos. Resolución Primera Parte. Haskell.

Pues bueno, aquí va la parte en Haskell del examen. Dadme vuestras opiniones. Al menos lo que tiene que hacer a mi me lo hacía xD. A ver si saco notaza ^^

Si preferís descargarlo (a mi me haceis un favor) podréis hacerlo de aqui.
Los enunciados y bibliotecas se encuentran aqui

Ahí os va el code ;)


module StronglyConnectedComponents  where

import DataStructures.Graph.DiGraph 

import DataStructures.Graph.DiGraphDFT
    ( dft         -- :: (Ord a) => DiGraph a -> a -> [a] 
    )

import Data.List--( (\\), intersect )
import DataStructures.Stack.LinearStack
-------
-- A --
-------
reverseDiGraph :: Eq a => DiGraph a -> DiGraph a
reverseDiGraph g = mkDiGraphEdges (vertices g) (aux (diEdges g) )

aux :: [DiEdge a] -> [DiEdge a] 
aux xs = [(y:->z) | (z:->y) <- xs]


restrictDiGraph :: Eq a => DiGraph a -> [a] -> DiGraph a
-- el subgrafo de g con vértices en vs
restrictDiGraph g vs = deleteVertices' vs g

deleteVertices :: Eq a => [a] -> DiGraph a -> DiGraph a
deleteVertices xs g = mkDiGraphSuc (vertices g\\xs) suc' 
   where suc' v = (successors g v) \\ xs

deleteVertices' :: Eq a => [a] -> DiGraph a -> DiGraph a
deleteVertices' xs g = mkDiGraphSuc (intersect(vertices g) xs) suc' 
   where suc' v = intersect (successors g v)  xs

{-
*StronglyConnectedComponents> restrictDiGraph gExample [A,B,H,I,J]
Graph, Vertices : [A,B,H], DiEdges: [A :-> B]

*StronglyConnectedComponents> reverseDiGraph $ restrictDiGraph gExample [A,B,H] 
Graph, Vertices : [A,B,H], DiEdges: [B :-> A]
-}

type SCC a = [a] 

-------
-- C --
-------
sccOf :: Ord a => DiGraph a -> a -> SCC a
-- la scc (strongly connected component) en el grafo g del vértice v
sccOf g v =  dft (reverseDiGraph (restrictDiGraph g (dft g v))) v

{-
*StronglyConnectedComponents> sccOf  gExample A
[A,E,B]
-}

-------
-- D --
-------
-- todas las componentes
sccs :: Ord a => DiGraph a -> [SCC a]
sccs g  = aux3 g (vertices g) []

aux3 :: Ord a => DiGraph a -> [a] -> [SCC a] -> [SCC a]
aux3 g [] zs     = zs
aux3 g (x:xs) zs = aux3 g (xs\\vs)  (vs:zs)
  where vs = sccOf g x


{-
*StronglyConnectedComponents> sccs gExample
[[A,E,B],[C,D,H],[F,G]]
it :: [SCC Vertice]

-- las componentes son tres ciclos
-}


-------------------------------------
--- El grafo del enunciado del examen 
-------------------------------------

data Vertice = A|B|C|D|E|F|G|H|I|J|K deriving (Eq,Show,Ord,Enum)


gExample = mkDiGraphEdges [A .. H] 
                         [ A :-> B, B:-> F, B:->E, C:->D, C:->G, 
                           D:->C, D:->H, E:->F, E:->A,
                           F:->G, G:->F, H:->D, H:->G]


Como veis. Importé el intersect de Data.List (espero que no me reste xD). Los comentarios que empiezan por "StronglyConnectedComponents" son lo que tendrías que poner y lo que debería salir con el grafo de ejemplo que se crea al final (es el mismo que el del enunciado)

martes, 18 de febrero de 2014

EXAMEN Febrero 2014. Estructuras de Datos. Enunciados

Buenas. Aquí os traigo los enunciados del examen de Estructuras de datos que hemos hecho hoy (día 18/02/2014) en Ingeniería Informática en la UMA.  Tanto la parte de Haskell como la de Java son el mismo programa. La resolución de la de Haskell la subiré el Miércoles y la de Java el viernes.

Aquí los archivos necesarios. (Debeis esperar el tiempo que os dice y arriba a la derecha darle a entrar).
Nota: Los códigos además los pegaré, pero con las librerías no puedo hacerlo. ;)
Plantilla Haskell -> Es sobre lo que deberíais de trabajar.
Librerías que utilizar -> Debeis descomprimir el archivo en el mismo sitio donde tengais la plantilla.
Librerías de Java
Plantilla de Java -> Es un txt. Copiadlo en la class.

Para la de Haskell, en la misma carpeta deberían de estar la plantilla (Es el archivo sobre el que codeareis) y la carpeta DataStructures (Dentro del zip).
Para la de Java. Debeis crear un paquete llamado dataStructures.graph y dentro de él, una clase que se llame SCCDiGraph. Luego importais las librerias (el unit6.jar)

Aquí teneis el enunciado:
Cómputo de las Componentes Fuertemente Conexas de un digrafo.
Dado un digrafo g , se dice que dos vértices v y w están fuertemente conectados (escrito v FC w) si existe un camino desde v hasta w y otro camino desde w hasta v . Por ejemplo, para el grafo de la izquierda de la Figura 1, los vértices A y B están fuertemente conectados, pero los vértices F y B no lo están.
 La relación FC es una relación de equivalencia y sus clases de equivalencia se llaman Componentes Fuertemente Conexas o SCCs (Strongly Connected Components). Por ejemplo, la colección [A,E,B]es una clase de equivalencia, o sea, una componente fuertemente conexa. En la parte derecha de la Figura 1 aparecen del mismo color los vértices de cada una de las tres componentes. Para computar la SCC (Strongly Connected Component) de un vértice v podemos seguir los siguientes pasos: 

1. Exploramos en profundidad el grafo g desde v; sea vs la lista de vértices obtenida. Entre estos vértices estará la componente fuertemente conexa de v ya que la lista vs contiene solo y únicamente los vértices alcanzables desde v.
2. Por ello, nos limitaremos al subgrafo de g con vértices en vs; sea pues el grafo gr, restricción de g al conjunto de vértices de vs. 
3. Ahora computamos g’, el grafo inverso de gr. Entonces, para cada vértice w visitable desde v en el grafo g’, existirá un camino desde w hasta v en el grafo original g. 
4. Si exploramos en profundidad el grafo g’ desde v, la lista de vértices obtenida es la Componente Fuertemente Conexa (SCC) de v.
Por ejemplo, para el grafo de la Figura 1, la exploración en profundidad desde A proporciona la lista de vértices [A,B,F,G,E] = vs coloreados en rojo en la parte izquierda de la Figura 2. La restricción de g sobre esta lista, es decir el subgrafo gr obtenido en el paso 2, aparece en el centro de la Figura 2. Su grafo inverso g’obtenido en el paso 3, aparece en la parte derecha de la Figura 2. Al explorar en profundidad g’ partiendo del vértice A (paso 4) obtenemos la lista [A,E,B], que es la componente fuertemente conexa del vértice A.


Ejercicios a realizar:
(A) Escribe la función que devuelve el grafo inverso de un digrafo:
reverseDiGraph :: Eq a => DiGraph a -> DiGraph a


(B) Escribe la función que toma un grafo g y una lista de vértices vs y devuelve el subgrafo de g con vértices en vs:
restrictDiGraph :: Eq a => DiGraph a -> [a] -> DiGraph a


(C) Con ayuda de las funciones anteriores, siguiendo los pasos 1-4 descritos anteriormente, escribe una función para computar la SCC sobre un grafo de un determinado vértice:
type SCC a = [a]
sccOf :: Ord a => DiGraph a -> a -> SCC a


(D) Aplicando reiteradamente la función anterior, podemos obtener todas las componentes del grafo original
eliminando en cada paso los vértices de la componente computada. Escribe la función correspondiente a este cómputo:
sccs :: Ord a => DiGraph a -> [SCC a]

Ahora en java:

(A) Define un método que tome un digrafo como argumento y devuelve su grafo inverso:
public static <V> DiGraph<V> reverseDiGraph(DiGraph<V> g)


(B) Escribe el método que toma un grafo g y una lista de vértices vs y devuelve el subgrafo de g con vértices en vs:
 public static <V> DiGraph<V> restrictDiGraph(DiGraph<V> g, Set<V> vs)


(C) Con ayuda de los métodos anteriores, siguiendo los pasos 1-4 descritos anteriormente, escribe un método para computar la SCC sobre un grafo g de un determinado vértice src:
public static <V> Set<V> sccOf (DiGraph<V> g, V src)


(D) Aplicando reiteradamente el método anterior, podemos obtener todas las componentes del grafo original
eliminando en cada paso los vértices de la componente computada. Escribe el método correspondiente a este cómputo:
public static <V> Set<Set<V>> stronglyConnectedComponentsDiGraph(DiGraph<V> g)


Aquí os pongo la plantilla de Haskell:


module StronglyConnectedComponents  where

import DataStructures.Graph.DiGraph 

import DataStructures.Graph.DiGraphDFT
    ( dft         -- :: (Ord a) => DiGraph a -> a -> [a] 
    )

import Data.List( (\\) )

-------
-- A --
-------
reverseDiGraph :: Eq a => DiGraph a -> DiGraph a
reverseDiGraph g = undefined

-------
-- B --
-------
restrictDiGraph :: Eq a => DiGraph a -> [a] -> DiGraph a
-- el subgrafo de g con vértices en vs
restrictDiGraph g vs =  undefined


deleteVertices :: Eq a => [a] -> DiGraph a -> DiGraph a
deleteVertices xs g = mkDiGraphSuc (vertices g\\xs) suc' 
   where suc' v = (successors g v) \\ xs


{-
*StronglyConnectedComponents> restrictDiGraph gExample [A,B,H,I,J]
Graph, Vertices : [A,B,H], DiEdges: [A :-> B]

*StronglyConnectedComponents> reverseDiGraph $ restrictDiGraph gExample [A,B,H] 
Graph, Vertices : [A,B,H], DiEdges: [B :-> A]
-}

type SCC a = [a] 

-------
-- C --
-------
sccOf :: Ord a => DiGraph a -> a -> SCC a
-- la scc (strongly connected component) en el grafo g del vértice v
sccOf g v = undefined

{-
*StronglyConnectedComponents> sccOf  gExample A
[A,E,B]
-}

-------
-- D --
-------
-- todas las componentes
sccs :: Ord a => DiGraph a -> [SCC a]
sccs g  = undefined


{-
*StronglyConnectedComponents> sccs gExample
[[A,E,B],[C,D,H],[F,G]]
it :: [SCC Vertice]

-- las componentes son tres ciclos
-}


-------------------------------------
--- El grafo del enunciado del examen 
-------------------------------------

data Vertice = A|B|C|D|E|F|G|H|I|J|K deriving (Eq,Show,Ord,Enum)

gExample = mkDiGraphEdges [A .. H] 
                         [ A :-> B, B:-> F, B:->E, C:->D, C:->G, 
                           D:->C, D:->H, E:->F, E:->A,
                           F:->G, G:->F, H:->D, H:->G]




Y aquí la de Java ;)
package dataStructures.graph;

import dataStructures.set.Set;
import dataStructures.set.HashSet;

public class SCCDiGraph {

  /* 
   * apartado A
   */
   public static  DiGraph reverseDiGraph(DiGraph g){
   DiGraph reversedDiGraph = new DictionaryDiGraph();
   // Vuestro Resultado aqui
   return reversedDiGraph;
  }

   /* 
    * apartado B
    */
  public static  DiGraph restrictDiGraph(DiGraph g, Set vs){

   DiGraph restrictedGraph = new DictionaryDiGraph();
   // Vuestro Resultado aqui

   return restrictedGraph;
  }

  /* 
    * apartado C
    */
  public static  Set sccOf (DiGraphg, V src) {
   //Vuestro Resultado aqui

   return null;
  }

  
  /* 
    * apartado D
    */
  public static  Set> stronglyConnectedComponentsDiGraph(DiGraph graph) {
   Set> components  = new HashSet>();
   // Vuestro Resultado aqui

   return components;
  } 

 static  Set iterableToSet(Iterable it) {
  Set set = new HashSet();
  for(V v : it)
   set.insert(v);
  return set;  
 }
 
} // class

Pasadlo bien :p Saludos ;)

lunes, 17 de febrero de 2014

Práctica de creación de Jarras (Parte 2) Excepciones.

Bueno, Ahora vamos a retomar la práctica de las jarras pero con algunos cambios. Vamos a introducir las excepciones.
Para ello haremos lo siguiente:

1.- Modificar el programa principal para que en lugar de crear dos jarras con capacidad inicial fija de 5 y 7 litros cada una, sea posible pasar las capacidades iniciales de las dos jarras como parámetros de entrada al programa principal. Esto significa que las capacidades iniciales de las dos jarras podrán ser diferentes para cada llamada al programa. En este caso, se podrían producir las siguientes excepciones:
a) ArrayIndexOutOfBoundsException: si se intenta ejecutar el nuevo programa principal sin parámetros de entrada, o con menos parámetros de entrada de los necesarios.
b) NumberFormatException: si se intenta ejecutar el nuevo programa principal con parámetros que no sean numéricos.
c) RuntimeException: si se intenta ejecutar el nuevo programa principal con jarras que tengan capacidad 0 o negativa (suponiendo que en la versión anterior de la práctica se lanzaba esta excepción en el constructor de la clase Jarra cuando el parámetro capacidadInicial del constructor era 0 o un número negativo).

2.- Capturar desde el programa principal la excepción ArrayIndexOutOfBoundsException. Mostrar el siguiente mensaje al usuario:
ERROR: Use: TestJarra capacidadInicialJarra1 capacidadInicialJarra2

3) Capturar desde el programa principal la excepción NumberFormatException y mostrar el siguiente mensaje al usuario:
ERROR: Algún parámetro no es un número

4) Crear una excepción JarraCapacidadException que será lanzada por la clase Jarra cuando
la capacidad inicial de la Jarra sea menor o igual a 0 (en lugar de lanzar la excepción de tipo
RuntimeException).

5) Modificar el programa principal para capturar y manejar la excepción JarraException.

Aquí tenemos las soluciones ;)

Clase JarraCapacidadException:

@SuppressWarnings("serial")
public class JarraCapacidadException extends Exception{ 
 //Si fuera una excepcion no comprobada se usaria extends RunTimeException.
  public JarraCapacidadException() {
   super();
  }
  public JarraCapacidadException(String e) {
   super(e);
  }
 }
Nota: el @SuppressWarnings("serial") Lo que hace es que no nos de un molesto warning que no nos interesa. Solo eso;)

Clase JarraException:

public class JarraException {
 private final int capacidad;
 private int cantidad;
 
 public JarraException(int capacidadInicial) throws JarraCapacidadException{
  if (capacidadInicial<=0) throw new JarraCapacidadException("Error, capacidad incorrecta.");
  capacidad = capacidadInicial;
  cantidad = 0;
 }
 
 
 
 public int capacidad() {
  return capacidad;
 }
 
 public int cantidad() {
  return cantidad;
 }
 
 public void llena() {
  cantidad = capacidad;
 }
 
 public void vacia() {
  cantidad = 0;
 }
 
 public void llenaDesde(JarraException j){
  int cantidadMinima = Math.min(capacidad- cantidad, j.cantidad);
  
  cantidad   += cantidadMinima;
  j.cantidad -= cantidadMinima;
 }


 public String toString(){
  String frase = " capacidad de " + capacidad + " y cantidad de " + cantidad + " de líquido.";
  return frase;
 }
}

Clase TestJarraException:

public class TestJarraException {
 public static void main(String[] arg) throws Exception
 {
 try{
  JarraException jarraA = new JarraException(Integer.parseInt(arg[0]));
  JarraException jarraB = new JarraException(Integer.parseInt(arg[1]));
  jarraA.llena();
  jarraB.vacia();
  System.out.println("JA "+ jarraA.toString());
  System.out.println("JB "+ jarraB.toString());
  jarraB.llenaDesde(jarraA);
  jarraA.llena();
  jarraB.llenaDesde(jarraA);
  jarraB.vacia();
  jarraB.llenaDesde(jarraA);
  jarraA.llena();
  jarraB.llenaDesde(jarraA);
  System.out.println("JA "+ jarraA.toString());
  System.out.println("JB "+ jarraB.toString());
  } catch (JarraCapacidadException e) {
   System.out.println("ERROR: Use: TestJarra capacidadInicialJarra1 capacidadInicialJarra2");
  } catch (NumberFormatException e) {
   System.out.println("ERROR: Algún parámetro no es un número");
  } catch (RuntimeException e){
   System.out.println("Capacidad nula.");
   
  }
 }
 
}
Espero que le vayais pillando el truco a esto. No es difícil, sólo es ponerse ^^ Saludos ;)

domingo, 16 de febrero de 2014

Práctica Coche y Coche Importado de Herencia

Cread la clase Coche cuyas instancias mantienen el nombre del coche y su precio (antes de impuestos).
El precio total de un coche se calcula aplicando un IVA al precio marcado.
Este IVA puede variar (por defecto el IVA es del 16%), pero será siempre el mismo para todos los coches.
Proporcionad métodos para cambiar el IVA, calcular el precio total y mostrar el coche como cadena de caracteres con el formato "nombre -> precio".

Un coche importado es un coche para el que además del IVA aplicamos un impuesto de homologación. El impuesto de homologación es específico de cada vehículo, y será dado en el momento de su creación. El precio total de un coche importado se calcula como el de cualquier coche pero ahora hay que sumar este nuevo impuesto. Cread la clase CocheImportado para mantener información de coches importados. El impuesto se guardará como total, mientras que el IVA se guardará como porcentaje(por ejemplo, el IVA de 16% se guardará como 0.16).

Aquí teneis la clase de testeo.
public class EjCoches {
 static public void main(String[] args) {
  Coche[] cs = { new Coche(" Seat Panda", 15000),
  new CocheImportado("Ferrari T-R", 65000, 8000),
  new Coche("Seat Toledo", 21000),
  new CocheImportado("Jaguar XK", 41000, 6000),
  new CocheImportado("Porche GT3", 44000, 7000) };
  for(Coche c : cs) {
   System.out.println(c);
  }
  // Cambiamos el iva a todos los coches
  Coche.setPiva(0.18);
  System.out.println("Con IVA de 18%");
  for(Coche c : cs) {
   System.out.println(c);
  }
 }
}

Y aquí los resultados del test:



Seat Panda -> 17400.0
Ferrari T-R -> 83400.0
Seat Toledo -> 24360.0
Jaguar XK -> 53560.0
Porche GT3 -> 58040.0
Con IVA de 18%
 Seat Panda -> 17700.0
Ferrari T-R -> 84700.0
Seat Toledo -> 24780.0
Jaguar XK -> 54380.0
Porche GT3 -> 58920.0

Ahora os dejo el código de la clase Coche:



public class Coche {
 private String nombre;
 private double precio;
 public static double PIVA = 0.16;
 
 public Coche(String n, double p) {
  nombre = n;
  precio = p;
 }
 
 public double precioTotal() {
  
  return precio*(1+PIVA);
 }
 
 public static void setPiva( double i) {
  PIVA = i;
 }
 
 public String Nombre() {
  return nombre;
 }
 
 public String toString() {
  return this.Nombre() + " -> " + this.precioTotal();
 }
}
Y el de la clase CocheImportado:

public class CocheImportado  extends Coche{
 private double homologacion;
 
 public CocheImportado(String nombre, double p, double h) {
  super(nombre, p);
  homologacion = h;
 }
 
 public double precioTotal() {
  
  return super.precioTotal()+homologacion;
 }
}

Lo único que hay que recalcar es que para la clase Coche Importado hemos usado un "super(nombre, p);" en el constructor. Ésto lo que dice es algo como "CocheImportado es un coche con las caracterñisticas nombre y p" pero que además tiene otro valor más. También hemos usado super en el método precioTotal. De esa forma calculamos el precioTotal del coche tal y como lo calcularía el otro método. De esta forma nos ahorramos bastante que escribir ^^ Saludos ;)

viernes, 14 de febrero de 2014

Ejercicios de Introducción a Haskell

Aquí unos ejercicios básicos para empezar a entender Haskell. Con ellos empezamos a conocer sus tipos básicos, la definición de funciones y operadores, el manejo de tuplas, las pruebas con QuickCheck... ¡Importante importar Test.QuickCheck para realizar esto último! (:

{-
-- Ejercicio 1
Tres enteros positivos x, y, z constituyen una terna pitagórica si x^2+y^2=z^2, es decir, si son los lados de un triángulo rectángulo.

a) Define la función
esTerna :: Integer -> Integer -> Integer -> Bool
que compruebe si tres valores forman una terna pitagórica
-}


esTerna :: Integer -> Integer -> Integer -> Bool
esTerna x y z
        | (x^2 +y^2 == z^2 )= True
        | (x^2 + z^2 == y^2) = True
        | (y^2 + z^2 == x^2) = True
        | otherwise = False
{-
b) Es fácil demostrar que para cualesquiera x e y enteros positivos con x>y, la terna (x2-y2, 2xy, x2+y2) es pitagórica.
Usando esto, escribe una función terna que tome dos parámetros y devuelva una terna pitagórica
-}
terna :: Integer -> Integer -> (Integer, Integer, Integer)
terna x y= (x^2 - y^2, 2*x*y, x^2 + y^2)

{-
c) Lee y entiende la siguiente propiedad, para comprobar que todas las ternas generadas por la función terna son pitagóricas:
-}
p_ternas x y = x>0 && y>0 && x>y ==> esTerna l1 l2 h
  where
    (l1,l2,h) = terna x y

{-
--------------------------------------------------------
 Ejercicio 2

Define una función polimórfica
intercambia :: (a,b) -> (b,a)
que intercambie de posición los datos de la tupla:
--------------------------------------------------------
-}

intercambia :: (a,b) -> (b,a)
intercambia (x,y) = (y,x)

{-
---------------------------------------------------------
Ejercicio 3
Este ejercicio versa sobre ordenación de tuplas.
---------------------------------------------------------

a) Define una función sobrecargada para tipos con orden
ordena2 :: Ord a => (a,a) -> (a,a)
que tome una tupla con dos valores del mismo tipo y la devuelva ordenada de menor a mayor:
-}
ordena2 :: Ord a => (a,a) -> (a,a)
ordena2 (x,y)
        | x > y = (y,x)
        | otherwise = (x,y)

p1_ordena2 x y = enOrden (ordena2 (x,y))
  where enOrden (x,y) = x<=y
p2_ordena2 x y = mismosElementos (x,y) (ordena2 (x,y))
  where
    mismosElementos (x,y) (a,b) = (x==a && y==b) || (x==b && y==a)
{-
b) Define una función sobrecargada para tipos con orden
ordena3 :: Ord a => (a,a,a) -> (a,a,a)
que tome una tupla con tres valores del mismo tipo y la devuelva ordenada, con los elementos de menor a mayor:
-}

ordena3 :: Ord a => (a,a,a) -> (a,a,a)
ordena3 (x,y,z)
  |x>y = ordena3(y,x,z)
  |y>z = ordena3(x,z,y)
  |x>z = ordena3(z,x,y)
  |otherwise = (x,y,z)
<br />
-- c) Escribe propiedades análogas a las del apartado anterior pero para esta función, y compruébalas usando QuickCheck.

p1_ordena3 x y z = enOrden (ordena3 (x,y,z))
  where enOrden (x,y,z) = (x <= y) && (y <= z)


p2_ordena3 x y z = mismosElementos (x,y,z) (ordena3 (x,y,z))
  where mismosElementos (x,y,z) (a,b,c) = (x,y,z) == (a,b,c) ||   (x,y,z) == (a,c,b) ||  (x,y,z) == (b,a,c) ||  (x,y,z) == (b,c,a) || (x,y,z) == (c,a,b) ||  (x,y,z) == (c,b,a)

{-
----------------------------------------------------------
Ejercicio 4.
Aunque ya existe una función predefinida (max :: Ord a => a -> a -> a) para calcular el máximo de dos valores,
el objetivo de este ejercicio es que definas tu propia versión de dicha función.
----------------------------------------------------------
a) Como no está permitido redefinir una función predefinida, define una nueva y llámala max2 :: Ord a => a -> a -> a
-}

max2 :: Ord a => a -> a -> a
max2 x y
    | x > y = x
    | otherwise = y
             
     
--b) Define las siguientes propiedades que debería verificar tu función max2 y compruébalas con QuickCheck

p1_max2 x y = True ==> max2 x y == x || max2 x y == y
p2_max2 x y = True ==> max2 x y >= x || max2 x y >= y
p3_max2 x y = x>=y ==> max2 x y == x
p4_max2 x y = y>=x ==> max2 x y == y


{-
----------------------------------------------------------
Ejercicio 5
Define una función sobrecargada para tipos con orden
entre :: Ord a => a -> (a,a) -> a
que tome un valor x además de una tupla con dos valores (max,min) y compruebe si x pertenece al intervalo determinado por min y max,
devolviendo True o False según corresponda.
----------------------------------------------------------
-}

entre :: Ord a => a -> (a,a) -> Bool
entre x (i1, i2) = x >= i1 && x <= i2

{-
----------------------------------------------------------
Ejercicio 6
Define una función sobrecargada para tipos con igualdad
iguales3 :: Eq a => (a,a,a) -> Bool
que tome una tupla con tres valores del mismo tipo y devuelva True si todos son iguales.
----------------------------------------------------------
-}
iguales3 :: Eq a => (a,a,a) -> Bool
iguales3 (x,y,z) = (x == y && x == z)

{-
---------------------------------------------------------
Ejercicio 7
Recuerda que el cociente y el resto de la división de enteros se corresponde con las funciones predefinidas div y mod.
---------------------------------------------------------

a) Define una función descomponer que, dada una cantidad positiva de segundos, devuelva la descomposición en horas,
 minutos y segundos en forma de tupla, de modo que los minutos y segundos de la tupla estén en el rango 0 a 59.
-}
type TotalSegundos = Integer
type Horas = Integer
type Minutos = Integer
type Segundos = Integer

descomponer :: TotalSegundos -> (Horas,Minutos,Segundos)
descomponer x = (horas, minutos, segundos)
   where
     (horas,resto)      = divMod x 3600
     (minutos, segundos)   = divMod resto 60

--b) Comprueba la corrección de tu función verificando con QuickCheck que cumple la siguiente propiedad:

p_descomponer x = x>=0 ==> h*3600 + m*60 + s == x && entre m (0,59) && entre s (0,59)
  where (h,m,s) = descomponer x

-----------------------------------------------------------
-- Ejercicio 8
-----------------------------------------------------------
unEuro :: Double
unEuro = 166.386

-- a) Define una función pesetasAEuros que convierta una cantidad (de tipo Double) de pesetas en los correspondientes euros.
pesetasAEuros :: Double -> Double
pesetasAEuros p = p/unEuro

-- b) b) Define la función eurosAPesetas que convierta euros en pesetas.
eurosAPesetas :: Double -> Double
eurosAPesetas e = e* unEuro


------------------------------------------------------------
-- Ejercicio 9
------------------------------------------------------------
infix 4 ~=
(~=) :: Double -> Double -> Bool
x ~= y = abs (x-y) < epsilon
  where epsilon = 1/1000

p_inversas x = eurosAPesetas (pesetasAEuros x) ~= x

{-
-----------------------------------------------------------
-- Ejercicio 10
a) Define una función raíces que tome tres parámetros (correspondientes a los coeficientes a, b y c de la ecuación) y devuelva una
 tupla con las dos soluciones reales de la ecuación (para calcular la raíz cuadrada, usa la función predefinida sqrt).
Recuerda que el discriminante se define como b^2-4ac y que la ecuación tiene raíces reales si el discriminante no es negativo.
-----------------------------------------------------------
-}

raíces :: (Ord a, Floating a) => a -> a -> a -> (a, a)
raíces a b c
  | dis < 0     = error "Raíces no reales"
  | otherwise   = ((-b + raizDisc) / denominador, (-b - raizDisc) / denominador)
 where  dis     = b^2 - 4*a*c
        raizDisc = sqrt dis
        denominador = 2*a

p2_raíces a b c  = a/= 0 && b^2 - 4*a*c >= 0   ==> esRaíz r1 && esRaíz r2
  where
   (r1,r2) = raíces a b c
   esRaíz r = a*r^2 + b*r + c ~= 0

------------------------------------------------------------
-- Ejercicio 11
-- Define una función esMúltiplo sobrecargada para tipos integrales que tome dos valores x e y, y devuelva True si x es múltiplo de y.
-------------------------------------------------------------

esMúltiplo :: Integer -> Integer -> Bool
esMúltiplo x y = (mod x y == 0)

------------------------------------------------------------
-- Ejercicio 12
-- Define el operador de implicación lógica (==>>) :: Bool -> Bool -> Bool de forma que sea asociativo a la izquierda,
--con precedencia menor que los operadores conjunción y disyunción
------------------------------------------------------------

infixl 1 ==>>
(==>>) :: Bool -> Bool -> Bool

False ==>> y    =       True
True ==>>  y     =       y

{-
------------------------------------------------------------
-- Ejercicio 13
Los años bisiestos son los años múltiplos de 4. Una excepción a esta regla son los años múltiplos de 100, que sólo se consideran bisiestos
si además son múltiplos de 400. Define una función esBisiesto que tome como parámetro un año y devuelva True si es bisiesto.
------------------------------------------------------------
Ayuda: utiliza el operador de implicación lógica y la siguiente frase: “n es bisiesto si satisface las dos condiciones siguientes:
(a) es múltiplo de 4, y (b) si n es múltiplo de 100 entonces n es múltiplo de 400”.
-}

esBisiesto :: Integer -> Bool
esBisiesto x
  | (mod x 4 == 0) &&  ((mod x 100==0) ==>> (mod x 400 == 0)) = True
  | otherwise = False

{-
------------------------------------------------------------
Ejercicio 14
Aunque ya existe en Haskell el operador predefinido (^) para calcular potencias, el objetivo de este problema es que definas
tus propias versiones recursiva de este operador.
------------------------------------------------------------
a) A partir de la propiedad b^n = b·b^(n-1) define una función recursiva potencia que tome un entero b y un exponente natural n y devuelva b^n.
-}
potencia :: Integer -> Integer -> Integer
potencia x n
  | n == 0      =       1
  | n > 0       =       x * potencia x (n-1)
  | otherwise   = error "Exponente negativo"

-- b)
potencia' :: Integer -> Integer -> Integer
potencia' x n
  | n == 0              =       1
  | even n         = potencia' x (div n 2) * potencia' x (div n 2)
  | otherwise       = x * potencia' x (div (n-1) 2) * potencia' x (div (n-1) 2)
-- c) Comprueba con QuickCheck la corrección de ambas funciones mediante la siguiente propiedad
p_pot b n = n>=0 ==> potencia b n == sol && potencia' b n == sol
  where sol = b^n

{-
--------------------------------------------------------------
-- Ejercicio 15
Dado un conjunto finito con todos sus elementos diferentes, llamamos permutación a cada una de las posibles ordenaciones de los
elementos de dicho conjunto. Por ejemplo, para el conjunto {1,2,3}, existen un total de 6 permutaciones de sus elementos:
{1,2,3}, {1,3,2}, {2,1,3}, {2,3,1}, {3,1,2} y {3,2,1}. El número de permutaciones posibles para un conjunto con n elementos
viene dada por el factorial de n (se suele escribir n!), que se define como el producto de todos los números naturales menores
o iguales a n. Escribe una función factorial que tome como parámetro un número natural y devuelva su factorial.
Dado que el factorial crece muy rápido, usa el tipo Integer, es decir, factorial :: Integer -> Integer.
--------------------------------------------------------------
-}
factorial :: Integer -> Integer
factorial 1 = 1
factorial n = n* factorial(n-1)

--------------------------------------------------------------
-- Ejercicio 16 -- FALTA APARTADO C
-- Este ejercicio estudia la división entera (exacta) de números enteros.
--------------------------------------------------------------
{-
a) Define una función divideA que compruebe si su primer argumento divide exactamente al segundo.
-}
divideA :: Integer -> Integer -> Bool
divideA a b = (mod b a == 0)

-- b)
p1_divideA x y = y/=0 && y `divideA` x ==> div x y * y == x

-- c) Escribe una propiedad p2_divideA para comprobar usando QuickCheck que si un número divide a otros dos, también divide a la suma de ambos.
p2_divideA a b c = a /= 0 && divideA a b && divideA a c ==> divideA a (b+c)


{-
-------------------------------------------------------------
-- Ejercicio 17
La mediana de un conjunto de valores es aquel valor tal que el 50% de los valores del conjunto son menores o iguales a él, y los restantes mayores o iguales.
Queremos definir una función para calcular la mediana de los valores de una tupla de cinco elementos
mediana :: Ord a => (a,a,a,a,a) -> a
de forma que se tenga: mediana (3,20,1,10,50)  10
Observa que se satisface 1 , 3 ≤ 10 ≤ 20,50. Teniendo en cuenta este detalle, define la función a través de ecuaciones con guardas:
-------------------------------------------------------------
-}

mediana :: Ord a =>; (a,a,a,a,a) -> a
mediana (x,y,z,t,u)
  | x > z = mediana (z,y,x,t,u)
  | y > z = mediana (x,z,y,t,u)
  | t < z = mediana (x, y, t, z, u)
  | u < z = mediana (x, y, u, t ,z)
  | otherwise = z


miércoles, 12 de febrero de 2014

Juegos de Cartas. La siete y Media

Pues hoy vamos a tirarle otra vez a la herencia, pero ésta vez con un conocido juego de cartas como es la Siete y Media. Este esquema va a ser algo más feo, pero veréis como se le coge el truco en seguida ;)

sin contar la clase ManoSieteyMedia, lo demás nos sirve para crear casi cualquier juego de cartas. Es por eso por lo que hemos hecho el tipo abstracto. Más adelante usaremos estas clases para (creando una clase simple para la mano) poder crear otros juegos. Aquí teneis la clase test ;)

public class SieteyMedia {
 public static void main(String[] args) {
  //Se crean el mazo, el jugador y la banca
  Mazo mazo = new Mazo();
  ManoSieteyMedia jugador = new ManoSieteyMedia();
  ManoSieteyMedia banca = new ManoSieteyMedia();
  
  //Se reparten las cartas iniciales: 
                //Una al jugador y una a la banca
  jugador.agnadeCarta(mazo.daCarta());
  banca.agnadeCarta(mazo.daCarta());
  
  //El jugador pide cartas mientras según su estrategia
  while(jugador.cuentaPuntos()<=5){
   System.out.println(
                              "El jugador pide una carta extra");
   jugador.agnadeCarta(mazo.daCarta());
  }
  
  //La banca se planta si el jugador se ha pasado.
                //En caso contrario pide cartas
  if(jugador.cuentaPuntos()<=7.5){ 
                  //el jugador no se ha pasado
   while(banca.cuentaPuntos()<7.5 && 
                            banca.cuentaPuntos()<jugador.cuentaPuntos()){
    System.out.println(
                                       "La banca pide una carta extra");
    banca.agnadeCarta(mazo.daCarta());
   }
  }
  //Se cuentan los puntos obtenidos y se decide el ganador
  double puntosJ = jugador.cuentaPuntos();
  double puntosB = banca.cuentaPuntos();
  
  if(puntosJ<=7.5 && (puntosB>7.5 || puntosJ>puntosB)){

   System.out.println("Gana el jugador con "+jugador
                            +" ("+ puntosJ+" puntos) frente a "+ banca+
                            " ("+puntosB+" puntos) de la banca");
  }else if (puntosB<=7.5){
   System.out.println("Gana la banca con "
                            +banca+" ("+ puntosB+
                            " puntos) frente a "+ jugador+" ("+
                            puntosJ+" puntos) del jugador");
  }else{
   System.out.println("No hay ganador: Jugador "+ 
                            jugador+" ("+puntosJ+" puntos) y banca "
                            + banca +" ("+
                            puntosB+" puntos) se han pasado");
  }
 }
}
Ahora procedo a poneros las soluciones ;)

Primero la clase abstracta Mano.

public abstract class Mano{
 protected Carta[] cartas;
 protected int numCartas;
 static final int TOPE = 20;
 public Mano() {
  numCartas = 0;
  cartas = new Carta[TOPE];
 }
 
 public Mano(int num) {
  cartas = new Carta[num];
  numCartas = 0;
 }
 
 public void descartaTodas() {
  numCartas = 0;
 }
 
 public void agnadeCarta(Carta c) {
  if(numCartas >= TOPE) 
               throw new RuntimeException("No puedes añadir mas cartas");
  cartas[numCartas] = c;
  numCartas ++;
 }
 
 public int numeroDeCartas() { 
  return numCartas;
 }
 
 public abstract double cuentaPuntos();
 
 public String toString() {
  String std = "";
  for(int i = 0; i < numCartas; i++) {
   std = std + " "+ cartas[i];
  }
  return std;
 }
}

Ahora os pondré la clase Carta: Nota: Fijaos que el enum de los palos va dentro de ésta ;)
public class Carta {
 public static enum Palo { PICA, TREBOL, DIAMANTE, CORAZON};
 private static String[] nombreCarta = {"AS", "2", "3", "4",
                                               "5", "6", "7", "8",
                                               "9", "10", "J", "Q",
                                               "K"};
 
 private int valor;
 private Palo palo;
 
 public Carta(int v, Palo p){
  valor = v;
  palo = p;
 }
 public int valor() {return valor;}
 public Palo palo() {return palo;}
 public String toString() {
  return nombreCarta[valor-1] + " de " + palo;
 }
 
}
Vamos ahora con la clase Mazo ;)
import java.util.Random;
public class Mazo {
 private static Random alea = new Random();
 private Carta[] mazo;
 private int numCartas;
 
 public Mazo() {
  mazo = new Carta[52]; //Creo el array de cartas.
  for(int n = 1; n < 13; n++) {
   for(Carta.Palo p: Carta.Palo.values()) {
    mazo[numCartas] = new Carta(n, p);
    numCartas++;
   }
  }
 }

 public void baraja() {
  for(int i = 0; i< numCartas; i++) {
   int r = alea.nextInt(numCartas);
   Carta c = mazo[i];
   mazo[i] = mazo[r];
   mazo[r] = c;
  }
 }

 public int numeroDeCartas() {
  return numCartas;
 }
 
 public Carta daCarta(){ 
  if (this.numeroDeCartas()==0) 
                   throw new RuntimeException("No quedan cartas.");
  numCartas--;
  return mazo[this.numeroDeCartas()];
 }
}

Y ya por último con la clase ManoSieteYMedia:
public class ManoSieteyMedia extends Mano{
 public double cuentaPuntos() {
  double puntos = 0;
  for(int i = 0; i<numCartas; i++) {
   puntos += cartas[i].valor();
  }
  return puntos;
 }
}

Como veis no son demasiado complicadas ;) Es más, si quisieramos definir otro juego, valdría (en un principio) con definir una nueva clase 'ManoNuestroJuego' que heredara de Mano y que definiera cuentaPuntos(). Simple, ¿verdad?

Si algún día me da la picada, subiré (usando estas mismas clases) un proyecto que hice de un solitario Spider, pero ya más adelante cuando hayamos visto algo de IDEs ;)

Disfrutadlo y no olvideis comentarme vuestras impresiones.

Saludos

lunes, 10 de febrero de 2014

Vector y Recta.

Para empezar usaremos la clase Punto que vimos en las prácticas anteriores. Basca con arrastrarla a la carpeta src de nuestro proyecto y ya estará importada ;)

Ésta será la primera práctica donde usemos las excepciones.Aquí teneis el esquema:

La clase vector representa el vector que iría desde el origen de cordenadas (el punto (0,0) ) hasta el punto (o coordenadas del mismo) que le demos. 
En el caso de la recta, podemos darle o bien dos puntos, o bien un punto y un vector.

Nota: Para los que no lo sepan, un vector es "una flecha" que posee módulo (longitud), dirección (sobre que recta está) y sentido (dirección a la que apunta). Para más información aquí teneis el link a la wiki.

Aquí os dejo el test para probar las clases ;)

public class TestRectas {
 public static void main(String[] args) {  
                // Calcular el área del triángulo definido por sus tres vértices
  Punto p1 = new Punto(0,0);    
  Punto p2 = new Punto(4,0);
  Punto p3 = new Punto(2,3);
  // Se calcula la distancia entre p1 y p2
  double base = p1.distancia(p2);
  // Se calcula la recta que pasa por p1 y p2
  Recta r1 = new Recta(p1,p2);
  // se calcula la distancia entre p3 y r1
  double altura = r1.distanciaDesde(p3);
  // El area es base*altura/2
  double area = base*altura/2;
  System.out.printf("Puntos %s %s %s\n",p1,p2,p3);
  System.out.println("Área = "+area);
  }
 }
Y aquí tenéis las soluciones a las clases ;)


Aquí la clase Recta:
public class Recta {
 private Vector director;
 private Punto origen;
 
 public Recta(Vector v, Punto p) {
  director = v;
  origen = p;
 }
 public Recta(Punto p1, Punto p2) {

  Vector v = new Vector(p1, p2);
  director = v;
  origen = p1;
 }
 public Vector vector() {return director;}
 public Punto origen() {return origen;}
 
  public boolean pasaPor(Punto p) {
  Vector v = new Vector(origen, p);
  return director.paralelos(v);
 }
 public boolean paralelaA(Recta r) {
  return director.paralelos(r.vector());
 }
 public Recta paralelaPor(Punto p) {
  Recta r = new Recta(director, p);
  return r;
 }
 public Recta perpendicularPor(Punto p) {
  Recta r;
  Vector v = director.ortogonal();
  r = new Recta(v, p);
  return r;
 }
 public Punto interseccionCon(Recta r) {
  double d, d1, d2, x0, y0;
  Punto p;
  if (this.paralelaA(r)) {
   throw new RuntimeException("Rectas paralelas");
   }
  d = director.componenteX() * r.vector().componenteY() - 
                    director.componenteY() * r.vector().componenteX();
  if (d==0) {
   throw new RuntimeException("Rectas paralelas 
                    o coincidentes");
   }
  d1 = director.componenteX() * origen.y() - 
                    director.componenteY() * origen.x();
  d2 = r.vector().componenteX() * r.origen().y() - 
                    r.vector().componenteY() * r.origen().x();
  
  x0 = (d1 * r.vector().componenteX() - 
                    director.componenteX() * d2)/d;
  y0 = -(director.componenteY() * d2 - 
                    r.vector().componenteY() * d1)/d;
  
  p = new Punto(x0, y0);
  return p;
 }
 public double distanciaDesde(Punto p) {
  Recta perp = this.perpendicularPor(p);
  Punto comun = this.interseccionCon(perp);
  return p.distancia(comun);
 }
 
 public String toString() {
  return "R("+director + ", " + origen + ")";
 }
}

Y aquí la clase Vector.
public class Vector {
 private Punto extremo;
 
 public Vector(double x0, double y0) {
  extremo = new Punto(x0, y0);
 }
 public Vector(Punto pto) {
  extremo = pto;
 }
 public Vector(Punto inicio, Punto fin) {
  double x0, y0;
  x0 = fin.x() - inicio.x();
  y0 = fin.y() - inicio.y();
  extremo = new Punto(x0, y0);
 }

 public double componenteX() {
  return extremo.x();
 }
 public double componenteY() {
  return extremo.y();
 }
 public double modulo() {
  double sum = extremo.x()*extremo.x() + extremo.y()*extremo.y();
  return Math.sqrt(sum);
 }
 public Vector ortogonal() {
  double x,y;
  Vector ort;
  x = extremo.x();
  y = extremo.y();
  ort = new Vector(-y, x);
  return ort;
 }
 public boolean paralelos(Vector v) {
  double xExt, yExt, xV, yV;
  xExt = extremo.x();
  yExt = extremo.y();
  xV = v.componenteX();
  yV = v.componenteY();
  
  return (xExt*yV == yExt*xV);
 }
 public Punto extremoDesde(Punto pto) {
  double x0, y0, x, y;
  Punto p;
  x0 = extremo.x();
  y0 = extremo.y();
  x = x0 + pto.x();
  y = y0 + pto.y();
  p = new Punto(x,y);
  return p;
 }

 public String toString() {
  return "V("+extremo.x()+","+extremo.y()+")"; 
 }
}

domingo, 9 de febrero de 2014

Creación de un Banco y Cuentas Bancarias

Buenas, aquí me encuentro otro día más codeando porque me encanta ^^. Esta practica representará un Banco y una Cuenta Bancaria; además de las operaciones que podemos realizar. Aquí teneis el esquema:
Esquema de las clases banco y cuenta en UML

La novedad es que un banco será un array de Cuentas. Un array (por si alguien aún no lo sabe) es un medio de guardar un conjunto de objetos de la misma clase, digamos que es como una "lista ordenada", aunque más adelante veremos que no es así.

Creo que no hay que explicar mucho del esquema. Las variables ppl y unca representan respectivamente la primera posición libre en el array de cuentas (están en posiciones contiguas) y el primer número de cuenta libre, de forma que una vez asignado el número a una nueva cuenta este contador se debe incrementar.
El valor inicial de unca será el de la constante NUMCTALIBRE (1001).

Cosas a tener en cuenta:

Algunas cuestiones:
  1. • Los constructores de la clase Banco se encargarán de crear el array de cuentas con un tamaño inicial, así como de dar valores iniciales a las variables auxiliares. El segundo argumento del constructor de Banco con dos argumentos indica el tamaño inicial del array de cuentas. En el constructor con un argumento el array se inicializará con un tamaño por defecto (10). 
  2. • La creación de cuentas no debe fallar porque el array esté lleno; en caso de no quedar espacio en el array se creará un array (de doble capacidad) para habilitar más espacio. 
  3. • Un banco no permite que una cuenta quede con saldo negativo. Si se intenta realizar un débito por una cantidad mayor que el saldo, solo se permitirá extraer el saldo. En ese caso, el saldo quedará a 0 y se devolverá el dinero que realmente se ha extraído de la cuenta.
  4. • Para facilitar la implementación de algunos métodos se debe implementar un método llamado posicionCuenta. Éste es un método auxiliar que devuelve la posición dentro del array de cuentas en la que se encuentra la cuenta con el número de cuenta dado como argumento. Si la cuenta no existe, el método debe lanzar una excepción RuntimeException de la siguiente manera:                               "throw new RuntimeException(“No existe la cuenta dada”);"
Aquí teneis la clase para testear que todo esté correcto:

public class TestbancoA {
 public static void main(String[] args) {
  Banco b = new Banco("TubbiesBank", 5);
  int nPo = b.abrirCuenta("Po", 500);
  int nDixy = b.abrirCuenta("Dixy", 500);
  int nTinkyWinky = b.abrirCuenta("Tinky Winky", 500);
  int nLala = b.abrirCuenta("Lala", 500);
  System.out.println(b);
  b.ingreso(nPo, 100);
  b.debito(nDixy, 100);
  b.transferencia(nTinkyWinky, nLala, 100);
  System.out.println(b);
  b.cerrarCuenta(nPo);
  b.ingreso(nDixy,200);
  System.out.println(b);
  }
 }

Bueno. Ahora subo las soluciones. 
Cuidado con leer los Spoilers ;)
.
.
.

Clase Cuenta:

public class Cuenta {
 private String titular;
 private double saldo;
 private int cuenta;
 
 public Cuenta(String tit, int num, double din) {
  titular = tit;
  saldo = din;
  cuenta = num;
 }
 public Cuenta(String tit, int num) {
  titular = tit;
  saldo = 0;
  cuenta = num;
 }

 public void ingreso(double cant) {
  saldo += cant;
 }
 public void debito(double cant) {
  saldo -= cant;
 }
 
 public String titular() {return titular;}
 public double saldo() {return saldo;}
 public int cuenta() {return cuenta;}
 
 public String toString() {
  return titular + " con numero de cuenta " + cuenta + " tiene " + saldo + "€";
 }
}

Clase Banco:

public class Banco {
 private final static int NUMCTALIBRE = 1001;
 private String nombre;
 private int ppl;
 private int unca;
 private Cuenta[] cta;
 
 public Banco(String st) {
  
  cta = new Cuenta[10];
  nombre = st;
  ppl = 0;
  unca = NUMCTALIBRE;
 }
 public Banco(String st, int pos) {
  cta = new Cuenta[pos];
  nombre = st;
  ppl = 0;
  unca = NUMCTALIBRE;
 }
 
 public int abrirCuenta(String nombre){

  if(ppl >= cta.length) {
   Cuenta[] cuentaAux = new Cuenta[cta.length * 2];
   System.arraycopy(cta, 0, cuentaAux, 0, ppl);
   cta = cuentaAux;
  }
  cta[ppl] = new Cuenta(nombre, unca);
  ppl++;
  unca++;
  
  return unca-1;
 }

 public int abrirCuenta(String nombre, double din){

  if(ppl >= cta.length) {
   Cuenta[] cuentaAux = new Cuenta[cta.length * 2];
   System.arraycopy(cta, 0, cuentaAux, 0, ppl);
   cta = cuentaAux;
  }
  cta[ppl] = new Cuenta(nombre, unca, din);
  ppl++;
  unca++;
  
  return unca-1;
 } 

 private int posicionDeCuenta(int num){
  int pos = 0;
  boolean esta = false;
  for(int i = 0; i < ppl; i++){
   if (cta[i].cuenta()==num) pos = i; esta = true;
  }
  if(!esta) throw new RuntimeException("No existe la cuenta dada");
  return pos;
 }
public void cerrarCuenta(int num) {

  int pos = posicionDeCuenta(num);
  for (int i = pos; i<cta.length-2; i++) {
   cta[i]=cta[i+1];
  }
  ppl--;
}

 public void ingreso(int numeroDeCuenta, double din) {
  int pos = posicionDeCuenta(numeroDeCuenta);
  cta[pos].ingreso(din);
 }

 public double debito(int numeroDeCuenta, double din){
  double dineroCargado;
  int pos = posicionDeCuenta(numeroDeCuenta);

  if(cta[pos].saldo()>=din) {cta[pos].debito(din);dineroCargado = din;}
  else {
   cta[pos].debito(cta[pos].saldo());
   dineroCargado = cta[pos].saldo();
  }
  return dineroCargado;
 }

 

 public double saldo(int numeroDeCuenta) {
  int pos = posicionDeCuenta(numeroDeCuenta);
  return cta[pos].saldo();
 }

 public double transferencia(int num1, int num2, double din) { //transfiere din dinero de la cuenta num1 a la cuenta num 2
  double dineroDeTransferencia = this.debito(num1, din);
  this.ingreso(num2, dineroDeTransferencia);
  
  return dineroDeTransferencia;
 }

 public String toString(){
  String res ="Banco " + nombre + ": [  ";
  for(int i = 0; i<ppl; i++) {

    res= res + "\n"+ cta[i].toString();
  }
  return res;
 }

sábado, 8 de febrero de 2014

Práctica de herencia con Punto, Circulo y Cilindro.

Pues en esta práctica implementaremos un Punto, luego un Círculo que esté formado por un entero (radio) y un punto (centro) y luego un Cilindro formado por un Círculo (base) y un entero (altura). Aquí tenéis el esquema UML

Como test de prueba usaremos el siguiente:

public class TestCilindro {
 public static void main(String[] args) {
  Punto centroBase = new Punto(3.0, 5.0);
  Circulo base = new Circulo(centroBase, 4.0);
  Cilindro miCilindro = new Cilindro(base, 10.0);
  System.out.println(miCilindro);
  miCilindro.trasladar(2.0, 2.0);
  System.out.println(miCilindro);
  System.out.println(
  new Cilindro(new Circulo(new Punto(3.0, 5.0),4.0),10.0));
  }
 }



Ahora paso a daros los resultados. Primero el del Punto:
public class Punto {

 private double x;
 private double y;
 
 public Punto() {
  x = 0;
  y = 0;
 }
 public Punto(double a, double b) {
  x = a;
  y = b;
 }
 
 public double x() {return x;}
 public double y() {return y;}
 
 public double distancia(Punto p) {
  double dist = 0;
  double distX = Math.abs(x-p.x);
  double distY = Math.abs(y-p.y);
  distX *= distX;
  distY *= distY;
  dist = Math.sqrt(distX+distY);
  
  return dist;
 }

 public void x(double a) {x = a;}
 public void y(double a) {y = a;}
 
 public void trasladar(double a, double b) {
  x += a;
  y += b;
 }
 
 public String toString() {
  return "("+x+", "+y+")";
 }
 
}

El del Círculo:
public class Circulo extends Punto{
 
 private Punto centro;
 private double radio;
 
 public Circulo() {
  centro = new Punto();
  radio = 1;
 }
 public Circulo(Punto pto, double rad) {
  centro = pto;
  radio = rad;
 }

 public Punto centro() {return centro;}
 public double radio() {return radio;}
 
 public void centro(Punto pto) {centro = pto;}
 public void radio(double rad) {radio  = rad;}
 public void trasladar(double a, double b) {
  centro.trasladar(a, b);
 }
 public String toString() {
  String center = centro.toString();
  return "El centro es "+center+" y el radio mide " + radio;
 }
 
}

Y el del Cilindro :)
public class Cilindro extends Circulo{
 private Circulo base;
 private double altura;
 
 public Cilindro() {
  base = new Circulo();
  altura = 1;
 }
 public Cilindro(Circulo bs, double alt) {
  base = bs;
  altura = alt;
 }

 public Circulo base() {return base;}
 public double altura() {return altura;}
 public void base(Circulo bs) {base = bs;}
 public void altura(double alt) {altura = alt;}
 
 public void trasladar(double a, double b) {
  base.trasladar(a, b);
 }
 public String toString() {
  String bass = "Las características de la base son: "+base.toString();
  return bass + " y la altura es de " + altura;
 }
}

Eso es todo. Espero que os quede claro todo lo que significa la herencia.

Saludos ;)

jueves, 6 de febrero de 2014

Práctica de creación de Jarras (Parte 1)

Alguna vez habéis hecho el típico rompecabezas donde con dos jarras de distintos volúmenes os piden conseguir un número determinado de litros con las únicas posibilidades de llenar, vaciar o volcar una jarra en la otra. Pues ahora vamos a realizar la primera parte, crear una clase Jarra que utilizaremos para “simular” algunas de las acciones que podemos realizar con ella.

Así será la jarra. Si tienes dudas sobre como interpretar esta imagen, mira esta entrada del blog 

Aquí tenéis el archivo con el que probareis vuestro programa:


public class TestJarras {
 public static void main(String[] arg)
 {
 Jarras jarraA = new Jarras(5);
 Jarras jarraB = new Jarras(7);
 jarraA.llena();
 jarraB.vacia();
 System.out.println("JA "+ jarraA.toString());
 System.out.println("JB "+ jarraB.toString());
 jarraB.llenaDesde(jarraA);
 jarraA.llena();
 jarraB.llenaDesde(jarraA);
 jarraB.vacia();
 jarraB.llenaDesde(jarraA);
 jarraA.llena();
 jarraB.llenaDesde(jarraA);
 System.out.println("JA "+ jarraA.toString());
 System.out.println("JB "+ jarraB.toString());
 }
}


¿Entendido? Hasta aquí el enunciado. Ahora procedo a poner el resultado (No hagáis trampas xP)


public class Jarras {

 private final int capacidad;
 private int cantidad;
 
 public Jarras(int capacidadInicial) {
  if (capacidadInicial<=0) throw new RuntimeException("Error, capacidad incorrecta.");
  capacidad = capacidadInicial;
  cantidad = 0;
 }
 
 public int capacidad() {
  return capacidad;
 }
 
 public int cantidad() {
  return cantidad;
 }
 
 public void llena() {
  cantidad = capacidad;
 }
 
 public void vacia() {
  cantidad = 0;
 }
 
 public void llenaDesde(Jarras j){
  int cantidadMinima = Math.min(capacidad- cantidad, j.cantidad);
  
  cantidad   += cantidadMinima;
  j.cantidad -= cantidadMinima;
 }


 public String toString(){
  String frase = " capacidad de " + capacidad + " y cantidad de " + cantidad + " de líquido.";
  return frase;
 }
}


Espero que no quede ninguna duda. Si tenéis alguna pregunta posteadlo (No pregunteis cosas del tipo "k signifik k as puest int ants d cantidad?" primero porque hay que aprender a escribir para poder programar y segundo porque asumo que si estáis haciendo esto sabéis ya las bases mínimas de programación  )

Salud ;)

Como leer especificaciones de aplicaciones en UML

Pues voy a explicaros brevemente como leer las especificaciones que pondré a menudo sobre las aplicaciones. Aquí un ejemplo:

+Primer cuadrado: Nombre del programa.

+Segundo cuadrado: variables a definir (en este caso un entero llamado cantidad y otro entero llamado capacidad).

+Tercer cuadrado: Lista de métodos a definir. Entre paréntesis irán las variables que reciben de entrada (primero el nombre y luego el tipo) y fuera del paréntesis y tras dos puntos, el tipo de lo que deben devolver.

El - y el + significan si lo que va después es private o public, respectivamente. Por lo general las variables serán privadas y la mayoría de los métodos públicos.

Ahora veamos algo más avanzado:


Las flechas tienen un 1 en un extremo y varias salidas en el otro. Ésto significa que (en el caso de la primera) un punto vale para hacer muchos círculos. El "- centro" indica que la clase Circulo tiene una variable privada (de ahí el -) la cual se llama centro y es de tipo Punto. 
Además la flecha nos indica que Circulo hereda de Punto, por lo cual en el encabezado hay que escribirlo de forma adecuada. Algo así:

public Circulo extends Punto {....

Saludos ;)

Actualización: Si una variable aparece escrita EN MAYÚSCULAS, significará que es una constante.


miércoles, 5 de febrero de 2014

Abro oficialmente este blog ^^



Pantalla de Bienvenido de Windows
Buenas a todos (a nadie en estos momentos, aunque espero que eso cambie :p). Soy NikNitro, Actualmente estoy en Segundo año de Ingeniería Informática en la Universidad de Málaga. A lo largo de este año he visto ejercicios prácticamente imposibles que he tenido que hacer (y otros que no he hecho) acerca de los cuales encontraba poca o nula información en Google. Lo más, otro blog pero que ha ayudado poco puesto que muchos ejercicios estaban mal -.-'

Espero que cuando yo haga algo mal me lo aviséis y podamos aprender entre todos. Me gustaría hacer más adelante una web si veo que esto medio funciona e incluso un foro de programación. Una de mis metas personales sería programar una IA, pero aún queda un largo y arduo camino para ello.

También espero que si teneis alguna duda con ejercicios (Java, Haskell y algo de C y C++) me los propongáis a ver si puedo ayudaros ;)

Solo me queda decir que ahora mismo estoy en exámenes, por lo que subiré poquito xD (Que hay que estudiar, que sale muy caro para perder el tiempo)

Saludos a todos y bienvenidos ;)