lunes, 22 de noviembre de 2010

Apuntadores

Los apuntadores  o punteros son unas de las características mas poderosas del lenguaje de programación ANSI C y a su vez podemos decir que una de las herramientas mas difíciles de dominar en el lenguaje.

Debemos mencionar que para tener un buen nivel en la programación o por lo menos pasar a un siguiente nivel es necesario tener un buen conocimiento sobre punteros, ya que con ellos podemos realizar infinidad de cosas como por ejemplo en los programas simular llamadas por referencias, crear y manipular estructuras de datos dinámicas (las que cambian su tamaño durante su ejecución), tales como listas enlazadas, colas, pilas y arboles.

Los apuntadores son variables que contienen direcciones de memoria como sus valores.Por lo regular una variable contiene directamente un valor especifico. Un apuntador, por otra parte, contiene la dirección de una variable que contienen un valor especifico. Un apuntador por otra parte, contiene la dirección de una variable que contiene un valor especifico. En este sentido, un nombre de variable se refiere directamente a un valor y un apuntador se refiere indirectamente a un valor.El referirse a un valor a través de un apuntador se le conoce como indirección.
Los apuntadores como cualquier otra variable, deben ser declarados antes de ser utilizados. La declaración

int *countPtr, count;

declara la variable countPtr siendo del tipo int, o bien “countPtr” apunta a un objeto del tipo entero”. También, la variable count se declara como un entero, no un apuntador a un entero. El símbolo * solo se aplica a countPtr en la declaración. Cuando el * se utiliza de esta forma en una declaración, indica que la variable que se esta declarando es apuntador. Los apuntadores pueden ser declarados para apuntar a cualquier tipo de datos.
La siguiente imagen muestra el ejemplo de una referenciacion directa o indirecta de una variable.
image 
Los apuntadores deben ser inicializados cuando son declarados o en un enunciado de asignación. Un apuntador puede ser inicializado a 0, Null o a una dirección. Un apuntador con el valor NULL no apunta a nada. Null es una constante simbólica, definida en el archivo cabecera de stdio.h Cabe mencionar que al inicializar un apuntador  con 0, es equivalente a inicializar un apuntador a NULL, pero es importante mencionar que para este caso es preferible utilizar Null. El valor 0 es el único valor entero que puede ser directamente asignado a una variable de apuntador.

Operadores de un puntero:
El & conocido como operador de dirección, es un operador unario que regresa la dirección de su operador. Por ejemplo, suponiendo las declaraciones
int y = 5;
int*yPtr
El enunciado yPtr = &y
asigna la dirección de la variable “y” a la variable de apuntador yPtr. La variable yPtr se dice entonces que “apunta a ”. La siguiente figura muestra una representación:donde podemos ver como un apuntador  “apunta ” a una variable entera.

image


Apuntadores a funciones:
Los apuntadores a funciones son quizá uno de los usos más confusos de los apuntadores en C. Los apuntadores a funciones no son tan comunes como otros usos que tienen los apuntadores. Sin embargo, un uso común es cuando se pasan apuntadores a funciones como parámetros en la llamada a una función.
El siguiente programa, muestra como calcular el cubo de cualquier numero mediante funciones, en la primera utiliza llamadas a funciones por valores, y la segunda utiliza llamadas a funciones por parámetros, estos últimos utilizan los apuntadores.
image

image

Los programas anteriores presentan dos formas de elevar un numero al cubo mediante funciones, en este caso las funciones cubeByValue y cubeByReference.
El primer programa pasa la variable number a la función cubeeByvalue, utilizando una llamada por valor. La función cubeByReference toma eleva al cubo su argumento y pasa su nuevo valor de regreso a main, utilizando el enunciado return. El nuevo valor se asigna a la variable number que se encuentra en main.

El segundo programa que hace exactamente lo mismo, pero en este caso este utiliza parameros por referencia, trabaja así: pasa la variable number utilizando una llamada por referencia(apuntador a la variable number) a la funcion cubeByReference. La funcion cubeByReference toma un apuntador a int conocido como nPtr como argumento. La funcion dereferencia el apuntador y eleva al cubo el valor hacia el cual apunta nPtr. Esto cambia el valor de number dentro de main.



Referencias:
http://www.fismat.umich.mx/mn1/manual/node11.html
Como programar en c/c++-Deitel-Deitel-Editorial PEARSON.

El esquema de programación Multiparadigma.

Bueno y que decir, se termino el semestre!, en todo este tiempo conocimos muchas cosas nuevas, por mencionar algunas que es la programación, y en si que es un paradigma de programación, entre muchas otras cosas.

En mi primer articulo en el blog, si bien recuerdo el paradigma de programación  lo definíamos como un conjunto de técnicas de programación para poder escribir de la mejor manera posible nuestros programas.

En todo el curso conocimos que dichas técnicas de programación, nos facilitan realmente el problema a tratar de resolver.
Por ejemplo conocimos lo que eran los paradigmas imperativos, funcionales, lógicos y orientados a objetos.
Y la verdad es que cada uno de ellos es bueno para el determinado problema que se nos presente.

Ahora un punto interesante.¿Podemos utilizar las cualidades de todos esos paradigmas, para resolver un problema en especifico? Por supuesto que si!, la programación sigue creciendo a pasos agigantados y siempre será necesario que nosotros también estemos al día y no quedarnos como vagamente se diría “quedarnos obsoletos”.

Volviendo al tema, claro que si!. Nosotros podemos aplicar técnicas de  varios paradigmas de programación para resolver determinado problema, e incluso hoy en día existen lenguajes dedicados para ese propósito, como lo es el caso de Go y OZ por mencionar algunos.
Cabe mencionar que muchos lenguajes modernos, también incorporan elementos de varios paradigmas de programación. Es mas no vallamos muy lejos, si recordamos casi al principio del curso conocimos lo que eran los lenguajes Script o lenguajes interpretados. Estos lenguajes poseen características de varios paradigmas.

El principal propósito de este paradigma , es permitir  a los programadores utilizar las mejores herramientas de trabajo,  si lo vemos desde este punto de vista, ningún paradigma de programación nos  va resolver los problemas de la forma mas fácil y eficiente posible. Hay que saber utilizar todas las herramientas disponibles y saber en donde aplicarlas.
En cuestiones de herramientas disponibles, tenemos a nuestro alcance el lenguaje de programación Oz que como ya mencione anteriormente, este incorpora características de varios paradigmas.

El lenguaje Oz fue diseñado para hacer un avance moderno para las aplicaciones concurrentes , inteligentes , de redes , tiempo real , paralelismo , interactivas y reactivas de la misma forma para resolver aplicaciones complejas robusta y rápidamente. Sin mencionar que oz contiene una forma simple y bien hecha de la mayoría de los conceptos de los principales paradigmas de programación, mencionados anteriormente.
Como Oz trabaja con muchos de los conceptos de los paradigmas de programación, es importante señalar que en el lenguaje existe una jerarquía entre sus tipos de datos. El siguiente esquema lo muestra de una manera mas clara:

oz

