jueves, 31 de julio de 2014

Diferencia entre iteración y recursión en ensamblador (MIPS)

Buenas gente. Últimamente os tenemos demasiado abandonados. Mea culpa. Estamos los dos de viajes a todos lados (me fuí a Valencia a la DreamHack) y a la vuelta empecé a trabajar en una academia. No tengo tiempo para nada. Es totalmente estresante. Trabajo de mañana y de tarde pero bueno.., hay que comer no?

Hoy os traigo un code simple en MIPS tanto en forma iterativa como recursiva para que veais las diferencias entre ambos así como el uso de la pila. Debo decir que (en éste codigo concreto) la versión iterativa es más eficiente que la recursiva, pero no siempre es así.
El código lo único que hace es coger y multiplicar los registros $4 y $5 y guardar el resultado en $2, pero lo hace simando $5 veces $4.
Dicho ésto, aquí vuestro código iterativo:

Y aquí vuestro código recursivo:


Espero que veais la diferencia. Hay que añadir que en todos los códigos recursivos (ya que hay que usar la pila) es necesario hacer push y pop, donde push siempre es restar un múltiplo de 4 a $29 ($sp) y guardar los valores con sw en esa memoria; y pop es la operación inversa.

Espero que os haya quedado claro y que nos perdoneis por no ser puntuales :P
Un saludo y gracias ;)

viernes, 18 de julio de 2014

Ejercicios C++: Strings (I)

Aquí unos ejercicios en los que usamos strings y todo lo aprendido anteriormente sobre Registros y arrays.

Diseñar un algoritmo (y desarrollar los subalgoritmos C++ correspondientes y el main para probarlo) que permita traducir una cadena numérica al número natural que representa:
Entrada: 7805 (hay que leer el dato como un string)
Salida: 7805 (hay que mostrar el dato como un unsigned)
#include <iostream>
#include <string>


using namespace std;

void leerCadena(string & cadena){
 cout << "Introduce cadena numérica: ";
 cin >> cadena;
}

unsigned potenciaDiez(unsigned exp){
 unsigned resultado=1;
 for(unsigned i = 1; i <= exp; i++){
 resultado = resultado * 10;
 }
 return resultado;
}

void transformar (string cadena, unsigned& num){
 num = 0;
 unsigned n;
 for(unsigned i= 0 ; i < cadena.size(); i++){
  n = (int(cadena[i]))-(int('0'));
  num = num + n * potenciaDiez(cadena.size()-1-i);
 }
}

int main() {
 string cadena;
 unsigned num;
 leerCadena(cadena);
 transformar(cadena, num);
 cout << "El número con el que se corresponde es el: "<< num;
 return 0;
}


Una palabra w es un anagrama de la palabra v, si podemos obtener w cambiando el orden de las letras de v. Por ejemplo, VACA es un anagrama de CAVA.
Diseñar un algoritmo (y desarrollar los subalgoritmos C++ correspondientes y el main para probarlo) que lea un texto y determine de cuántas palabras es anagrama la primera que aparece dentro de dicho texto. Hay que tener en cuenta que:

  • El texto contiene un número indefinido de palabras.
  • El texto termina con la palabra FIN.
  • Cada palabra tiene un número indefinido pero limitado de caracteres (todos alfabético mayúsculas).
  • El carácter separador de palabras es el espacio en blanco.

#include <iostream>
#include <string>
using namespace std;


void esAnagrama(string palabra, string texto){
 unsigned contador = 0;
 bool loes = false;
 string aux = texto;
 if(palabra.size() == texto.size()){

  for(unsigned i= 0; i < palabra.size(); i++){

   unsigned j= 0;
   loes = false;


   while(j < texto.size() && loes== false){

     if(palabra[i]== aux[j]){
      loes = true;
      contador++;
      aux[j]= ' ';
     }

    j++;
   }
  }

 }

 if(contador == palabra.size()){
  cout << texto << " es anagrama de "<< palabra << endl;
 }else{
  cout << texto << " no es anagrama de "<< palabra << endl;
 }
}


