Buscar este blog

lunes, 30 de septiembre de 2013

Parámetros en procedimientos

En la última entrada, aprendimos a crear procedimientos: consiste en darle un nombre a un código, de manera que podamos invocarlo cuando queramos.

Nuestro procedimiento, en este momento, sirve para crear cuadrados.

void dibujaCuadrado()
{
 final def Lados = 4;
 final def Angulo = 90;
 final def Distancia = 50;
 
 for(def i = 0; i < Lados; ++i) {
  turtle.forward( Distancia );
  turtle.turnRight( Angulo );
 }
}

De acuerdo, pero quizás... podríamos hacer que la distancia (la longitud del lado, representada por la distancia que recorre la tortuga), pudiese cambiar. De esta manera, podríamos crear cuadrados más grandes o más pequeños. Eso se puede conseguir, precisamente, mediante parámetros. Le añadiremos parámetros al procedimiento, de forma que podamos cambiar algunos aspectos. De hecho, si pudiéramos cambiar el número de lados... ¡podríamos dibujar cualquier polígono regular, pues el ángulo se obtiene dividiendo 360 entre el número de lados!

Sintaxis de creación del procedimiento

void nombreProcedimiento(tipo1 id1 [, tipo2 id2 [,... tipon idn]])
{
    instruccion1;
    instruccion2;
    ...
    instruccionn;
}

Sintaxis de llamada al procedimiento

nombreProcedimiento( expresión1 [, expresión2 [,... expresiónn]]);
Los parámetros, tal cual aparecen en la definición del procedimiento, se denominan formales. Los que aparecen cuando llamamos al procedimiento, se denominan reales. Los parámetros reales pueden ser valores literales, variables, cálculos...

Ejemplo

void dibujaPoligono(int lados, int distancia)
{
 def angulo = 360 / lados;
 
 for(def i = 0; i < lados; ++i) {
  turtle.forward( distancia );
  turtle.turnRight( angulo );
 }
}

dibujaPoligono( 4, 50 );

En este ejemplo, estaríamos dibujando un polígono regular de 4 lados, es decir, un cuadrado cuyo lado es de longitud 50.

Ejemplo

Podemos hacer figuras aleatorias utilizando el procedimiento rand() en el módulo math. Veamos un programa completo, que crea cuatro figuras haciendo girar la tortuga cuatro veces.

/** @name   poligonos
  * @brief  Dibuja polígonos al azar
  * @author jbgarcia@uvigo.es
  * @date   2013-9-30
  */

import media.gw;
import media.turtle;
import std.math;

void dibujaPoligono(int lados, int distancia)
{
 def angulo = 360 / lados;
 
 for(def i = 0; i < lados; ++i) {
  turtle.forward( distancia );
  turtle.turnRight( angulo );
 }
}

for(def i = 0; i < 4; ++i) {
 dibujaPoligono( ( rand() * 15 ) + 3, 20 );

 turtle.setPen( false );
 turtle.forward( 60 );
 turtle.turnRight( 90 );
 turtle.setPen( true );
}

domingo, 29 de septiembre de 2013

Procedimientos

Los procedimientos son bloques de código a los que se les da un nombre, para poder utilizarlos más adelante mediante ese nombre.

Los bloques de código se encierran entre llaves { y }. No es nada nuevo, en realidad: los hemos estado utilizando constantemente para indicar el código que se debe ejecutar cuando una condición se cumple (o no), o cuando una repetición se sucede. Por supuesto, tienen muchas más posibilidades, que iremos desgranando poco a poco.

Sintaxis

void nombreProcedimiento()
{
    instruccion1;
    instruccion2;
    ...
    instruccionn;
}

Ejemplo

void dibujaCuadrado()
{
    for(def i = 0; i < 4; ++i) {
        turtle.forward( 100 );
        turtle.turnRight( 90 );
    }
}

Ahora disponemos de un código que podemos invocar cuando queramos. Por ejemplo, sería posible dibujar cuatro cuadrados seguidos con solo llamar a este procedimiento. Para hacerlo, solo es necesario poner su nombre, y a continuación, la apertura y cierre de paréntesis.

turtle.forward( 25 );
dibujaCuadrado();

turtle.forward( 25 );
dibujaCuadrado();

turtle.forward( 25 );
dibujaCuadrado();

turtle.forward( 25 );
dibujaCuadrado();

Por supuesto, ya sabemos que podemos mejorar un poco este código. Todo lo que suponga repeticiones, es mejor, al fin y al cabo, meterlo dentro de un bucle:

for(def i = 0; i < 4; ++i) {
    turtle.forward( 25 );
    dibujaCuadrado()
}

Hablando de mejorar el código, no es bueno que aparezcan tantas constantes que no sabemos muy bien de dónde salen. Aunque en este momento estamos exagerando, pronto veremos que es muy útil tener estos valores como constantes o variables. Podemos mejorar nuestro primer procedimiento:

void dibujaCuadrado()
{
 final def Lados = 4;
 final def Angulo = 90;
 final def Distancia = 50;
 
 for(def i = 0; i < Lados; ++i) {
  turtle.forward( Distancia );
  turtle.turnRight( Angulo );
 }
}