Algunos de ellos ya los conocemos, porque los hemos utilizado antes, otros tantos son del lenguaje mismo..
Oz al ser un lenguaje tan completo,  también posee entre sus características esquemas de la programación concurrente, es decir a un conjunto de procesos o hilos de ejecución creados por un único programa, por ejemplo la característica principal de la programación concurrente es la simultaneidad en la ejecución de múltiples tareas interactivas.
Podemos mencionar que en oz la concurrencia es muy eficiente y económica. Es decir puede generar miles de procesos en muy poco tiempo de ejecución a comparación de otros lenguajes de programación.

Bueno estas son las principales cualidades que podemos apreciar en un lenguaje de este tipo de paradigma.
La verdad me hubiera gustado poner algún ejemplo en donde se viera aplicado el lenguaje, pero me resulto muy difícil ya fue poca la información que me encontré, pero como mencione anteriormente, este lenguaje lo podemos ver aplicado a la programación de sistemas distribuidos y paralelos.

Compañeros, espero les sea de agrado esta entrada, otra cosa importante que me gustaría expresar es que no porque ya se halla terminado el semestre y esta unidad de aprendizaje halla finalizado, dejemos en el olvido todos nuestros blogs personales. Si tienen la posibilidad de seguir publicando háganlo ;) si al estar practicando descubren algo nuevo o hagan algo interesante, compártanlo con todos nosotros ;) estoy seguro que una gran parte de nosotros mostrara un intereses a todo lo nuevo que hagan.
Muchos saludos =)

Practicando en C++.(extra)

Bueno me pareció interesante incluir algunos de los primeros programas que escribir en C++, si a alguien les puede servir de algo adelante ;)

Aclaro lo siguiente,  como fueron de los primeros programas que escribí en C++, este programa no sigue el esquema de la programación orientada a objetos, ya que utiliza C++ como si fuese C normal, salvo por algunas librerías, si les puede servir de referencia para comenzara a escribir en C++, adelante ;)

El programa lo que hace es convertir kilómetros a millas.

El código fuente es el siguiente:

Pantallazo

y la ejecución del mismo es la siguiente:

Pantallazo-1

Ojala y les sea útil ;)

domingo, 21 de noviembre de 2010

Paradigma de programacion Imperativo.

Me tarde un poco en subir este reporte pero aquí esta ;) bueno si recordamos las características  que resaltan de este paradigma, son los programas que se conforman principalmente de oraciones o conjunto de instrucciones que le indican a la computadora que instrucciones realizar. Los elementos más importantes de este paradigma son las variables, los tipos de dato, expresiones y estructuras de control. Los lenguajes que siguen este modelo de programación son: C, FORTRAN, ALGOL, Pascal y Cobol.

Para este reporte había que elegir algunos lenguajes de programación de dicho paradigma, en mi caso yo elegí los lenguajes C, PASCAL y FORTRAN.

Lenguaje de programación ANSI C.

El primer programa es en lenguaje C, es la solución de una ecuación de segundo grado.El código fuente es el siguiente:

codigo fuente1

A diferencia de otras implementaciones con las que me he topado, quise realizar este programa mediante funciones, en donde se declara varias funciones para el calculo de las raíces y el calculo del discriminante, posteriormente en el programa principal se llama a la función correspondiente según sea el caso.

Dándole valores específicos para probar las tres posibles soluciones, podemos ver la ejecución del programa:

0001

0002

00003

Lenguaje de programación PASCAL.

El siguiente programa es mas sencillo que el anterior, pero utiliza características resaltantes del paradigma, en este caso se enfoca mas a sentencias de selección.

El programa que realice en PASCAL se enfoca un poco al área del electromagnetismo, se trata de un programa que resuelve la Ley de OHM. Utiliza un Switch para elegir el tipo de calculo que queramos realizar, en este caso para calcular voltaje, corriente y resistencia.

pascal01

La ejecución del programa, probando las tres diferentes opciones:

pascal ejecucion ohm

Lenguaje de programación FORTRAN.

En este lenguaje quise hacer uso de un bucle repetitivo, algo parecido a lo que en ANSI C se conoce como bucle for. El programa se encarga de pedir 15 salarios de un trabajador, posteriormente este mostrara la suma de esos elementos, claro solo utilizando el bucle repetitivo.

En si el programa es muy sencillo, pero espero que sirva para quienes se adentren al estudio del lenguaje y comprendan como se implementa este bucle repetitivo en FORTRAN.

El código fuente es el siguiente:

FORTRAN1

La ejecución del programa es la siguiente:

FORTRAN2

Espero que esta entrada sea de su agradado =)

 

Referencias.

Manual de C.

Breve manual de FORTRAN

ttp://www.learn-programming.za.net/

5 grandes preguntas a 5 grandes programadores.

Hace un rato, buscando información para terminar unos artículos pendientes, caí en un interesante blog, en donde hacen una traducción de un articulo en ingles, en donde entrevistan a 5 programadores reconocidos.

Entrevistan a programadores como Linus Torvalds (autor de núcleo Linux), Guido Van Rossum (creador de Phytom), Bjarne Stroustrup (Creador de C++) James Gosling(creador de Java) y Peter Norvig (Director de desarrollo de Google.)

El articulo original en ingles se encuentra en la pagina:

http://www.stifflog.com/2006/10/16/stiff-asks-great-programmers-answer

La traducción en español se encuentra en el siguiente blog:

http://www.logadmin.net/2008/09/5-gran-preguntas-5-de-los-grandes.html

Es un blog el cual lleva por nombre "El blog de un administrador de Sistemas", tiene artículos muy interesantes acerca de muchas herramientas de software, artículos sobre como podría ser el campo laboral en la programación entre muchas otras cosas interesantes.

Retomando a la entrevista, están interesantes las respuestas que ellos nos dan, nos explican como llegaron al lugar en el que se encuentran, si realmente la Universidad les sirvió de algo, si las matemáticas y las físicas también tienen importancia en la programación entre otras cosas.

Les sugiero ampliamente que si lo pueden leer lo hagan ;)

Referencias:

http://www.stifflog.com/2006/10/16/stiff-asks-great-programmers-answer

"El blog de un administrador de Sistemas",

http://www.logadmin.net/2008/09/5-gran-preguntas-5-de-los-grandes.html

Problemas de compilación con Gfortran. (extra)

Hace un rato que estaba trabajando en el lenguaje de programación Fortran, me surgió un problema interesante el cual creo que vale la pena analizarlo, por si alguien mas le sucede lo mismo.

Bueno cuando según yo termine de escribir el código de mi programa, al querer compilarlo en la terminal utilizando el comando:

guillermo@guillermo-desktop:~$  gfortran  hola.f

Me aparecieron una lista de errores en el código, y siendo que el programa era bien sencillo (un típico “hola mundo” en Fortran). El error fue fue el siguiente:

Pantallazo

El código del programa contiene lo siguiente:

PROGRAM HOLA
   PRINT *, '¡Hola, mundo!'
END

En si al analizar el código, el programa anterior no recae en errores de sintaxis ni nada por el estilo. Esto también ocurría con cualquier otro código.

Al investigar acerca de este error, en los foros dedicados a Ubuntu, encontré que al parecer esto error se debe a las distintas versiones que existen de Fortran.