void introducirTexto(){
 string palabra, texto;
 cout << "Introduce texto: "<< endl;
 getline(cin, palabra, ' ');
 //getline(cin, texto, ' ');
 cin >> texto;
 while(texto != "FIN"){
  esAnagrama(palabra, texto);
  cin >> texto;
 }
}


int main() {
 introducirTexto();
 return 0;
}


Supongamos que deseamos evaluar a un determinado número de alumnos siguiendo el criterio de que aprobará una determinada evaluación aquel que supere o iguale la nota media de la clase en dicha evaluación.
Diseñar un algoritmo (y desarrollar los subalgoritmos C++ correspondientes y el main para probarlo) que lea por teclado un número de alumnos, N_alumnos (como máximo podrá tomar el valor de MAX_ALUMNOS=20), y las notas de tres evaluaciones para cada alumno, N_EVALUACIONES=3, y como resultado emita un informe indicando para cada alumno el resultado de cada evaluación (Aprobado o Suspenso).
#include <iostream>
using namespace std;

const unsigned MAX_ALUMNOS=20;
const unsigned N_EVALUACIONES=3;

typedef double notasAlumno[N_EVALUACIONES];

struct TAlumnos{
 string nombre;
 notasAlumno notas;
};

typedef TAlumnos ArrayAlumnos[MAX_ALUMNOS];

unsigned leerNalumnos(){
 unsigned N_alumnos;
 do{
  cout << "Introduce el número de alumnos (<= "<<MAX_ALUMNOS<<"): ";
  cin >> N_alumnos;
 }while(N_alumnos > MAX_ALUMNOS);
 return N_alumnos;
}

void leerAlumnos(unsigned N_alumnos, ArrayAlumnos& alumnos){
 for(unsigned i=0; i < N_alumnos; i++){

  cout << "Introduce el nombre y 3 notas: ";
   getline(cin, alumnos[i].nombre, ' ');
   for(unsigned j = 0; j < N_EVALUACIONES; j++){
    cin >> alumnos[i].notas[j];
   }
 }
}

double notaMedia (unsigned N_alumnos, const ArrayAlumnos& alumnos, unsigned evaluacion){
 double suma = 0;
 for(unsigned i= 0; i < N_alumnos; i++){
  suma = suma + alumnos[i].notas[evaluacion-1];

 }
 return suma/N_alumnos;
}






void notasAlumnos(unsigned N_alumnos, const ArrayAlumnos& alumnos){
 cout << "Alumno \t Nota 1 \t Nota 2 \t Nota 3" << endl;
 cout << "-------------------------------------------------------";
 for(unsigned i=0; i < N_alumnos; i++){

  cout << alumnos[i].nombre << "\t";

  for(unsigned ev = 1; ev <= N_EVALUACIONES; ev++){
   double media = notaMedia(N_alumnos, alumnos, ev);
   //cout << media << endl;
   if(alumnos[i].notas[ev-1] >= media){
    cout << "Aprobado \t";
   }else{
    cout << "Suspenso \t";
   }

  }

  cout << endl;


 }
}

int main() {
 
 unsigned N_alumnos = leerNalumnos();

 ArrayAlumnos alumnos;
 leerAlumnos(N_alumnos, alumnos);
 notasAlumnos(N_alumnos, alumnos);

 return 0;
}
Diseñar un algoritmo (desarrollando los subalgoritmos C++ correspondientes y el main para probarlo) que se comporte como una calculadora que pida repetidamente un operador de conjuntos y dos operandos que sean conjuntos de letras minúsculas y que escriba el resultado de la operación. Las operaciones se expresan como caracteres, siendo válidas las siguientes:
+ Unión de conjuntos
- Diferencia de conjuntos
* Intersección de conjuntos
El proceso se repetirá hasta que se introduzca como código de operación el carácter ‘&’. Los operadores y el resultado se expresan como cadenas de caracteres. Ejemplo:
Operación = *
Operando1 = azufre
Operando2 = zafio
Resultado = afz
Operación = -
Operando1 = abril
Operando2 = arco
Resultado = bil
Operación = &
FIN
#include <iostream>
#include <string>
using namespace std;