Programa final

El programa final, que hemos ido desgranando en esta entrada, queda como aparece más abajo. Se ha introducido el uso de setPen(), un procedimiento en el módulo turtle. Lo que hace este procedimiento (sí, son también procedimientos de la librería de jC), es evitar que la tortuga deje rastro o no, según se le pase true o false.


/** @name   Cuadrado4
  * @brief  Dibuja cuatro cuadrados en la pantalla.
  * @author jbgarcia@uvigo.es
  * @date   2013-09-29
  */

import media.gw;
import media.turtle;

void dibujaCuadrado()
{
 final def Lados = 4;
 final def Angulo = 90;
 final def Distancia = 50;
 
 for(def i = 0; i < Lados; ++i) {
  turtle.forward( Distancia );
  turtle.turnRight( Angulo );
 }
}

for(def i = 0; i < 4; ++i) {
 turtle.setPen( false );
 turtle.turnRight( 90 );
 turtle.forward( 25 );
 turtle.setPen( true );
 dibujaCuadrado();
}

viernes, 27 de septiembre de 2013

JavaScript backend

Han sucedido algunas novedades desde que empecé este pequeño blog. En concreto, me estoy refiriendo a la nueva habilidad de jC de compilar a JavaScript.

En la imagen se puede ver el resultado, tras pulsar el botón play con el programa star.jc cargado (publicado recientemente). Tras compilar a un HTML con el código JavaScript, lo abre en el navegador del sistema.

Esto permite cosas muy chulas, como una sección en la web de jC para ejemplos... que son ejecutables por el usuario. Cuando el usuario pulsa el botón de ejecutar, arranca un programa creado con jC.

La idea de crear código para BeanShell, nunca me acabó de convencer. El objetivo era ir teniendo "algo", para más adelante compilar a Java, es decir, a un jar. Sin embargo, creo que la idea de compilar a JavaScript es todavía mucho mejor que compilar a Java, pues hoy en día los navegadores que soportan JavaScript son todavía más ubícuos que los Java Applets, que están desapareciendo de Internet.

En cualquier caso, es posible escoger la plataforma objetivo (BeanShell, o JavaScript) en Edición >> Preferencias.

Las sintaxis de Java (y, por lo tanto, BeanShell) y JavaScript son muy parecidas, así que el mayor esfuerzo consistió en portar las librerías, en realidad.

En fin, ¡a disfrutarlo!

lunes, 9 de septiembre de 2013

Tipos y variables (o constantes)

Hasta ahora, cuando queríamos definir variables y constantes, lo hacíamos así:

final def Lados = 4;    // Constante
def distancia = 2;      // Variable

No es que no se pueda seguir haciendo así (es perfectamente válido, e incluso recomendado), pero es mejor que vayamos teniendo en cuenta qué está sucediendo "por debajo".

Cuando jC detecta la palabra reservada def, lo que hace es fijarse en lo que aparece después del símbolo igual, la asignación, para saber qué tipo debe asignarlo a la variable. Por ejemplo, en el caso de arriba, tanto a Lados como a distancia se le asigna el tipo número entero o int.

Si nos planteamos el siguiente caso:

final def PI = 3.1416;
final def CR = '\n';

En este caso, jC deduce que el tipo para PI es número flotante, que se denomina double (por doble precisión). El tipo para CR es un carácter, o char. La tabla completa de tipos disponibles es la siguiente:

TipoExplicación
booleanSólo puede almacenar dos valores: true(o verdadero) or false (falso). Además, true y false son palabras reservadas en el lenguaje (no se pueden crear variables con esos nombres, por ejemplo). Una condición, como por ejemplo, i > 5, se evalúa a true o false.
charUsado para representar caracteres, según la norma UTF-16.
intNumeros enteros (positivos, el cero, y negativos). Es capaz de representar números de -2 mil millones a +2 mil millones.
doubleNúmeros reales o en coma flotante. Soportan un rango muy grande, aunque precisamente debido a temas de precisión, para realizar comparaciones numéricas entre números enteros, es mejor utilizar int.

Las definiciones que aparecen más arriba se pueden reescribir así:

final int Lados = 4;    // Constante
int distancia = 2;      // Variable
final double PI = 3.1416;
final double CR = '\n';

¡Es el momento de experimentar! En cualquier lugar donde se escribe def, se puede sustituir por su tipo, que ahora ya sabemos cuáles son (al menos los tipos básicos, pronto veremos los tipos complejos).

Un ejemplo:

/** @name   Poly
  * @brief  Dibuja polígonos
  * @author jbgarcia@uvigo.es
  * @date   2013-8-10
  */

import media.gw;
import media.turtle;

final int Lados = 4;
final int Distancia = 35;

double angulo = 360 / Lados;

gw.setTitle( "Poly" );
for(int i = 0; i < Lados; ++i) {
 turtle.turnRight( angulo );
 turtle.forward( Distancia );
}

Y recuerda, no es que no se pueda utilizar def, de hecho es más cómodo, y por tanto aconsejable.