En este caso Fortran entre su muchas versiones, podemos encontrar las extensiones .f, .for, .f90, .f95. En Windows comúnmente es utilizada la extensión .for y en sistemas Unix es la extensión .f.

Volviendo al tema, se comentaba en los foros de Ubuntu, que un posible problema se debe a que el código aunque este bien escrito, muchas veces estemos utilizando una versión 90 o 95 de Fortran, lo que debemos hacer es  cambiar la extensión del archivo a .f90. Esto según ya que Fortran compila el código del archivo como código de fortran 77, que funciona un poco diferente a Fortran 90.

En dado caso que tampoco les llegue a funcionar lo anterior (como fue mi caso) hay que recurrir a las opciones de compilación de gfortran.

En este caso para compilar ese archivo debemos utilizar la siguiente instrucción :

–ffree-form

Añadiéndola a la instrucción para compilar nuestro código quedaría así:

guillermo@guillermo-desktop:~$  gfortran  –ffree-form  hola.f

y lo ejecutaríamos así:

guillermo@guillermo-desktop:~$ ./a.out

con esto se resolvería el problema de compilación , si es que les llega a ocurrir esto ;)

La siguiente captura muestra como si se resolvió el inconveniente ocurrido:

 

2

Ojala y les pueda servir de algo ;)

Referencias Recomendadas:

 http://ubuntuforums.org/showthread.php?t=1164769

http://gcc.gnu.org/wiki/GFortranUsage

http://www.file-extensions.org/

 

 

Primeros pasos en la Programación Orientada a Objetos. Comenzando a escribir Clases en C++

En mi entrada anterior publique una reseña acerca de la Programación Orientada a Objetos y observamos como de las Clases se derivan Objetos, o mejor dicho instancias de las clases.

En esta entrada daremos los primeros pasos a la programación orientada a objetos utilizando el lenguaje C++. Cabe destacar que esta entrada mostraremos ejemplos simples sobre como podemos comenzar a escribir programas usando la metodología de la programación orientada a objetos.

En esencia, una clase en C++ es una estructura , que en ANSI C se conoce como struct con algunas ventajas sencillas pero muy potentes.

Declaración de clases

Para declarar una clase, todo lo que se necesita es escribir una definición de estructura y sustituir la palabra reservada struct por class. Por ejemplo, en nuestro caso vamos a escribir una clase a la que llamaremos “Empleado” con los algunos campos como el nombre, departamento, posición y función para posteriormente nos imprima la información de este.Nos quedaría de la siguiente forma:

class Empleado{

char* m_nombre;
char* m_departamento;
char* m_posición;
long m_salario;
void Imprimir( Empleado infoEmpleado);

}

Un dato curioso es que cuando nosotros declaramos una clase en C++, no se reserva memoria para la clase hasta que nosotros creamos un objeto de la clase. Como comente anteriormente crear un objeto de una clase se le llama instancia de la clase.

Veamos un ejemplo utilizando la estructura anterior: Por ejemplo podemos crear una instancia o un objeto de la clase Empleado con el valor de m_nombre=Guillermo, m_departamento=Sistemas, m_posición=programador y m_salario=3000 por mencionar un ejemplo.

En la programación orientada a objetos con toparemos con lo que comúnmente se conocen como especificadores de acceso, pero ¿Que son los especificadores de acceso?

Los especificadores de acceso permiten acceder a algunos miembros de la clase y restringir el acceso a otros.

C++ utiliza especificadores de acceso para permitir controlar a una clase el acceso a las variables de datos de esa clase

Hay tres especificadores de acceso en C++, los cuales son: public, private y protected

  • Un miembro público significa que el acceso al mismo puede darse dentro del interior de la clase, dentro de una subclase, y desde un objeto instanciado de cualquiera de estas.
  • Un miembro privado significa que el acceso al mismo puede darse solamente dentro del interior de la clase que lo posee. Normalmente, el programador creador de una clase declara a los atributos de la clase como privados y a los métodos como públicos, esto con la idea de que el usuario de la clase no pueda tener acceso a los atributos sino es atreves de los métodos definidos para el caso.
  • Un miembro protegido se comporta de manera parecida a un miembro privado, salvo que estos son accesibles dentro de la clase que lo posee y desde las clases derivadas, pero no desde los objetos instanciados a raíz de dichas clases.

Veamos un ejemplo utilizando la clase anterior:

 

class Empleado {
    private:
        char* m_nombre;
        char* m_departamento;
        char* m_posicion;
        long m_salario;
    public:
        void ImprimirInfo();
        void SetNombre( char* nombre ) { m_nombre = nombre }
        void SetDepartamento( char * departamento) { m_departamento = departamento }
        void SetPosicion ( char* posicion ) { m_posicion = posicion }
        void SetSalario ( long salario ) { m_salario = salario }
        const char* GetNombre( ){ return m_nombre }
        const char* GetDepartamento( ){ return m_departamento }
        const char* GetPosicion( ){ return m_posicion }
        const char* GetSalario( ){ return m_salario }
};

Las funciones SetNombre, SetDepartamento, setPosicion, setSalario, GetNombre, GetDepartamento, GetPosicion y GetSalario  se denominan funciones intercaladas, que son funciones que se declaran en una sola línea.
Las variables de miembro son declaradas privadas para que funciones de miembro de otras funciones no tengan acceso a ellas sino a través de la correspondiente función Get o Set. Las funciones de miembro si son declaradas públicas de tal modo que se pueda acceder a ellas desde otras funciones.
La definición de la función PrintInfo puede quedar así:

void Empleado::ImprimirInfo( )
{
   cout << "Nombre: " << m_nombre << '\n';
   cout << "Departamento: " << m_departamento << '\n';
   cout << "Puesto: " << m_posición << '\n';
   cout << "Salario: " << m_salario << '\n';
}

Los dos dos puntos ( :: ) se denomina operador de resolución de ámbito. Nos indica que la función que estamos definiendo que en este caso es ImprimirInfo, pertenece a la clase Empleado.
La tercera parte es la función main. Veamos como podría ser:

void main()
{
    //creacion de un objeto de la clase Empleado
    Empleado empleado12;
    //asignacion de valores a las variables miembro
    empleado12.SetNombre("Guillermo");
    empleado12.SetDepartamento("Sistemas");
    empleado12.SetPosicion("Programador");
    empleado12.SetSalario(3000);
    //impresión de los datos
    empleado12.ImprimirInfo();
}

Entonces, primero en : Empleado empleado12;
Se instancia un objeto de la clase Empleado con nombre empleado12. Entonces empleado12 tiene la estructura de la clase Empleado.
Luego, en las líneas siguientes a la instanciación del objeto, se le asignan los valores iniciales a sus variables:


    //asignacion de valores a las variables miembro
    empleado12.SetNombre("Guillermo");
    empleado12.SetDepartamento("Sistemas");
    empleado12.SetPosicion("Programador");
    empleado12.SetSalario(3000);


Finalmente se llama ImprimirInfo para imprimir el contenido de las variables:
        //impresion de los datos
    empleado12.ImprimirInfo();