string restaString(string op1, string op2){
 string res;
 bool esta;
 for(unsigned i=0; i < op1.size(); i++){
  esta = false;
  unsigned j = 0;
  while(esta == false && j < op2.size()){
   if(op1[i] == op2[j]){
    esta = true;
   }

   j++;
  }

  if(!esta){
   res = res + op1[i];
  }

 }
 return res;
}

string interseccion(string op1, string op2){
 string res;
  bool esta;
  for(unsigned i=0; i < op1.size(); i++){
   esta = false;
   unsigned j = 0;
   while(esta == false && j < op2.size()){
    if(op1[i] == op2[j]){
     esta = true;
    }

    j++;
   }

   if(esta){
    res = res + op1[i];
   }

  }
  return res;
}

string realizarOperacion(char operacion, string op1, string op2){
 string resultado;
 switch (operacion){
 case '+': resultado = op1 + op2;;
  break;
 case '-': resultado = restaString(op1,op2);
  break;
 case '*': resultado = interseccion(op1, op2);
  break;
 }

 return resultado;
}


void introducirDatos(){
 char operacion;
 string op1, op2;




 do{
 cout << "Operación: ";
 cin >> operacion;
 } while(operacion != '+' && operacion != '-' && operacion != '*' && operacion != '&');

 while(operacion != '&'){
 cout << "Operando 1: ";
 cin >> op1;
 cout << "Operando 2: ";
 cin >> op2;


 string resultado = realizarOperacion(operacion, op1, op2);
 cout << "Resultado: "<< resultado << endl;

 do{
  cout << "Operación: ";
  cin >> operacion;
  } while(operacion != '+' && operacion != '-' && operacion != '*' && operacion != '&');

 if(operacion == '&'){
  cout << "FIN";
 }
 }


}




int main() {
 cout << "Operaciones con strings" << endl; 
 introducirDatos();
 return 0;
}

viernes, 11 de julio de 2014

Mi primera App con Android. BPCalculator.

Buenas gente, ¿qué tal? Acabo de depurar la aplicación que hice antes de ayer y ya os puedo mostrar de qué va. Os cuento... Resulta que por ser de la UMA, tengo una tarjeta para la BP mediante la cual me descuentan 5 céntimos por litro, pero me los dan en mano. Pues como hay veces que llevo 4,60 y pocos euros y cosas así, me decidí a hacer una calculadora con la que poder ver lo que me iba a costar y cuánto me iban a echar. Ésta es la version 1.0. Quiero poder hacer que busque directamente el precio, pero eso será más adelante cuando aprendamos a conectar la aplicación con la web. El proyecto en git lo tenéis por aquí.

Antes de nada os aconsejaría que en vez de usar las máquinas virtuales de Android uséis vuestro teléfono, que irá mil veces mejor (ayer me dijeron que en el eclipse de Linux, las máquinas van perfectas; pero aún no lo he podido probar). Si no sabéis cómo conectar el móvil, preguntad ;)

Aquí tenéis una imagen del aspecto de la aplicación:


Ésto lo podéis hacer editando el activity.xml (es uno de los dos archivos que se os abren). De todos modos, aquí os dejo el mío:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="wrap_content"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="com.NikNitro.bpcalculator.Calculator" >

    <GridLayout
        android:id="@+id/gridLayout1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentRight="true"
        android:layout_alignParentTop="true"
        android:layout_marginTop="25dp"
        android:alignmentMode="alignBounds"
        android:columnCount="2"
        android:useDefaultMargins="true" >

        <TextView
            android:id="@+id/textView1"
            android:layout_width="102dp"
            android:layout_column="0"
            android:layout_gravity="left|top"
            android:layout_row="0"
            android:text="Precio"
            android:textAppearance="?android:attr/textAppearanceLarge" />

        <TextView
            android:id="@+id/textView2"
            android:layout_column="1"
            android:layout_gravity="center"
            android:layout_row="0"
            android:text="Cantidad(€)"
            android:textAppearance="?android:attr/textAppearanceLarge" />

        <EditText
            android:id="@+id/Cantidad"
            android:layout_width="106dp"
            android:layout_column="0"
            android:layout_gravity="left|center_vertical"
            android:layout_row="1"
            android:ems="10"
            android:inputType="numberDecimal" />

        <EditText
            android:id="@+id/Precio"
            android:layout_width="121dp"
            android:layout_column="1"
            android:layout_gravity="center"
            android:layout_row="1"
            android:ems="10"
            android:inputType="numberDecimal" />

    </GridLayout>

    <Button
        android:id="@+id/button"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_alignLeft="@+id/gridLayout1"
        android:layout_below="@+id/gridLayout1"
        android:layout_marginTop="26dp"
        android:text="Aceptar" />

    <GridLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_alignLeft="@+id/button"
        android:layout_below="@+id/button"
        android:layout_marginTop="75dp"
        android:columnCount="2"
        android:useDefaultMargins="true" >

        <TextView
            android:id="@+id/textView3"
            android:layout_width="126dp"
            android:layout_column="0"
            android:layout_gravity="right|top"
            android:layout_row="0"
            android:text="Vas a Pagar"
            android:textAppearance="?android:attr/textAppearanceLarge" />

        <TextView
            android:id="@+id/textView4"
            android:layout_width="124dp"
            android:layout_gravity="left"
            android:text="Vas a Tener"
            android:textAppearance="?android:attr/textAppearanceLarge" />

        <TextView
            android:id="@+id/Pago"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="left"
            android:textAppearance="?android:attr/textAppearanceLarge" />

        <TextView
            android:id="@+id/Compra"
            android:layout_gravity="left"
            android:textAppearance="?android:attr/textAppearanceLarge" />

    </GridLayout>

</RelativeLayout>
Como veis no es nada difícil de comprender (no digo nada de hacerlo, solo de entenderlo :P). Bueno, aquí os dejo ahora el código de la aplicación (el cual es más sencillo aún).

package com.NikNitro.bpcalculator;

import android.app.Activity;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;

public class Calculator extends Activity implements OnClickListener{
 //Botón
 private Button boton;
 //Texto Editable por el usuario
 private EditText litros, precio;
 //Texto SÓLO legible por el usuario
 private TextView compra, preciofinal;
 // Variables enteras
 private double dlitros, dprecio, dcompra, dpreciofinal;
 
 @Override
 protected void onCreate(Bundle savedInstanceState) {
  //Éste método se ejecuta el primero al iniciar la aplicación.
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_calculator);
  
  initialize();
 }

 private void initialize() {
  // TODO Auto-generated method stub
  boton = (Button)findViewById(R.id.button);
  //Añado al botón el controlador.
  boton.setOnClickListener(this);
  //Así es como se inicializan los objetos para que queden
  // linkeados con el activity.
  litros = (EditText)findViewById(R.id.Cantidad);
  precio = (EditText)findViewById(R.id.Precio);
  compra = (TextView)findViewById(R.id.Compra);
  preciofinal = (TextView)findViewById(R.id.Pago);
  
  
 }

 @Override
 public boolean onCreateOptionsMenu(Menu menu) {
  // Inflate the menu; this adds items to the action bar if it is present.
  getMenuInflater().inflate(R.menu.calculator, menu);
  return true;
 }

 @Override
 public boolean onOptionsItemSelected(MenuItem item) {
  // Handle action bar item clicks here. The action bar will
  // automatically handle clicks on the Home/Up button, so long
  // as you specify a parent activity in AndroidManifest.xml.
  int id = item.getItemId();
  if (id == R.id.action_settings) {
   return true;
  }
  return super.onOptionsItemSelected(item);
 }

 @Override
 public void onClick(View v) {
  // Al hacer click en algún botón, se llama aquí.
  //Si tuvieramos más de un botón tendríamos que ver a cual se refiere. Para ello usamos la v que nos pasan.
  calcular();
  mostrarToast("Cálculo completo");
 }

 private void mostrarToast(String string) {
  //Muestra un mensaje
  Toast texto1 = Toast.makeText(getBaseContext(), string, Toast.LENGTH_SHORT);
  texto1.show();
  
 }

 private void calcular() {
  try {
   dlitros = Double.parseDouble(litros.getText().toString());
   dprecio = Double.parseDouble(precio.getText().toString());
   double prec = Math.rint(dprecio*100/dlitros)/100;
   compra.setText(prec+"");
   double desc = prec*0.05;
   preciofinal.setText((dprecio-desc)+"");
  } catch (Exception e) {
   mostrarToast("Rellene todos los campos correctamente, por favor");
  }
  
 }
 
 
}