que lo que hará es imprimir el valor de las variables en la pantalla.
Permitir el acceso a las variables solo a través de funciones, que en la mayoría de los casos se llaman SetXxx y GetXxx, se llama encapsulación de datos. Las funciones que necesitan valores de otra clase, llaman a las funciones que les dan acceso y obtienen estos datos sin conocimiento de detalles específicos de como se manipulan los datos.

Hasta este punto podemos comenzar a definir las clases en nuestros programas, un dato importante es que la forma de comenzar a escribir programas en el paradigma orientado a objetos se basa principalmente en escribir las definiciones de las clases.

Espero sea de su agrado esta entrada =)

Referencias recomendadas:

Como programar en C/C++ y Java-Harvey M. Deitel Editorial PEARSON, 4a Edición.

http://dis.unal.edu.co/~fgonza/courses/2003/poo/c++.htm

http://dis.unal.edu.co/~fgonza/courses/2003/poo/c++.htm

http://www.dcp.com.ar/poo/poop1.htm

http://es.wikibooks.org/wiki/Programaci%C3%B3n_en_C%2B%2B/Objetos_y_Clases

sábado, 20 de noviembre de 2010

Programación Orientada a Objetos. Una nueva forma de pensar.

En esta ocasión conoceremos un nuevo esquema de programación totalmente distinto a lo que conocimos anteriormente, hablamos de la programación orientada a objetos.

Pero ¿que es la Programación Orientada a Objetos?

En este nuevo modelo, cambia totalmente a lo que comúnmente estábamos acostumbrados en la programación imperativa. Por mencionar un ejemplo, algunos lenguajes no orientados a objetos como Pascal, Basic, C entre otros basan su funcionamiento en el concepto de función. La función lo podremos definir como un conjunto de instrucciones que efectúan un resultado,  de este modo los programas desarrollados en dicho paradigma no son mas una serie de llamadas entre el programa principal y el sistema operativo.

En la programación orientada a objetos cambia este esquema, ya que el elemento principal no es una función en si,  si no lo que se conoce como un objeto.

Un objeto es la representación en un programa de un concepto, y este contiene toda la
información necesaria para abstraerlo: datos que describen sus atributos y operaciones
que pueden realizarse sobre los mismos.

De esta forma la Programación Orientada a Objetos es una nueva forma de pensar una manera distinta de resolver los problemas.

Siempre se entienden mejor las cosas cuando nosotros aplicamos un ejemplo a las nuevas cosas que estamos aprendiendo, de este modo el siguiente ejemplo mostrara la forma de pensar de dicho paradigma de programación.

Si nos detenemos un momento a analizar como resolver determinado problema de programacion, al analizar con detalle los elementos o la manera en que lo podemos resolver,  descubrimos que los elementos de ese problema, si lo vemos de una forma algo abstracta podemos ver que forman una “entidad” (o también podríamos llamarlo un individuo u objeto). Estas entidades poseen un conjunto de propiedades o atributos, y un conjunto de métodos mediante los cuales muestran su comportamiento.

Y no sólo eso, también podremos descubrir,  un conjunto de interrelaciones entre las entidades, guiadas por el intercambio de mensajes; las entidades del problema responden a estos mensajes mediante la ejecución de ciertas acciones.

El siguiente ejemplo es algo raro pero sirve muy bien para que se comprendan algunos conceptos de la filosofía de la programación orientada a objetos.

Imaginemos el siguiente escenario:

Es un día viernes como cualquier otro, y yo me encuentro en casa junto a mi hermanita pequeña, de repente a mi hermanita tiene demasiada hambre; como seria mi reacción natural me dirigiría a la cocina a buscar algo de comer.

La situación anterior puede resultar un tanto extraña, pero ahora si la analizamos en términos de objetos podremos descubrir lo siguiente: El objeto “Hermano” ha  recibido un mensaje procedente del objeto “Hermanita”. El objeto ”hermano” responde al mensaje mediante una acción: buscar comida. El objeto “hermanita” no tiene que decirle al objeto “hermano” como resolver el problema, es responsabilidad del objeto “hermano” resolver el problema como considere mas conveniente.Continuemos con el escenario:

El hermano al dirigirse al refrigerador descubre que no hay nada para comer ya que es viernes. Entonces el hermano acude a una cadena de comida rápida, donde es atendido por una señorita la cual pregunta “¿que desea llevar?” a lo que el hermano responde:” una orden de pollo”. Entonces la señorita del restaurante desaparece y al poco tiempo regresa con una orden de pollo en las manos. El hermano paga el importe del producto y se regresa a su casa. En casa  el hermano le proporciona el alimento a su hermanita que luego de un rato comienza a sentirse mejor .

El objeto hermano, sabe que es lo tiene que hacer para resolver el problema, en este caso conseguir alimento. Para esto entra en juego un nuevo objeto, el objeto “señorita” quien responde al mensaje del objeto “hermano” consiguiendo el alimento. Ahora el objeto “señorita” es responsable de la solución del problema. Después el objeto “señorita” emite un mensaje al objeto “hermano” pidiéndole pagar el importe, el objeto “hermano” responde a tal mensaje con la acción de pagar.

Como hemos podido ver, en la historia nos encontramos con varios objetos que se diferencian de los demás por un conjunto de características y propiedades, también por un conjunto de acciones que realizaban en respuesta a unos eventos que se originaban en otros objetos o en el entorno.

También podemos darnos cuenta de que, aunque todos los objetos tienen propiedades
distintas, como el color del cabello, altura, edad, todos tienen un conjunto de atributos en común por ser ejemplos son de una misma entidad llamada “ser humano”. A este conjunto de objetos (en nuestro caso “ser humano”) lo llamaremos clase.

Con el ejemplo anterior espero que se comprenda que los objetos son casos particulares de las clases, y  que las clases no son mas que una ”plantilla” que definen los comportamientos, variables, y métodos comunes a todos los objetos de un mismo tipo.

En este caso vemos que la clase “ser humano” tiene entre sus muchas variables que la componen: el color de ojos, color de piel, estatura, peso, etcétera. Ahora lo importante es mencionar que a partir de una determinada clase, se pueden definir todos los objetos que se quieran especificando valores particulares para cada objeto, definidos anteriormente en las clases. Así  encontrarnos en el objeto “señorita” cuyo color de cabello es castaño, ojos negros, con una estatura 170 cm,  y así atributos específicos para cada objeto derivado esa clase.

Ahora veremos con mas detalle lo que son los objetos y las clases, las formas en que se comunican y varias definiciones de la programacion orientada a objetos.

Un objeto no es más que un conjunto de variables (datos) y métodos (funciones)
relacionados entre sí. Los objetos en programación se usan para modelar objetos o
entidades del mundo real (en el ejemplo anterior el objeto hermano, hermanita, o señorita). Un objeto es, por tanto, la representación en un programa de un concepto, y contiene toda la información necesaria para abstraerlo: datos que describen sus atributos y operaciones que pueden realizarse sobre los mismos.

OBJETO

 