Jeje, bueno, espero que no os queden dudas y (si os quedan) las preguntéis, pues estaré encantado de responderos. Un saludo y hasta la próxima ;)

miércoles, 9 de julio de 2014

Arduino: Control de un motor con velocidad variable.

Qué pasa gente? Aquí os traigo una nueva curiosidad si estáis empezando en Arduino. Si queréis hacer algo con motores, lo primero que notaréis es que el motor corre a una velocidad exagerada. Hoy aprenderemos a controlarla con un sencillo programita. Para ello utilizaremos los pines PWD (los que tienen un signo ~ junto al número) pues éstos nos permiten variar la velocidad. Antes de nada os dejo un video del proyecto, para que veais cómo va:

El esquema que usaremos será el siguiente:

Conexiones.
Por si no se ve bien, el amarillo va a la salida de 5V, el negro al GND y el verde a la salida ~3.
Ahora os dejo el código:

int motor=3;     //Declara Pin del motor

void setup() {
  Serial.begin(9600); 
  Serial.println("Eliga de 0 a 9 la velocidad de giro del motor");
}


void loop() {

  // Si hay algun valor en la Consola Serial
  if (Serial.available()){

    //Variable donde se guarda el caracter enviado desde teclado
    char a = Serial.read();

    // Si el caracter ingresado esta entre 0 y 9
    if (a>='0' && a<='9'){ 

      //Variable para escalar el valor ingresado a rango de PWM
      int velocidad = map(a,'0','9',0,255);
      //Escritura de PWM al motor
      analogWrite(motor,velocidad);
      //Mensaje para el usuario
      Serial.print("El motor esta girando a la velocidad ");
      Serial.println(a);

    } else { 

      Serial.print("Velocidad invalida");
      Serial.println(a);

    }
  }
}

Como veis no es nada demasiado complicado. Una vez hecho tenéis que abrir la consola desde el programa de Arduino (Herramientas->Monitor Serial ó Control+Mayus+M).

Eso es todo. Espero que os hayais enterado bien y hasta la próxima.
Saludos;)

lunes, 7 de julio de 2014

Empezando con Android. Instalación.

Buenas gente. Llevo todo el año con un par de proyectillos en mente así que éste finde me decidí a empezar a darle caña a Android... Hasta hoy no he podido programar, por lo que espero dejaros medianamente claro cómo hay que instalarlo.

Comencé con Android Studio, pero me daba bastantes fallos (Muchos de ellos al buscar en Google solo encontrabas solución para otras versiones). Tiene mucho potencial pero aún está en BETA (versión 0.8.1).

Al fin (tras cargarme, Eclipse, Java...) empecé de 0. Instalé JRE, JDK, Instalé Eclipse (me decía que no podía abrir, pero busqué y abrí el archivo javaw.exe y justo después me dejaba abrir Eclipse. No me ha vuelto a dar fallos).

Ahora que tenemos Eclipse, nos descargamos e instalamos el SDK de Android de aquí (http://developer.android.com/sdk/index.html) dándole a abajo donde pone "GET THE SDK FOR AN EXISTING IDE". Instalamos donde nos dé la gana (en mi caso C:/Android) y abrimos Eclipse. Ahora nos vamos a Help->Install New Software y le damos a Add. Como nombre ponemos lo que queramos (en mi caso ADT) y en la URL ponemos la siguiente: https://dl-ssl.google.com/android/eclipse/ 
Típico Next, Next... Finish. Se instala todo. Reiniciamos Eclipse y VOI LÁ. Objetivo completado.
Para crear proyectos en Android nos vamos a New->Other-> Android -> Android Application Project.

A partir de ahora iré subiendo mis proyectos. Ahora mismo estoy con una especie de "calculadora" para el descuento de la gasolina; es muy simple, pero en cuanto esté acabada la subiré.

Saludos a todos y hasta otra;)

viernes, 4 de julio de 2014

Liga de Pádel. Modelo de Entidad Relación.

Buenas gente. Como ahora empezaré a dar (entre otras) clases de Bases de Datos, voy a ir subiendo ejercicios resueltos. Os dejo aquí el enunciado del mismo:


Se desea diseñar una base de datos para almacenar la información relacionada con la edición de ligas de pádel. Como es bien sabido, el pádel es un deporte similar al tenis el que siempre participan 4 jugadores en cada partido. Cada liga tiene su código y su nombre que son únicos, un organizador y un premio final. Cada liga se celebra como sumo una vez cada año, en lo que se denomina ediciones, cada una con sus propias normas. 
Cada partido de pádel se celebra en un club (aunque es posible que al principio el lugar sea desconocido y no se rellene este dato hasta que los jugadores celebren el encuentro). Por cada partido hay que rellenar la fecha de celebración, la pista donde se juega y el resultado final. La liga tiene convenios con una serie de clubs de los que hay que almacenar un código, un nombre (obligatorio) una dirección y un teléfono de contacto. En un club sólo se puede jugar un partido en una pista en una determinada fecha (en nuestro sistema gestor de bases de datos el tipo fecha contiene también la hora). 
De cada jugador hay que almacenar un código, nombre y teléfono móvil (obligatorios). El móvil debe ser único por jugador. Además, se ha habilitado una página web en la que los jugadores pueden inscribirse como usuarios. Un usuario es un jugador del que hay que almacenar el alias, la password de entrada y la dirección de correo electrónico. Es obligatorio que el organizador de cada liga esté inscrito como usuario. Cada usuario sólo puede organizar una liga. 
Hay que conocer qué jugadores están inscritos en cada una de las ediciones. Éstas, a su vez, se pueden descomponer en varias fases, cada una con su propia fecha de inicio, nombre (fase regular, playoff, finales, etc.) y número de partidos de los que consta, número de partidos que se han jugado realmente y cuáles son. Además, una vez terminada cada edición hay que saber la pareja de jugadores que ha resultado campeona de esa edición. 
Nuestro cliente nos comenta que últimamente se está poniendo de moda el pádel individual, el cual lo juegan 2 jugadores en lugar de 4 y que se están planteando organizar ligas de este estilo. Para ello, bastaría con almacenar el puesto que cada jugador ocupa en cada partido de modo que variará entre 1 y 4 para los partidos de ligas normales y entre 1 y 2 para las ligas de pádel individual.

Bueno, vamos a ello. En una primera lectura de la especificación podemos identificar fácilmente las
entidades (objetos de interés). Éstos serán seres distinguibles del mundo real; pudiendo ser reales o abstractos y vienen representados por un nombre o sustantivo.
Normalmente las entidades suelen ser algo sobre lo que la organización necesita información.
Identificamos las Entidades como:
Liga, Edición, Club, Partido, Jugador, Usuario y Fase. Ahora vamos a crearlas con sus atributos.

Hay que tener en cuenta que un atributo nunca puede tener 'propiedades', pues en ese caso se trataría de otra entidad más. Además por la propiedad de redundancia, no debemos tener atributos que podamos calcular (por ejemplo, si tenemos una fecha de nacimiento, no pongamos la edad puesto que podría darse el caso de que una de las dos estuviera mal y no cuadraran las cuentas).