Los atributos del objeto (estado) y lo que el objeto puede hacer (comportamiento) están
expresados por las variables y los métodos que componen el objeto respectivamente.
Por ejemplo, un objeto que modelase un auto en el mundo real tendría variables
que indicarían el estado actual de la bicicleta: su velocidad es de 20 km/h, su cadencia
de pedaleo 90 r.p.m. y su marcha actual es la 5ª. Estas variables se conocen
formalmente como variables instancia o variables miembro porque contienen el estado
de un objeto bicicleta particular y, en programación orientada a objetos, un objeto
particular se denomina una instancia.

Además de estas variables, el objeto bicicleta podría tener métodos para frenar, cambiar
la cadencia de pedaleo, y cambiar de marcha (la bicicleta no tendría que tener un
método para cambiar su velocidad pues ésta es función de la cadencia de pedaleo, la
marcha en la que está y de si los frenos están siendo utilizados o no, entre otros muchos
factores). Estos métodos se denominan formalmente métodos instancia o métodos
miembro, ya que cambian el estado de una instancia u objeto bicicleta particular.

El siguiente esquema lo muestra de una manera mas clara.

BICI COMO OBJETO

El diagrama del objeto bicicleta muestra las variables objeto en el núcleo o centro del
objeto y los métodos rodeando el núcleo y protegiéndolo de otros objetos del programa.
Este hecho de empaquetar o proteger las variables miembro con los métodos miembro
se denomina encapsulación. Este dibujo que muestra el núcleo de variables
miembro del objeto protegido por una membrana protectora de métodos o funciones
miembro es la representación ideal de un objeto y es el ideal que los programadores de
Bicicleta modelada como objetos suelen buscar. Sin embargo a menudo, por razones prácticas, es posible que un objeto desee exponer alguna de sus variables miembro, o proteger otras de sus propios métodos o funciones miembro. Por ejemplo, Java permite establecer 4 niveles de protección de las variables y de las funciones miembro para casos como éste. Los niveles de protección determinan qué objetos y clases pueden acceder a qué variables o a qué métodos.

El hecho de encapsular las variables y las funciones miembro
relacionadas proporciona dos importantes beneficios a los programadores de
aplicaciones:

Capacidad de crear módulos: El código fuente de un objeto puede escribirse y
mantenerse independiente del código fuente del resto de los objetos. De esta
forma, un objeto puede pasarse fácilmente de una parte a otra del programa.
Podemos dejar nuestra bicicleta a un amigo, y ésta seguirá funcionando.
Protección de información: Un objeto tendrá una interfaz pública
perfectamente definida que otros objetos podrán usar para comunicarse con él.
De esta forma, los objetos pueden mantener información privada y pueden
cambiar el modo de operar de sus funciones miembros sin que esto afecte a otros
objetos que usen estas funciones miembro. Es decir, no necesitamos entender
cómo funciona el mecanismo de cambio de marcha para hacer uso de él.

Los mensajes.

Un único objeto por sí solo no es muy útil. En general, un objeto aparece
como un componente más de un programa o una aplicación que contiene otros muchos
objetos. Es precisamente haciendo uso de esta interacción como los programadores
consiguen una funcionalidad de mayor orden y modelar comportamientos mucho más
complejos. Una bicicleta (como objeto) guardada en tu casa por sí sola, la bicicleta es incapaz de desarrollar alguna actividad. Tu bicicleta es realmente útil en tanto que otro objeto (tú) interactúa con ella (pedalea).

Los objetos de un programa interactúan y se comunican entre ellos por medio de
mensajes. Cuando un objeto A quiere que otro objeto B ejecute una de sus funciones
miembro (métodos de B), el objeto A manda un mensaje al objeto B.

¿Que es una clase?

en el mundo real existen varios objetos de un mismo tipo, o como
diremos, de una misma clase. Por ejemplo, mi bicicleta es una de las muchas
bicicletas que existen en el mundo. Usando la terminología de la programación
orientada a objetos, diremos que mi bicicleta es una instancia de la clase de objetos
conocida como bicicletas. Todas las bicicletas tienen algunos estados o atributos (color,
marcha actual, cadencia actual, dos ruedas) y algunos métodos (cambiar de marcha,
frenar) en común. Sin embargo, el estado particular de cada bicicleta es independiente
del estado de las demás bicicletas. La particularización de estos atributos puede ser
diferente. Es decir, una bicicleta podrá ser azul, y otra roja, pero ambas tienen en común
el hecho de tener una variable “color”. De este modo podemos definir una plantilla de
variables y métodos para todas las bicicletas. Las plantillas para crear objetos son
denominadas clases.
Una clase es una plantilla que define las variables y los métodos que son comunes para
todos los objetos de un cierto tipo.

La herencia.

Ya que conocemos el concepto de clase y el de objeto, estamos preparados de
introducir otra de las características básicas de la programación orientada a objetos: el
uso de la herencia.
La herencia permite definir nuevas clases partiendo de otras ya
existentes. Las clases que derivan de otras heredan automáticamente todo su
comportamiento, pero además pueden introducir características particulares propias que
las diferencian.

La programación orientada a objetos va más allá, permitiéndonos definir clases a partir
de otras clases ya construidas. Por ejemplo, las bicicletas de montaña, las de carretera y los triciclos son todos, en definitiva, bicicletas. En términos de programación orientada
a objetos, son subclases o clases derivadas de la clase bicicleta. Análogamente, la clase
bicicleta es la clase base o superclase de las bicicletas de montaña, las de carretera y los triciclos.

Una importante característica es que estas subclases no se limitan a los estados y los comportamientos que heredan de su clase base. Muy al contrario, estas subclases
pueden añadir variables y métodos a aquellas que han heredado.Las clases derivadas pueden incluso sobrescribir los métodos heredados y proporcionar implementaciones más especializadas para esos métodos.

La herencia es una herramienta clave para abordar la resolución de un problema de
forma organizada, pues permite definir una relación en una forma jerárquica entre todos los conceptos que se están manejando. Es posible emplear esta técnica para descomponer un problema de cierta magnitud en un conjunto de problemas subordinados a él.

Referencias:

Introducción a la programacion orientada a objetos.-Luis R. Izquierdo-

Programacion Orientada a Objetos con Java, una introducción practica usando BlueJ.-David J. Barnes –Michael K. Editorial PEARSON 3a Edición.

http://es.wikipedia.org/wiki/Herencia_(inform%C3%A1tica)

http://es.wikipedia.org/wiki/Objeto_(programaci%C3%B3n)

http://es.wikipedia.org/wiki/Programaci%C3%B3n_orientada_a_objetos

http://es.wikipedia.org/wiki/Clase_(inform%C3%A1tica)

miércoles, 17 de noviembre de 2010

Patrones de diseño.

Mucha de la información que uno encuentra en internet, que explica sobre lo que son los patrones de diseño, no lo explican de manera clara a las personas que nunca antes escucharon el termino,ya que utilizan definiciones bastante formales es por ello que cuando comenzamos a estudiar dichos términos pueden tornarse algo confusos o incluso tomar otro significado.

La siguiente entrada tratare de explicar lo que es un patrón de diseño para que personas que nunca antes hallan escuchado dicho termino no se les torne tan complicada la definición.