Ahora debemos fijarnos en qué atributos pueden ser únicos y elegir una clave para cada Entidad. Una clave es un atributo único que representa inequívocamente a su entidad (Por ejemplo, en la entidad Español, la clave debería ser DNI, pues es único).

Marcaremos con un * los valores obligatorios, con una U los únicos y con un # las claves. Una entidad puede tener varias claves (#1, #2...) o una clave compuesta (marcaremos los atributos con el mismo #) como en el caso de la Entidad Partido.

Ahora nos queda definir las relaciones. En ése momento nos daremos cuenta de que todos los Usuarios son Jugadores, por lo que Usuario es una Subentidad de Jugador. Además nos damos cuenta de que Fase es una entidad débil de Edición y ésta, a su vez, de Liga. Una entidad débil es aquella la cual sus atributos sólo la identifican de forma parcial (para saber de que fase estamos hablando necesitamos saber a qué edición pertenece y a qué liga).

Al fin, nuestro esquema quedaría de la siguiente manera:

Espero que si le echáis sus 5 minutos lo veáis todo claro, en otro caso me hallaré encantado de resolver vuestras dudas. Un saludo a todos y hasta la próxima ;)

miércoles, 2 de julio de 2014

Servidor de Echo en C++ para Linux.

Buenas gente. Ésta es la última práctica que se pidió para redes. Montar un servidor de Echo en C++ para Ubuntu. Me ha sido super trabajoso conseguirlo porque a mi ordenador le ha costado vida y media tirar de la máquina virtual (para compilar) y del Visual Studio para programar. Bueno, el servidor debe seguir el siguiente esquema:

Como veis parece ser seguir una estructura, pero el averiguar de donde sacar los datos nos costó (tanto a Cristina como a mi) demasiado tiempo. Seguramente haya códigos mejores que el mio, pues no soy perfecto. Pero espero que os sirva de ayuda. Aquí los teneis:

Código del Cliente:
#include <iostream>
#include <sys/socket.h>    //socket
#include<stdio.h> //printf
#include<netinet/in.h> 
#include<arpa/inet.h>  //inet_addr
#include<netdb.h>
#include<string.h>    //strlen
#include <stdlib.h>  // para atoi


using namespace std;





int main(int argc, char *argv[]) {
 int sck, rtn;
// const int PUERTO = 5050;
 const int PUERTO = atoi(argv[argc-1]);
 cout << argv[1] << ":" << PUERTO << "\n\n";

 struct sockaddr_in server;
 char bufferIn[2000], bufferOut[2000], bufferAux[2000];
 //creamos socket
 sck = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
 if (sck == -1) {
  cout << "No se puede crear el socket";
 }
 puts("Socket creado");

 server.sin_family = PF_INET;
 server.sin_port = htons(PUERTO);
 server.sin_addr.s_addr = inet_addr(argv[1]);
// server.sin_addr.s_addr = inet_addr("127.0.0.1");

 //Conectando al servidor
 if (connect(sck, (struct sockaddr*) (&server), sizeof(server)) < 0) {
  perror("Conexion fallida. error");
  return 1;
 }
 puts("Conectado\n");
 
 //Obtenemos la string a enviar, la separamos en caracteres y la enviamos.
 bool noAcaba = true;
 while (noAcaba) {
  cout << "Conectado al servidor " << inet_ntoa(server.sin_addr) << ":" << PUERTO << ".\n";
  cout << "Que desea enviar?\n";
  scanf("%s", bufferOut);
  if (!strcmp(bufferOut, "FIN")) {
   noAcaba = false; 
   if (write(sck, bufferOut, strlen(bufferOut)) < 0) {
    puts("envio fallido");
    return 1;
   }
  } else {
   strcat(bufferOut, "\n");

   if (write(sck, bufferOut, strlen(bufferOut)) < 0) {
    puts("envio fallido");
    return 1;
   }
   rtn = read(sck, bufferIn, 2000);
   
   cout << "\nDevuelto " ; 
   for (int i = 0; i < strlen(bufferOut); i++) {
    cout << bufferIn[i];
   }
   cout << "\n";
   strcpy(bufferIn, "\0");
   strcpy(bufferOut, "\0");
  }
  

 }
 cout << "Desconectado Correctamente.\n";
 

 return 0;
}