Cuando queremos resolver determinado problema de programación, al momento que estamos programando su solución es común que ciertas instrucciones las escribamos sin pensarlo mucho ya que con la misma practica vamos construyendo nuestro programa.

Ahora imaginemos que después surge otro problema similar al anterior, solo que un poco mas complejo. En este caso caemos en la necesidad de reutilizar el código que anteriormente utilizamos en el programa y agregar los detalles que este nuevo programa lo requiera, esto para ahorrarnos un poco de trabajo y tiempo.

Con el tiempo esto se torna un tanto rutinario y los programadores, tratan de averiguar nuevas formas para que el proceso de utilizar el código sea mucho mas cómodo  y que este sea lo suficientemente versátil como para no volver a modificarlo.

Entonces los programadores se dieron cuenta de este problema de tener que reescribir todas las líneas de código una y otra vez,si así su programa lo requiriera. Es por ello que así surgen lo que hoy conocemos como patrones de diseño, una forma en que todos esos códigos utilizados anteriormente pueden volver a ser reutilizados.

Los patrones de diseño nos ayudan a que nuestro código pueda volver a ser reutilizable en el momento que así lo requiriéramos, y así realizar las tareas mucho mas complejas que nos se nos presenten y esto sin necesidad de tocar el código anterior.

Dado lo anterior podemos afirmar entonces que un patrón de programación es un conjunto de soluciones a problemas que generalmente encuentras en el diseño de un programa. Cada patrón explica cómo resolver un determinado problema, bajo determinadas circunstancias, y las ventajas y desventajas de su uso.

Dependiendo de la naturaleza del problema a resolver, será el patrón mas conveniente a utilizar, en este caso nos podemos encontrar con patrones de creación, estructurales y de comportamiento.

 

  • Patrones de creación. Estos patrones se utilizan cuando debemos crear objetos pero debemos tomar decisiones dinámicamente en el proceso de creación. Para esto lo que hacemos es abstraer el proceso de creación de los objetos para realizar la decisión de qué objetos crear o cómo crearlos para el momento en que se tenga que hacer. Patrones de creación son: Abstract Factory, Builder, Factory Method, Object Pool, Prototype y Singleton.
  • Patrones estructurales. Nos describen como utilizar estructuras de datos complejas a partir de elementos más simples. Sirven para crear las interconexiones entre los distintos objetos y que estas relaciones no se vean afectadas por cambios en los requisitos del programa. Algunos ejemplos de patrones estructurales son: Adapter, Bridge, Decorator, Facade, Flyweight y Proxy.
  • Patrones de comportamiento. Fundamentalmente especifican el comportamiento entre objetos de nuestro programa. Hay varios: Chain of Responsability, Command, Interpreter, Iterator, Mediator, Memento (o Snapshot), Observer, State, Strategy, Template Method y Visitor.

 

No hay que preocuparse en este momento si todas estas definiciones tal vez suelen tornarse un poco confusas ya que aun no nos adentramos de lleno en el tema, pero ya en Programación Orientada a Objetos se vera con mucha mas detalle todas estas definiciones.

Si le interesa aprender patrones de diseño, pueden consultar el libro: UML y PATRONES, Introducción al análisis y diseño orientado a objetos el autor es Craig Larman y su editorial es PEARSON. Hay una versión en español por si les interesa ;)

Referencias recomendadas:

http://hanzcocchi.net/libro-uml-y-patrones-de-disenio/

http://msdn.microsoft.com/es-es/library/bb972240.aspx

http://www.davidvalverde.com/blog/tipos-de-patrones-de-diseno/

http://blog.innocuo.com/archive/2006/09/11/patrones-de-diseno-la-importancia-de-aprenderlos/

http://es.wikipedia.org/wiki/Patr%C3%B3n_de_dise%C3%B1o

http://catarina.udlap.mx/u_dl_a/tales/documentos/lis/diaz_c_a/capitulo4.pdf

martes, 16 de noviembre de 2010

Problema de los puentes de Königsberg. Los orígenes de la Teoría de Grafos.

Es un interesante problema que debería de explicarse cuando apenas nos adentramos al estudio de la teoría de grafos, ya que en si este problema refleja la importancia de dicho campo, como se van modelando problemas del mundo real como graficas y a su vez conocer el concepto de un ciclo Euleriano. Este problema da inicio a la teoría de grafos.
El problema dice lo siguiente:
Dado el mapa de Königsberg, con el río Pregolya dividiendo el plano en cuatro regiones distintas, que están unidas a través de los siete puentes, ¿es posible dar un paseo comenzando desde cualquiera de estas regiones, de modo de recorrerlas todas pasando sólo una vez por cada puente, y regresando al mismo punto de origen?

untitled
 
Imaginemos si lo intentáramos resolver mediante fuerza bruta, intentando cada una de las posibilidades hasta el cansancio, obviamente sin llegar al resultado esperado :P
Leonhard Euler un matemático en el año 1736 propone una ingeniosa y a la vez sencilla, forma de solucionar el problema, no solo para este caso, si no para muchos más que pueden diferir en la cantidad de puentes.
Euler formuló el problema de la siguiente manera: “En la ciudad de Königsberg, en Prusia, hay una isla llamada Kneiphof, rodeada por los dos brazos del río Pregel. Hay siete puentes a, b, c, d, e, f y g, que cruzan por los dos brazos del río. La cuestión consiste en determinar si una persona puede realizar un paseo de tal forma que cruce cada uno de estos puentes sólo una vez”.
01


Euler primeramente realizo una abstracción del modelo del mapa, quedando de una manera mucho más simple en donde él representa con puntos las regiones y con líneas los puentes que hay entre punto a punto. De esta forma el problema se reduce considerablemente.
 
Dibujo
Como resultado de ello Euler llego a la conclusión que no existe un camino, en el que pueda recorrer toda la ciudad solo pasando una sola vez.
Pero como sabemos los matemáticos son bastante analíticos, Euler no se conformo con dejarlo así, si no que nos dio una explicación razonable.
Según Euler, todo se basaba en utilizar una notación adecuada.


Entonces , Euler llamó A, B, C y D a las distintas regiones de Königsberg. El camino que va desde A hasta B puede ser por el puente a o por el b, pero Euler lo designó por AB. Una vez allí, para ir a D, se sigue el camino BD, designando la trayectoria total por ABD, y así sucesivamente hasta recorrer todas las zonas y puentes, de manera que al final se obtendrá una combinación de ocho letras. Sin embargo esta notación tiene un inconveniente, y es que no tiene en cuenta que para ir de una zona a otra puede que exista más de un puente.

En dicha combinación de letras, el camino AB debería aparecer dos veces, ya que también está el BA; el camino CA habría de aparecer otras dos veces; y tan sólo una los caminos AD, BD, y CD. Por lo tanto, las letras A, B, C, D, deben formar una serie de ocho letras, apareciendo el número requerido de veces las combinaciones de las mismas.
 

Euler vio que esta situación concreta no era posible, ya que, por ejemplo, si se empieza en la región A, si esta región sólo conectara con el puente a, como puede que se llegue o se venga de ella, la letra A aparecería una vez en la combinación de 8 letras. Si hubiera tres puentes que condujeran a la zona, entonces la letra A aparecería dos veces. Pero como llegan cinco puentes, en este caso, A debe aparecer tres veces en esa sucesión. Similarmente, B estaría dos veces; al igual que D y C. Pero entonces, ya tendríamos nueve letras en la sucesión, cuando para ser la ruta posible únicamente deberían haber ocho. Euler dedujo entonces que no se podía realizar la travesía requerida a través de los siete puentes de Königsberg .

Sin embargo, y como comente anteriormente, Euler no se contentó sólo con solucionar esta situación concreta, sino que se dedicó por completo al estudio del problema en general, obteniendo una solución que servía también para cualquier número de puentes.
Para ello, el procedimiento que siguió Euler consistió en lo siguiente: en primer lugar, apuntó en un papel el número de puentes más uno (ocho, en el caso de Königsberg ). Después, abajo a la izquierda formó una columna con todas las letras de las regiones (A, B, C y D, en este caso). A su derecha, formó una segunda columna con el número de puentes que salen de cada una de las correspondientes zonas (5, 3, 3 y 3, en este caso), marcando con un asterisco aquellas letras de las que salen un número par de puentes.

Después realizó las siguientes operaciones con los números de la segunda columna: si el número de la segunda columna (número de puentes que llegan a una determinada región) es impar, lo sumo en una unidad y lo dividió entre dos. Si el número es par, lo dividió entre dos. Euler colocó finalmente a la derecha una tercera columna con las cuentas anteriormente especificadas (3, 2,2, 2, en nuestro caso).

003
Euler  entonces llego a la conclusión que el problema sólo tendría solución si la suma de los números de la última columna es menor o igual al numero de puentes sumando una unidad. En este caso 7 puentes sumando 1 dando lugar a 8. Ese debería de ser la sumatoria de la ultima columna en dado caso que existiera una solución. En nuestro caso la sumatoria es igual a 9 es por ello que Euler determino que no existe una solución para el problema de los puentes de Königsberg
Para comprender mucho mejor la manera en que Euler resolvio el problema, es importante apreciar las siguientes cuestiones:
•La suma de los números de la segunda columna, es siempre par, ya que su          mitad refleja el número de puentes.
• Si la suma de dichos números se aumenta en dos unidades y luego se divide entre dos, el resultado es el número escrito en la parte superior de la tabla construida.
• Si los números de la segunda columna son todos pares, la tercera columna, formada por las mitades de ellos, sumará una unidad menor que el número escrito inicialmente de la tabla (con lo que la ruta será siempre posible)
• Si en la segunda columna hay sólo dos números impares, la ruta requerida será también siempre posible, porque la suma de la tercera columna coincidirá con el número inicial.
• Si hay más de dos números impares en la segunda columna,la ruta no será nunca posible, pues la suma de la tercera columna superará siempre al número inicialmente escrito.
Entonces Euler dedujo algunas  reglas para cruzar todos los puentes una sola
vez, se tienen que cumplir las siguientes condiciones:
• Si hay más de dos regiones a las que conducen un número impar de puentes, la ruta no será posible.
• Si sólo hay dos regiones a las que llega un número impar de puentes, la ruta se podrá realizar, comenzando en una de esas regiones.
• Si no hay regiones a las que conduzcan un número impar de puentes, la ruta pedida se podrá realizar, comenzando en cualquier punto.
Con esto Euler dio inicio a las primeras nociones de un grafo, donde el modeló el problema de los 7 puentes como un grafo, los vértices representaban cada una de las regiones y las aristas las conexiones entre ellas.
Con la demostración de Euler, también surgió lo que conocemos en teoría de graficas como ciclo euleriano, llamado así justamente en honor a Leonhard Euler, que representa cualquier camino dentro de un grafo particular, capaz de recorrer todas las aristas una única vez, regresando finalmente al mismo vértice original.

Referencias recomendadas:
http://en.wikipedia.org/wiki/Seven_Bridges_of_K%C3%B6nigsberg
http://mathforum.org/isaac/problems/bridges1.html
http://en.wikipedia.org/wiki/Eulerian_path
http://www.iesezequielgonzalez.com/matematicas/grafos.htm
http://es.wikipedia.org/wiki/Problema_de_los_puentes_de_K%C3%B6nigsberg
http://es.wikipedia.org/wiki/Ciclo_euleriano

Script gracioso en Java Script.

Hace un rato que estaba revisando mi correo, me encontré con algo interesante, un coreo del año 2006, en donde me envían un script (escrito en java script) mostrándome un montón de ventanas con mensajes graciosos y hasta que no finalizara la ejecución del script era cuando las ventanitas se detenían.

Sinceramente me es imposible citar alguna referencia con dicho script ya que fue hace bastante tiempo y aparte que el mismo se encuentra alojado en mi correo, por ello me es difícil saber cual es la fuente original del mismo.

En particular cuando lo analizaba no era la gran cosa, sin embargo hay algunas cosas que modifique de dicho script como algunos mensajes (ya que había algunos muy fuera de lugar y que eran un poco inapropiados :P)

El script lo subí a un servidor de Windows Live Messenger.

Advertencia:  El script es un poco molesto :P queda a criterio del usuario la ejecución del mismo :P

El link es el siguiente:

http://cid-0e91a056bbe131c6.office.live.com/self.aspx/P%c3%bablico/script%20molesto.html

El funcionamiento del script es bien sencillo, básicamente la mayoría de las instrucciones son los comandos que envían un mensaje al usuario, en este caso la instrucción

<SCRIPT>alert ('Aquí escribes tu mensaje')</SCRIPT>

La otra instrucción interesante es:

var namePrompt=prompt("Cual es su nombre","");
function dispname(namePrompt) {
document.write(""+namePrompt+"");

}
{dispname(namePrompt);
}

Que básicamente lo que hace es preguntar el nombre del usuario, lo guarda para posteriormente imprimirlo al usuario.

La ultima instrucción pero no de gran importancia es la siguiente:

<FONT face="Comic Sans MS" color=00FF00 size=10>

Que básicamente elegimos el tipo de fuente a utilizar, en este caso Comic Sans MS, el color en este caso de la paleta de colores RGB en HTML en este caso el color utilizado 00FF00 corresponde al color verde y con size se define el tamaño de la fuente.

Y con estos tres elementos principales se compone el script anterior, no es tan complicado ¿verdad?

En caso de que quieran revisar el código fuente del mismo, bastaría con abrir el archivo con cualquier editor de textos =)

domingo, 7 de noviembre de 2010

Lenguajes Logicos.