Código del Servidor:
// EchoServer.cpp: define el punto de entrada de la aplicación de consola.
//

#include <iostream>
#include <sys/socket.h> 
#include <unistd.h>  //write
#include <stdio.h>  //para perror
#include <stdlib.h>  // para atoi

//Otros includes:
#include<netinet/in.h> 
#include<arpa/inet.h> //inet_addr
#include<netdb.h>
#include<string.h>  //strlen

using namespace std;




int main(int argc, char *argv[]) {

 int listen_socket, cliente, rtn;
 struct sockaddr_in server, clientinfo;
// const int PUERTO = 5050;
 const int PUERTO = atoi(argv[1]);

 //SOCKET
 listen_socket = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); 
 if (listen_socket == -1) {
  perror("No se puede crear el socket");
  return 1;
 }
 cout << "Socket creado\n";

 //preparar la estructura sockaddr_in
 server.sin_family = AF_INET;
 server.sin_addr.s_addr = INADDR_ANY;
 server.sin_port = htons(PUERTO);
 
 //BIND
 rtn = bind(listen_socket, (struct sockaddr*)&server, sizeof(server));
 if (rtn < 0) {
  perror("Error en el bind");
  return 1;
 }
 puts("Bind hecho");
 
 //LISTEN
 rtn = listen(listen_socket, 1); //1 es el maximo de conexiones a la vez
 cout << "Esperando conexiones entrantes en el puerto "<< PUERTO << "\n";
 /*if (rtn < 0) {
  perror("Error en el listen");
  return 1;
 }*/

 while (true) {

 sockaddr client;
 socklen_t c = sizeof(client);
 //ACCEPT
 cliente = accept(listen_socket, &client, &c);
 if (cliente < 0) {
  perror("Error en el accept");
  return 1;
 }
 cout << "Conexion aceptada en el puerto " << PUERTO << "\n";
 fflush(stdout);

 //READ
 char buffer[2000], bufferAux[2000];
//  cout << "Al menos intenta leer \n";
 bool noAcaba = true;
 while ((rtn = read(cliente, buffer, 2000)) > 0 && noAcaba) {
   cout << "Conectado en el puerto " << PUERTO << ". Esperando accion.\n";
//   cout << "RECIBIDO: " << buffer << "\n";
   if (!strcmp(buffer, "FIN")) {
    noAcaba = false;
   }
   else {
    fflush(stdout);
 //   cout << "Al menos lee \n";
 //   strcat(buffer, "  Servidor");
    for (int i = 0; i < rtn; i++) {
     buffer[i] = toupper(buffer[i]);
    }
    fflush(stdout);
    if (write(cliente, buffer, strlen(buffer)) < 0) {
     perror("Envio fallido");
     return 1;
    }
//    cout << "ENVIADO: " << buffer;
    fflush(stdout);
    //Reiniciarlo
    strcpy(buffer, "\0");
   }

   
  }
  if (rtn == 0) {
   cout << "Recibido FIN. \nCerrando la conexión con el cliente\n";
   cout<<"Cliente desconectado. Esperando conexion en el puerto "<< PUERTO << "\n";
   fflush(stdout);
  }
  else if (rtn == -1)
  {
   perror("Error en Read");
  }
  cout << "Esperando otro cliente.\n \n";

 }
 
 
 return 0;
}

Como podéis ver son algo extensos y programados de forma estructurada. De todos modos aquí teneis el proyecto en Git donde podréis ver los cambios así como otras dos posibilidades de crearlo llamadas "client2" y "server2".

Espero que os haya gustado. El contenido de éste post tiene relación con el "intento de chat" que aún está por acabar, pues ése empezó siendo un servidor de echo.

Saludos y hasta la próxima;)