En clase se estudiaron ya varios tipos de lenguajes, que entran en la categoría de paradigma imperativo y paradigma funcional, en esta ocasión estudiaremos el paradigma lógico.
Sabemos que las aplicaciones que hemos desarrollado casi siempre siguen un mismo esquema, por ejemplo casi siempre nuestros programas involucran operaciones aritméticas, secuencias de instrucciones, etc. Muchas veces es difícil (inclusive para un programador experimentado) tratar de modelar cierto problema con la programación tradicional.
Hoy en día estos lenguajes que pertenecen a la categoría del paradigma imperativo, han evolucionado bastante que ya no es tan complicado como en varios años.
Para poder resolver problemas de este tipo tenemos a la programación lógica, que es una manera más sencilla, para el intelecto humano, de expresar problemas complejos y así poder resolverlos mediante la aplicación de reglas, hipótesis y teoremas.
De ahí surgen los lenguajes del paradigma lógico, en donde es más factible resolver ciertos problemas en donde la programación tradicional sería un fracaso.
Para tratar de demostrar esto, nuestra tarea consiste en elegir un problema lógico y modelar su solución, aplicando varias reglas de lógica, algunos teoremas del álgebra booleana, etc..
El problema que elegí está un poco largo pero no es nada del otro mundo que no podamos comprender ya que aplicaremos conceptos ya vistos en matemáticas discretas y en sistemas digitales. Está un poco encaminado al área de la electrónica digital pero sigue los mismos principios de la lógica computacional.
Mi problema es el siguiente:
Granja de Ovejas
Un granjero requiere de una alarma para detectar cuando hay peligro para sus ovejas ya que cercas del rancho, hay una manada de lobos y pueden ser devorados por ellos. El rancho cuenta con una puerta grande que solo puede ser cerrada o abierta por varios trabajadores.
Entonces hay que diseñar un sistema que
1-active la alarma cuando las ovejas estén fuera del corral y la puerta este abierta
2-active la alarma cuando los lobos estén cercas y las ovejas fuera del corral.
Todo esto aplicando reglas de lógica, y algunos teoremas.
Para ello tomaremos como variables de entrada: las ovejas, los lobos y la puerta.
La salida resultante sería la función de la alarma que implementaremos.
Entonces lo siguiente que realizaremos será una tabla de verdad en donde veremos todas las posibles condiciones.
Tomaremos los siguientes valores para trabajar.
Si la puerta está cerrada tomaremos como un 0
Si la puerta está abierta tomaremos como un 1

Si las ovejas están fuera del corral tomaremos como un 1
Si las ovejas están dentro del corral tomaremos como un 0

Si los lobos están cerca tomaremos como un 1
Si los lobos están lejos tomaremos como un 0 



Este comportamiento lo vemos representado en la tabla de verdad con todas las condiciones posibles, cuando se activara la alarma. 


Para que se comprenda mucho mejor los conceptos y tener un mejor control sobre las variables, utilizaremos las variables A para representar las ovejas, B para representar la puerta y C para representar los lobos.
Luego de esto obtendremos la función que representa el comportamiento anterior que estaría dada por la siguiente:
F=A¬ B C+A B C¬+A B C
donde solo tomaremos los resultados verdaderos para construir dicha función. Para aclaración el símbolo “¬” indica que el termino es negado.
Posteriormente de la tabla de verdad obtenida, haremos uso de algunos teoremas para reducir esta expresión algebraica booleana, estos teoremas son ampliamente utilizados en el diseño secuencial.

Haremos uso del mapa de Karnaugh. ¿Pero que son entonces los mapas de karnaugh?
Los Mapas de Karnaugh son una herramienta muy utilizada para la simplificación de circuitos lógicos. Cuando se tiene una función lógica con su tabla de verdad y se desea implementar esa función de la manera más económica posible se utiliza este método.
Para armar nuestro mapa se utiliza la formula 2^ n donde n es el numero de variables que utilizamos, en nuestro caso 3 variables, sustituyendo quedaría 2^3 que sería igual a 8. Ese será el número de casillas de nuestro mapa de Karnaugh.
Luego vamos llenando nuestro mapa con los resultados de la tabla de verdad, asignándolos en la posición correspondiente de acuerdo con nuestro mapa, por ejemplo en nuestra tabla de verdad en la posición 001 tenemos una salida que es igual a 0, posteriormente buscamos esa posición en nuestro mapa de Karnaugh y el resultado lo representaremos ahí. Haremos lo mismo con todos los valores de la tabla de verdad hasta llenar nuestro mapa de Karnaugh. 











Para que se comprenda mejor el llenado de la tabla, haremos las siguientes aclaraciones: Las dos primeras filas indican los valores que puede tomar la variable “Lobos” o la variable “C” en este caso primera fila donde C = 0 y segunda fila donde C = 1; La primera columna donde se puede observar los dos ceros agrupados, esta columna representa los valores de A y B es decir de las ovejas y de la puerta en donde toman los valores de cero AB=00(A=0 y B=0); La segunda columna al igual que la anterior representa los dos estados posibles de las variables donde AB=01(A=0 y B=1); Lo mismo para la tercera y cuarta columna AB=11(A=1 y B=1) y AB=10(A=1 y B= 0) respectivamente.
Posteriormente que llenamos nuestro mapa, hay que crear nodos agrupando en potencias de 2, los “unos” 1 que tengamos adyacentes de manera horizontal y vertical. 










 Ahora en cada grupo de unos se le asigna la unión (producto lógico) de las variables que se mantienen constante (ya sea uno o cero) ignorando aquellas que cambian.
Por ejemplo en nuestro mapa de karnaugh , nos vamos a la posición 0 1 1 que es donde tenemos nuestro primer 1 y nuestro nodo, entonces comparamos las variables A,B y C con cada uno de los nodos y solo las que permanezcan constantes, las tomaremos para formar la nueva función. 

Entonces quedaría así: 

Primera unión en la posición 0 1 1, con las variables C, A y B respectivamente.
Primera unión en la posición 1 1 1, con las variables C, A y B respectivamente.
Observamos que la variable C cambio cuando comparamos ambas posiciones y las variables A y B permanecieron constantes, entonces A y B las tomaremos para la nueva función.

Hacemos lo mismo en la segunda unión.
Segunda unión en la posición 1 1 1, con las variables C, A y B respectivamente.
Segunda unión en la posición 1 1 0, con las variables C, A y B respectivamente.
En esta segunda unión observamos que solo la variable B fue la que cambio, y las variables C y A permanecieron constantes, entonces son las que tomaremos para nuestra función.
La tabla siguiente muestra de manera mas clara el procedimiento anterior:












  






Como ya se dijo anteriormente solo se tomaron los valores que permanecieron constantes.
Nuestra nueva función ya reducida quedaría de la siguiente forma:
F= (A+B)(A+C) Agrupamos terminemos semejantes
F = A (B+C) y esta seria nuestra expresión ya reducida.

Ahora si queremos representar dicha función en un circuito o en algún lenguaje de programación, recordemos algunas de las puertas lógicas que vimos anteriormente en matemáticas discretas.
Si recordamos la puerta lógica AND indica una multiplicación y sus condiciones son: para que sus salida sea verdadera, por lo menos dos de sus entradas tendrán que ser verdaderas. Su representación es el siguiente:
 
La puerta lógica OR indica una suma y sus condiciones son: para que su salida sea verdadera, por lo menos una de sus entradas tendrá que ser verdadera. Su representación es la siguiente:


Nuestro circuito quedaria de la siguiente forma: 





 









Y de ahí solo quedaría a nuestro criterio si queremos implementarlo en un circuito electrónico o representar dicha función en un lenguaje de programación, en este caso, mas adelante lo representaremos en un lenguaje logico como lo es Prolog.

Referencias.