![]() | ![]() | ![]() | El lenguaje de las Rutinas |
El propósito de este capítulo es el de introducir a los principiantes a Inform como si se tratara de un lenguaje de programación de propósito general, en lugar de una herramienta específica para diseñar aventuras de texto. Los ejemplos dados serán programas cortos que realizan cálculos simples, en lugar de juegos. Para comenzar, el lenguaje Inform es:
El ordenador ejecuta un programa en Inform (que no tiene por qué ser un juego) con la ayuda de un "intérprete". Existen al menos 40 intérpretes diferentes disponibles para este formato (llamado "máquina-Z" o "formato Infocom") y puede que haya varios para tu modelo de ordenador: es una buena idea tratar de conseguir el más moderno y preciso posible. Fíjate en si soportan el standard de la máquina-Z, y, si es así, hasta qué número de revisión.
Tradicionalmente, todos los cursos de lenguajes de programación comienzan dando un programa que no hace nada más que imprimir "Hola, mundo". Aquí hay un programa de ese estilo en Inform:
! Programa de ejemplo "Hola, mundo" [ Main; print "Hola, mundo^"; ]; |
El texto tras el signo de exclamación es un "comentario", esto es, un texto escrito al margen por el autor para recordarse a sí mismo (o a las otras personas que puedan encontrarse leyendo ese código) qué es lo que ocurre en el programa. Tal texto no significa nada para Inform, que se limita a ignorar todo lo que haya en la misma línea y a la derecha del signo de exclamación.
Una vez que se han sacado los comentarios, Inform considera el código fuente como una lista de cosas a hacer, divididas por punto y coma ';'. Trata los retornos de carro, las tabulaciones y los espacios como "espacio en blanco": esto es, un agujero entre dos cosas cuyo tamaño no es importante. Así, podría producirse exactamente el mismo programa con este código fuente:
[
Main ;
print
"Hola, mundo^" ;
]
;
|
o, en el otro extremo, con este otro:
[ Main;print"Hola, mundo^";]; |
La legibilidad de un programa es una cuestión de buenos hábitos de formateo.
![]() |
La excepción a la regla por la que se ignoran
los espacios en blanco es el texto entrecomillado, donde
y
son dos fragmentos de texto genuinamente diferentes y que serán tratados como tales. Inform trata el texto entrecomillado con mucho más cuidado que el otro material del programa: por ejemplo, un signo de exclamación encontrado dentro de unas comillas no hará que el resto de la línea se deseche como un comentario. |
Cada programa debe contener una rutina llamada Main, y en este
ejemplo es la única rutina. Cuando un programa está siendo ejecutado,
la primera instrucción obedecida es la primera de Main, y luego se
continúa línea por línea a partir de ahí. Este proceso es llamado
"ejecución". Cuando la rutina Main termina, el programa para.
La rutina tiene sólo una instrucción:
print "Hola, mundo^" |
Imprimir es el proceso de escribir texto en la pantalla del ordenador.
La instrucción print imprime las dos palabras "Hola, mundo" y luego
se salta el resto de la línea (o "imprime una nueva línea"): el
caracter ^, en un texto entrecomillado, significa "nueva línea". Por
ejemplo, la instrucción
print "Azul^Rojo^Verde^" |
imprime:
Azul Rojo Verde |
print es una de las 28 instrucciones del lenguaje Inform. La lista
completa es la siguiente:
box break continue do font for give
if inversion jump move new_line objectloop print
print_ret quit read remove restore return rfalse
rtrue save spaces string style switch while
(Sólo unas 20 de estas se usan normalmente). La sección actual trata de todas las instrucciones no relacionadas con objetos. Estas últimas se tratarán en la sección * .
El siguiente código fuente tiene tres rutinas, Main, Quijote y
Sancho :
[ Main; print "Saludos desde un lugar de la Mancha...^"; Quijote(); ]; [ Quijote; print "... de cuyo nombre...^"; ]; [ Sancho; print "...no quiero acordarme.^"; ]; |
El programa resultante imprime
Saludos desde un lugar de la Mancha... ... de cuyo nombre... |
pero el texto "...no quiero acordarme." no se imprime. La
ejecución comienza en Main , y "Saludos desde un lugar de la
Mancha..." se imprime; después, la instrucción Quijote() hace que se
ejecute la rutina Quijote . Así continúa hasta que termina con el
marcador de final de rutina ']', con lo que la ejecución vuelve a la
rutina Main justo tras el punto en el que se dejó; dado que no hay
nada más que hacer en Main , el programa finaliza. Así, Quijote se
ejecuta pero Sancho no.
De hecho, cuando se compila el programa de arriba, Inform se da cuenta
de que Sancho no es necesaria e imprime una advertencia indicándolo.
El texto exacto producido por Inform varía de una máquina a otra, pero
es algo parecido a esto:
DJGPP Inform 6.15 (22nd March 1998) line 8: Warning: Routine "Sancho" declared but not used Compiled with 0 errors and 1 warning |
Los errores son fallos en el programa que hacen que Inform se niegue a
compilarlo, pero esto es sólo una advertencia. Hace notar al
programador que puede que se haya equivocado (porque presumiblemente
ha olvidado poner una instrucción que llame a Sancho) pero no impide
que la compilación tenga lugar. Obsérvese que la rutina Sancho
comienza en la octava línea del programa anterior.
Normalmente se producen fallos en un programa escrito desde cero y uno
ha de pasar por un proceso de ejecutar un primer borrador, recibir unos
cuantos mensajes de error, corregir el borrador de acuerdo con los
mensajes, e intentarlo de nuevo. Un mensaje de error típico habría
aparecido si, en la línea 3, hubiésemos escrito Qujote() en lugar de
Quijote() . Inform habría producido entonces:
DJGPP Inform 6.15 (22nd March 1998)) line 5: Warning: Routine "Quijote" declared but not used line 8: Warning: Routine "Sancho" declared but not used line 3: Error: No such constant as "Qujote" Compiled with 1 error and 2 warnings (no output) |
El mensaje de error significa que en la línea 3 Inform se encontró con
un nombre que no corresponde a ninguna entidad conocida (no es el
nombre de ninguna rutina, en particular). Obsérvese que Inform nunca
produce el archivo de juego final si encuentra errores durante la
compilación; esto evita que produzca archivos dañados. Obsérvese
también que ahora Inform piensa que la rutina Quijote no está siendo
usada, dado que no reconoció el error tipográfico, como habría hecho un
lector humano. Las advertencias se producen a veces por accidentes como
estos, así que normalmente es una buena idea preocuparse de arreglar
los errores primero y las advertencias después.
Internamente --esto es, a pesar de la apariencia externa-- todos los programas manipulan números, esencialmente. Inform entiende como "número" a un número entero entre -32768 y +32768. (Se requiere una programación especial para representar números mayores o fracciones.) Hay tres notaciones para escribir números en Inform: aquí hay un ejemplo de cada una de ellas:
-4205
$3f08
$$1000111010110
La diferencia es la base en la que están expresadas. La primera están
en decimal (base 10), la segunda en hexadecimal (base 16, donde los
dígitos después del 9 se escriben de `a' a `f' o de `A' a `F') y la
tercera en binario (base 2). Una vez que Inform ha leído un número, se
olvida de qué notación fue usada: por ejemplo, si el código fuente se
altera de modo que $$10110 se sustituya por 22, esto no supone
ninguna diferencia en el programa producido.
Una instrucción print puede imprimir números al igual que texto, pero siempre los imprime en notación decimal normal, Por ejemplo, el programa
[ Main; print "El número de hoy es ", $3f08, ".^"; ]; |
imprime
El número de hoy es 16136. |
dado que 16136 en base 10 es el mismo número que 3f08 en
hexadecimal.
Inform reconoce muchas otras notaciones como "constantes", esto es, valores que están descritos específicamente en el código fuente. Una lista completa aparece más tarde, pero un caso particular es el de un solo caracter entre comillas simples. Por ejemplo
'x'
es una constante. Un "caracter" es una sola letra o símbolo tipográfico, y todo lo que el programador necesita saber es que cada posible caracter tiene su propio valor numérico.
![]() |
Para la mayoría de los caracteres, este valor numérico es el
valor estandar ASCII del caracter: por ejemplo, 'x' tiene un valor
numérico de 120. (Esto es cierto incluso si Inform está ejecutándose en
un modelo de ordenador que no utiliza normalmente el juego de
caracteres ASCII). Los caracteres exóticos como '@ss' (la notación en
Inform de la sz alemana) tienen códigos no estandar: véase el Z-Machine
Standard Document si realmente se quiere saber más sobre esto.
|
Finalmente, en este grupo de notación de constantes, Inform provee dos constantes especiales:
true
false
que se usan para describir la verdad o la falsedad de posibles condiciones.
![]() |
true tiene el valor numérico 1; false tiene el valor numérico 0.
|
Inform tiene un concepto de "variable" como el que se usa en álgebra, donde es fácil pero limitado expresar hechos usando sólo números:
34 - 34 = 0
11 - 11 = 0
694 - 694 = 0
Aunque es sugerente, esto no sirve para expresar el caso general: que cualquier número restado a sí mismo es igual a cero. Expresamos este hecho simbólicamente en álgebra escribiendo
x-x=0
donde x es una variable; esto viene a decir "para cualquier valor que tome x, esto sigue siendo verdadero".
De la misma forma, en Inform lo que podría parecer una palabra en texto
puede ser una variable que representa un número; cuando el código
fuente se compila, Inform no puede saber qué valor numérico representa
este texto. Cuando el programa se ejecuta, siempre tendrá un valor
numérico en cualquier momento dado. Si aceite_restante es una variable,
la instrucción
print "Quedan ", aceite_restante, " galones.^"; |
se ejecuta como si aceite_restante se sustituyera por
cualquiera que sea el valor actual de la variable. Más tarde, la misma
instrucción podría ejecutarse de nuevo, produciendo un texto diferente
porque por aquel entonces aceite_restante tiene un valor diferente.
Inform sólo puede saber que un texto (tal como aceite_restante)
representa una variable si el código fuente ha "declarado" que lo es.
Cada rutina puede declarar su propia selección de variables en su línea
inicial. Por ejemplo, en el programa
[ Main alfa b;
alfa = 2200;
b = 201;
print "Alfa es ", alfa, " mientras que b es ", b, "^";
];
|
la rutina Main tiene dos variables, alfa y b . Del
mismo modo que la mayoría de los nombres que se dan en el código fuente
(llamados "identificadores"), los nombres de variable pueden tener
una longitud de hasta 32 caracteres y pueden contener letras del
alfabeto, dígitos decimales o el caracter de subrayado `_' (usado a
menudo para imitar un espacio). Sin embargo, a fin de evitar que se
parezcan demasiado a los números, no pueden comenzar con un dígito
decimal. (Así que a44 es legal pero 44a no lo es). Por ejemplo:
turnos_por_jugar
grafico45
X
son todos posibles nombres de variable. Inform ignora
cualquier diferencia entre mayúsculas y minúsculas en tales nombres,
considerando, por ejemplo, a GRAfico45 y a graFiCO45 como el mismo
nombre.
![]() | Los nombres de variables no admiten acentos ni eñe. |
Los dos signos `=' que aparecen en la rutina de más arriba son
ejemplos de "operadores": notaciones realizadas normalmente con los
símbolos de las teclas no alfabéticas de un teclado y que significan
que algo debe hacerse con los objetos que se encuentran junto a ellos.
En este contexto, `=' significa "haz que sea igual a". Cuando la
instrucción alfa = 2200 se ejecuta en tiempo de ejecución, el valor
actual de la variable alfa pasa a ser 2200 (y mantiene ese valor
hasta que otra instrucción lo altere).
Las variables alfa y b se llaman "variables locales" porque son
locales a Main ; de hecho, son su propiedad privada. El programa
[ Main alfa; alfa = 2200; Rival(); ]; [ Rival; print alfa; ]; |
causa un error en la instrucción print en Rival, porque
alfa no existe allí. De hecho, Rival podría incluso haber definido
una variable propia llamada también alfa , y esta hubiese sido una
variable separada de la otra y con un valor probablemente diferente.
El lenguaje Inform es bastante rico en operadores, lo cual lo hace conciso pero no siempre muy legible. Es muy importante sentirse cómodo con los operadores, como primer paso para poder comprender adecuadamente un código fuente en Inform. Afortunadamente, estos operadores se basan en las reglas habituales para escribir fórmulas aritméticas, con lo cual resultan bastante familiares a cualquiera.
De hecho, los operadores usados con mayor frecuencia son "aritméticos": combinan uno o más números para dar como resultado otro número. Siempre que un número es requerido en una instrucción, este puede ser sustituído por una expresión que dé como resultado un número. Por ejemplo, la instrucción
segundos = 60*minutos + 3600*horas; |
asigna a la variable segundos el resultado de multiplicar
la variable minutos por 60 más el resultado de multiplicar la
variable horas por 3600. No se necesita poner espacios en blanco
entre los operadores y los "operandos" (los números con los que se
trabaja): los espacios colocados a ambos lados del signo + están ahí
para hacer el texto más legible.
Las operaciones aritméticas básicas se realizan con la ayuda de los
operadores + (más), - (menos), * (por) y / (dividido entre).
Normalmente al dividir un entero por otro queda un resto: por ejemplo,
el 3 cabe dos veces en el 7, con lo que resta 1. En notación de Inform,
7/3 da como resultado 2, 7%3 da como resultado 1.
El operador % calcula el resto tras la división, llamado simplemente
"resto". No es posible hacer una división por cero, y un programa que
lo intente fallará.
![]() |
Esto es un pequeño ejemplo de cómo Inform puede (y cómo no puede)
ayudar al programador a encontrar errores. El programa
produce un error cuando se compila:
dado que Inform puede ver claramente que se está intentado realizar una acción ilegal. Sin embargo, Inform no acierta a encontrar ningún error en el siguiente programa, equivalente al anterior:
y este programa compila correctamente. El archivo producido se "colgará" cuando sea ejecutado, es decir, producirá un error fatal y se parará. La moraleja es que el sólo hecho de que Inform compile un programa sin errores no garantiza que el programa haga lo que el programador pretendía que hiciese. |
En una expresión compleja, el orden de los operadores puede afectar al resutado. Las dos siguientes expresiones:
23 + 2 * 700
2 * 700 + 23
dan como resultado 1423, porque el operador * tiene
"precedencia" sobre el +, y por esto se calcula primero la
multiplicación y luego la suma. Si se quiere evitar esto, se han de
usar paréntesis:
(23 + 2) * 700
2 * (700 + 23)
dan como resultado 17500 y 1446, respectivamente. Cada
operador tiene entonces un "nivel de precedencia". Cuando dos
operadores tienen el mismo nivel de precedencia (por ejemplo, + y -
tienen la misma precedencia), los cálculos se realizan (casi siempre)
de izquierda a derecha. La notación
a - b - c
es equivalente a
(a - b) - c
Las reglas matemáticas estándar dan a + y - igual precedencia, menor
que la de * y / (que también tienen la misma). En Inform, también el
operador % tiene la misma precedencia que * y /.
El último operador púramente aritmético que queda es el "menos
monario". Este se escribe como un signo menos `-', pero no significa
lo mismo que una resta normal. La expresión:
-credito
significa lo mismo que:
0 - credito
El operador - es diferente de todos los mencionados hasta ahora
porque opera con un sólo número. Tiene mayor precedencia que cualquiera
de los cinco operadores "binarios" tratados de más arriba. Por
ejemplo,
-credito - 5
significa (-credito) - 5 y no -(credito -5).
Un modo de imaginar la precedencia es pensar en ella como si estuviese pegada al operador con pegamento. Un nivel superior significa un pegamento más fuerte. Así, en
23 + 2 * 700
el pegamento alrededor de * es más fuerte que el que hay
alrededor de +, así que tanto el 2 como el 700 se quedan unidos a él.
Algunos operadores no actúan simplemente sobre los valores, sino que
cambian realmente el valor actual de las variables; las expresiones que
los contienen se llaman "asignaciones" (porque asignan valores a la
vez que trabajan con ellos). Uno de estos operadores es el símbolo
igual `=':
alfa = 72
asigna el valor 72 a la variable alfa .
Los otros dos operadores de asignación son ++ y --, que sin duda
serán familiares a cualquier programador de C. Son operadores unarios,
y pueden usarse de cualquiera de las siguientes maneras:
variable++
++variable
variable--
--variable
La primera significa "lee el valor de variable, y después incrementa
ese valor en uno". En ++variable el incremento ocurre antes de que
se lea el valor de la variable. -- trabaja de modo similar, pero
"decrementando" (reduciendo en 1) el valor de variable . Estos
operadores existen como formas abreviadas, dado que se podrían
conseguir los mismos efectos de otras maneras (usando sólo + y -).
Por ejemplo, supongamos que variable tiene el valor 12. Entonces tal
valor sería 12, 13, 12 y 11 respectivamente en el momento en que las
asignaciones anteriores lo leen, y 13, 13, 11 y 11 después de que hayan
realizado los incrementos y decrementos pertinentes.
Nótese que expresiones como
500++ (4*alfa)-- 34 = beta
no tienen sentido: los valores 500 y 34 no pueden alterarse,
e Inform no conoce ninguna forma de hacer que 4*alfa se decremente en
uno. Todas estas expresiones producirán errores.
![]() | Los "operadores a nivel de bit" se proporcionan para realizar números binarios, dígito a dígito. Esto se realiza a menudo en programas que utilizan los datos a un nivel muy bajo. *****FALTA***** |
![]() | Los operadores restantes se describirán más tarde a medida que sean necesarios. La tabla completa con todos ellos se encuentra en el Apéndice *. |
Como ya se ha dicho, en jerga "informita" la palabra "función" es sinónima de "rutina". Una función podría definirse como la correspondencia
(x1, ..., xn) ->f(x1, ..., xn)
donde una serie de números suministrados consituyen la entrada, y un sólo valor la salida. Estos números de entrada reciben el nombre de "argumentos". El número de salida recibe el nombre de "valor de retorno", y se dice que ha sido "devuelto" por la función.
Todas las rutinas de Inform funcionan así. Un cierto número de
argumentos se suministran a la rutina cuando esta es "llamada" (es
decir, cuando se la pone a funcionar) y siempre hay un único valor
numérico como resultado. Algunas rutinas muy simples ocultan este
hecho. Por ejemplo, considera el ejemplo Soneto:
[ Main; Soneto(); ]; [ Soneto; print "Un soneto me manda hacer Violante^"; print "que en mi vida me he visto en tal aprieto^"; ]; |
Soneto es una rutina que no toma ningún valor como entrada (esto es,
no tiene argumentos). Es un ejemplo del caso n = 0. Así que su
llamada no lleva nada entre los paréntesis. Aunque de hecho devuelve
un valor (este valor es true), la instrucción Soneto() simplemente
llama a la rutina y desecha el valor retornado. Si Main hubiese sido
[ Main; print Soneto(); ]; |
entonces el resultado al ejecutar el programa hubiese sido
Un soneto me manda hacer Violante que en mi vida me he visto en tal aprieto 1 |
porque a la instrucción print en Main se le ha dicho que
imprima el número resultante de la llamada a Soneto.
O sea, en Inform no existe el concepto de "procedimiento" (función que no devuelve nada): cada rutina devuelve siempre un valor, aunque muchas veces este se deseche inmediatamente sin darle ningún uso.
Cuando se llama a una rutina,
Rutina(arg1, ...)
los argumentos dados (es decir, arg1 y los que sigan) son
substituídos por las primeras variables declaradas para Rutina, y
luego se continúa ejecutando Rutina. Normalmente, puede haber
cualquier número de argumentos desde cero hasta 7, aunque se impone
un límite de 7 si se desea que Inform compile un archivo de juego de
un modelo anterior (véase sección sobre limitaciones de la máquina
Z).
Si la ejecución llega al marcador de final de rutina `]' de tal modo
que acaba sin que se haya especificado ningún valor de retorno
definido, entonces este valor es true. (Por esto es por lo que el
valor de retorno de Soneto es 1: true tiene el valor de 1.)
Un ejemplo más típico, aunque desde luego menos estético, que
Soneto:
[ Main; print Cubo(1), " "; print Cubo(2), " "; print Cubo(3), " "; print Cubo(4), " "; print Cubo(5), "^"; ]; [ Cubo x; return x*x*x; ]; |
que, cuando es ejecutado, imprime
1 8 27 64 125 |
La expresión Cubo(3) se calcula substituyendo la x por el número 3
cuando se ejecuta la rutina Cubo en ese punto; el resultado de la
expresión es el número devuelto por Cubo.
Cualquier argumento que falte en la llamada a una rutina se considera
cero, de modo que la llamada Cubo() es legal y produce lo mismo que
Cubo(0).
Las rutinas anteriores son demasiado simples, incluso para expresar muchas funciones matemáticas, y por ello se necesitan nuevos elementos que añadan mayor flexibilidad.
Una "estructura de control" es un tipo de instrucción que controla
si otras instrucciones se ejecutan o no, y si lo hacen, cuántas veces
o en qué orden. De estas, la más simple es if:
if (<condición>) <instrucción>
lo cual ejecuta la <instrucción> sólo si la <condición>, en el momento en que se examina, es cierta. Por ejemplo, cuando la instrucción
if (alfa == 3) print "Hola"; |
se ejecuta, la palabra "Hola" se imprime sólo si la variable
alfa tiene el valor 3. Es importante no confundir el operador ==
(examinar si algo es o no igual a otra cosa) con el operador = (de
asignación de valores).
Las condiciones siempre se dan entre paréntesis. Las condiciones básicas son:
(a == b) | El número a es igual al número b |
(a ~= b) | El número a no es igual al número b |
(a >= b) | a es mayor o igual a b |
(a <= b) | a es menor o igual a b |
(a > b) | a es mayor que b |
(a < b) | a es menor que b |
(o1 in o2) | El objeto o1 es poseído por o2 |
(o1 notin o2) | El objeto o1 no es poseído por o2 |
(o1 has a) | El objeto o1 tiene el atributo a |
(o1 hasnt a) | El objeto o1 no tiene el atributo a |
(o1 provides m) | El objeto o1 proporciona la propiedad m |
(o1 ofclass c) | El objeto o1 hereda la clase c |
(Las condiciones referidas a objetos se explicarán más tarde). El
operador especial or supone una extensión útil de este conjunto, y
sirve para dar alternativas. Por ejemplo,
if (alfa == 3 or 4) print "Scott"; if (alfa ~= 5 or 7 or 9) print "Amundsen"; |
donde se dan dos o más valores con la palabra or
entre ellos. Se imprime "Scott" si el valor de alfa es de 3 o 4, y
se imprime "Amundsen" si el valor de alfa no es 5, ni 7, ni 9.
or puede usarse con cualquiera de las condiciones, y se puede dar
cualquier número de alternativas. Por ejemplo
if (jugador in Bosque or Pueblo or Edificio) ... |
hace que el código sea mucho más claro que si escribiésemos tres condiciones separadas; o
if (x > 100 or y) ... |
puede ser conveniente para determinar si x es mayor que el
menor de 100 o y.
Las condiciones también se pueden construir partiendo de otras más
simples (del mismo modo que las expresiones se componen de operadores
simples) usando los tres operadores lógicos &&, || y ~~
(llamados "y", "o", y "no"). Por ejemplo,
if (alfa == 1 && (beta > 10 || beta < -10)) print "Lewis"; if (~~(alfa > 6)) print "Clark"; |
"Lewis" se imprime si alfa es igual a 1 y beta está fuera del
intervalo -10, 10; "Clark" se imprime si alfa es menor o igual a
6.
Lo anterior puede llevar a pensar que las condiciones son un tipo
especial de expresión que usa un cierto tipo de operadores (==,
&&, or, etc.). Pero esto no es así: no son especiales, las
condiciones son expresiones como cualquier otra. Es legal escribir
print (beta == 4); |
por ejemplo, y el resultado será imprimir 1 si beta es
igual a 4, o 0 si no. Entonces:
el resultado de una condición verdadera es 1; el resultado de una condición falsa es 0.
Esta es la razón por la que true y false se definieron como 1 y 0
respectivamente. Luego podríamos escribir código como
betaescuatro = (beta == 4); ... if (betaescuatro == true) ... |
aunque sería más sencillo escribir
betaescuatro = (beta == 4); ... if (betaescuatro) ... |
porque, del mismo modo que las condiciones pueden usarse como números, los números también pueden usarse como condiciones. Cero se considera como "falso", y todos los otros valores son considerados "verdaderos". Luego
if (1) print "Vasco"; if (0) print "da Gama"; |
siempre resultará en imprimir "Vasco", nunca "da Gama".
Un uso habitual de las variables consiste en utilizarlas como "banderas". Una bandera puede tener tan sólo el valor 0 o el 1, falso o verdadero dependiendo del estado del programa1. El hecho de que un número puede usarse como una condición permite la construcción de instrucciones de significado intuitivo, como
if (cavernas_inferiores_exploradas) print "Ya has estado por ahí abajo."; |
donde cavernas_inferiores_exploradas es una variable que
el programa usa como bandera.
![]() |
Nótese que && y || sólo calculan aquello que es absolutamente
necesario para determinar el valor de verdad. Esto es,
if (A && B) ...
calculará primero
if (x == 7 && Rutina (5)) ...
donde puede ser importante saber que la |
El factorial de un entero positivo n se define como el producto de 1 ×2 ×3 ×...×n, de modo que, por ejemplo, el factorial de 4 es 24. Aquí hay una rutina de Inform que calcula factoriales:
[ Main; print Factorial(7), "^"; ]; [ Factorial n; if (n==1) return 1; return n*Factorial(n-1); ]; |
Esto calcula el factorial de 7 y da como resultado 5040. (Los
factoriales crecen rápidamente y el factorial de 8 ya es demasiado
grande como para que "quepa" en un número estandar de Inform, así
que llamar a Factorial(8) daría una respuesta
errónea)2.
La rutina Factorial se llama aquí a sí misma: esto se llama
"recursión". La ejecución alcanza una "profundidad de siete
rutinas" antes de empezar a "emerger". Cada una de estas copias de
Factorial se ejecuta con su propio valor privado de la variable n.
El truco de la recursión puede ser peligroso. Si uno llama a la rutina
[Desastre; return Desastre(); ]; |
entonces, a pesar de la tranquilizadora presencia de la
palabra return, la ejecución continúa infinitamente, incapaz de
acabar evaluando el valor de retorno. La primera llamada a Desastre
necesita hacer una segunda antes de que pueda terminar; la segunda
necesita hacer una tercera; y así sucesivamente. Esto es un ejemplo de
error de programación que será desastroso cuando el programa se
ejecute, aunque no causará ningún error cuando el fuente se compile.
(Se ha probado que es imposible construir un compilador capaz de
detectar este tipo general de error. Inform ni siquiera lo intenta).
Una característica común de todas las estructuras de control es que
en lugar de dar simplemente una <instrucción>, uno puede
dar una lista de instrucciones agrupadas en una sola unidad llamada
"bloque de código". Tal agrupamiento comienza con una llave
abierta `{' y termina con una llave cerrada `}'. Por ejemplo,
if (alfa > 5)
{ print "El cuadrado de alfa es ";
print alfa*alfa;
print ".^";
}
|
Si alfa es 3, no se imprime nada; si alfa es 9, se imprime
El cuadrado de alfa es 81. |
(Como viene siendo habitual, el formateo es una cuestión de
convención; normalmente se escriben los bloques de código con un
indentado de varios espacios). En algunos aspectos, los bloques de
código son como las rutinas, y al principio puede parecer
inconsistente el escribir las rutinas entre corchetes (`[' y `]')
y los bloques de código entre llaves (`{' y `}'). Sin embargo, los
bloques de código no pueden tener variables privadas propias y no
devuelven valores, y es posible que la ejecución se salga fuera de los
bloques de código, o que salte de uno a otro, cosa que no puede
suceder con las rutinas.
Una instrucción if puede tener opcionalmente la forma
if (<condición>) <instrucción1> else <instrucción2>
de tal modo que la <instrucción1> se ejecutará si la condición es verdadera, y la <instrucción2> si es falsa. Por ejemplo,
if (alfa == 5) print "Cinco."; else print "No cinco."; |
Nótese que la condición sólo es evaluada una vez. La instrucción
if (alfa == 5)
{
print "Cinco.";
alfa = 10;
}
else print "No cinco.";
|
no puede imprimir nunca "Cinco." y después "No cinco.".
La cláusula else tiene una pega: el problema de los "elses
colgantes".
if (alfa == 1)
if (beta == 2)
print "Claramente si alfa=1 y beta=2.^";
else
print "Ambiguo.^";
|
es ambiguo en cuanto a qué instrucción if acompaña el
else. La respuesta (en Inform 6, aunque esto ha cambiado desde otras
versiones anteriores del lenguaje) es que un else siempre acompaña a
su if más cercano, a menos que haya llaves que indiquen lo
contrario. Luego el else de arriba está emparejado con la condición
beta, no con la condición alfa.
En cualquier caso, es mucho más seguro usar llaves para expresar lo que se quiere decir, como en:
if (alfa == 1)
{
if (beta == 2)
print "Claramente si alfa=1 y beta=2.^";
else
print "Claramente si alfa=1 pero beta no es 2.^";
}
|
El constructo if...else... es ideal en los casos en que la ejecución
debe elegir dos posibles "caminos", como si fueran señales
ferroviarias, pero resulta incómodo cuando hay más de dos posibles
resultados. Continuando con la analogía, el constructo switch es
como la tornavía de un ferrocarril.
print "El tren del andén 1 va a ";
switch(DestinoEnAnden(1))
{ 1: print "Madrid.";
2: print "Ourense.";
3: print "A Coruña.";
}
|
Cada posible valor debe ser una constante, así que
switch(alfa)
{ beta: print "¡Las variables alfa y beta son iguales!";
}
|
es ilegal.
Se pueden especificar cualquier número de opciones, y los valores pueden agruparse en una sola opción. Por ejemplo,
print "La misión STS-", num, " se voló en el transbordador espacial";
switch(num)
{ 1 to 5, 9: print " Columbia.";
6 to 8: print " Challenger.";
10 to 25: if (num == 12) print " Discovery";
print ", pero se le dio el número de vuelo 51-B.";
default: print ".";
}
|
imprimirá una frase verdadera (mientras num esté entre 1
y, en el momento en que esto se escribe, 78), aunque puede que
incompleta. La cláusula default se ejecuta si la expresión original
no es igual a ninguno de los otros valores, y siempre debe ponerse al
final, si es que se pone. En este caso, significa que si num es 62,
por ejemplo, entonces se imprimirá
La misión STS-62 se voló en el transbordador espacial. |
Nótese que cada una de las cláusulas es por sí misma un bloque de
código y no necesita llaves { y } alrededor de ella para
delimitarla del resto de la rutina: esta abreviación hace que la
instrucción switch sea mucho más legible3
Las otras cuatro estructuras de control de Inform son todas
"bucles", esto es, formas de repetir la ejecución de uns instrucción
dada (o bloque de código). La explicación de una de ellas,
(objectloop), se retrasará hasta la sección *.
Las dos formas básicas de bucle son while y do...until:
while (<condición>) <instrucción>
do <instrucción> until (<condición>)
La primera chequea repetidamente la condición y, siempre que sea verdadera, ejecuta la instrucción. (Si la condición no es verdadera la primera vez que se chequea, la instrucción nunca se ejecuta). Por ejemplo:
[ RaizCuadrada n; x = n; while (x*x >n) x=x-1; return x; ]; |
es un método (bastante habitual) de encontrar raíces cuadradas. (Si se
llama a RaizCuadrada(200), entonces x va pasando por los valores
200, 199, ..., 14, momento en el cual x*x <= n, dado que
14×14=196.)
El bucle do...until repite las intrucciones dadas hasta que
la condición es encontrada verdadera. (Pero, ya que la condición no se
evalúa hasta despuñes de haber ejecutado la instrucción, la
instrucción se ejecutará como mínimo una vez).
Un tipo particualar de bucle while se usa tan a menudo que hay una
abreviación para él, llamada for. Por ejemplo,
contador = 1;
while (contador <= 10)
{ print contador, " ";
contadador++;
}
|
produce el resultado
1 2 3 4 5 6 7 8 9 10 |
(Hay que recordar que contador++ añade 1 a la variable contador).
Los lenguajes como BASIC hacen un uso extensivo de este tipo de bucle.
Por ejemplo, en BBC BASIC, el bucle anterior se escribiría
FOR contador = 1 TO 10
PRINT contador;" ";
NEXT
|
NEXT es una palabra que (de forma algo inadecuada) significa "el
bloque de código termina aquí", y es por tanto equivalente a la }
de Inform. Todo lo anterior se usa para significar "para valores del
contador que vayan de 1 a 10, haz...", de ahí la elección de la
palabra FOR
Inform (al igual que el lenguaje C) usa una sintaxis más flexible que
esta, pero que continúa llamándose for. Puede producir cualquier
bucle de la forma
<comienzo>
while (<condición>)
{ ...
<actualización>
}
donde <comienzo> y <actualización> son instrucciones de
asignación. La notación para hacer lo mismo con for
sería4:
for (<comienzo> : <condición> : <actualización>) ...
Por ejemplo, el bucle descrito más arriba se consigue con
for (contador=1 : contador<=10 : contador++)
print contador, " ";
|
Obsérvese que si la condición es falsa la primera vez, el bucle nunca se ejecuta. Por ejemplo,
for (contador=1 : contador<0 : contador++)
print "Plátano";
|
no imprime nada.
![]() |
En este punto cabe mencionar que en Inform se pueden combinar varias
asignaciones en una sola, separándolas con comas. Por ejemplo,
(tres asignaciones separadas por comas) es una sola
instrucción. Esto nunca resulta útil en el código normal, ya que las
asignaciones pueden separarse por punto y coma como es habitual. Sin
embargo, sí es útil dentro de bucles
produce el resultado "1 5, 2 4, 3 3 , 4 2, 5 1,". |
Cualquiera de las tres partes de una instrucción for puede omitirse.
Si se omite la condición, se asume que siempre será verdadera, o sea,
no hay ningún chequeo que realizar para ver si el bucle debería
terminar, y de esta forma el bucle continúa infinitamente.
A simple vista, los siguientes bucles se repiten todos para siempre:
while (true) <instrucción>
do <instrucción> until (false)
for (::) <instrucción>
Pero siempre hay una salida. Una forma consiste en colocar un return
dentro del bloque <instrucción>. Otra es saltar a una
etiqueta fuera del bucle (jump, que es la instrucción de salto, se
explicará en la sección *). Pero lo más elegante es usar la
instrucción break, que hace que la ejecución "se salga" del bucle
o de una instrucción switch, y continúe después de la llave que
delimita el bloque: puede considerarse como un "final prematuro".
Todas estas formas son totalmente "seguras", y no hay ningún peligro
en dejar un bucle a medio hacer.
La otra instrucció simple utilizada dentro de los bucles es
continue. Esta causa que la iteración actual cese inmediatamente,
pero no termina el bucle entero. En lugar de eso, se salta de nuevo al
principio del bucle, para comenzar una iteración nueva, dejando sin
ejecutar lo que había después del continue. Por ejemplo,
for (i=1: i<=5: i++)
{ if (i==3) continue;
print i, " ";
}
|
imprimirá "1 2 4 5" (saltándose el 3).
La rutina EjecutaPuzzle es un ejemplo interesante de bucle que,
aunque aparentemente bastante simple, contiene una trampa para los
incautos:
[ EjecutaPuzzle n contador;
do
{ print n, " ";
n = SiguienteNumero(n);
contador++;
}
until (n==1);
print "1^(hemos necesitado ", contador, "pasos para llegar al 1)^";
];
[SiguienteNumero n;
if (n%2 == 0) return n/2; ! Si n es par, divídelo a la mitad
return 3*n + 1; ! Si n is impar, tripícalo y añádele 1
];
|
La llamada EjecutaPuzzle(10), por ejemplo, produce el siguiente
resultado:
10 5 16 8 4 2 1 (hemos necesitado 6 pasos para llegar al 1) |
El código fuente asume que, sin importar cuál es el valor inicial de n, acabaremos por llegar a 1 con el suficiente número de iteraciones. Si esto no sucediera, el programa quedaría bloqueado por un bucle infinito, imprimiendo números infinitamente.
La rutina es aparentemente muy simple, así que parece muy razonable pensar que, si nos ponemos a ello, deberíamos ser capaces de decidir si es o no "segura" de usar (o sea, que podríamos garantizar que terminará siempre, o no).
Y aún así, nadie sabe si esta rutina es "segura". La hipótesis de
que cualquier valor de n acabará finalmente por llegar al valor 1
tiene al menos cincuenta años de antigüedad, pero aún no ha sido
probada, habiendo resistido todos los "ataques" matemáticos.
(Alarmantemente, a EjecutaPuzzle(27) le lleva 111 iteraciones
alcanzar el valor de 1.)
Quedan todavía cuatro instrucciones que controlan el flujo de la
ejecución. quit finaliza el programa inmediatamente (como si se
hubiera producido un valor de retorno en la rutina Main). Esta
medida tan drástica debería ser reservada para aquellos puntos de
un programa en los que se han detectado errores tan tremendos que
no tiene sentido seguir con ellos. Mejor aún sería no usarla
nunca5.
La instrucción jump transfiere la ejecución a algún otro lugar
dentro de la misma rutina. El lugar en cuestión es identificado con
un "nombre" que el programador decide. (Algunos lenguajes de
programación la llaman goto. Esta instrucción se puede usar y se
ha usado de formas muy feas y poco elegantes, por lo que la
construcción en sí misma fue acusada hace tiempo de ser una
vulgaridad informática que conduce al pecado a los que la usan. Un
buen uso de las estructuras de control evitará casi siempre la
necesidad de usar la instrucción jump y resultará en programas más
legibles. Pero el pecado es universal...).
Para usar jump, se necesita una notación para marcar algunas
partes determinadas del código fuente. Tales marcadores reciben el
nombre de "etiquetas". Por ejemplo:
[ Main i; i=1; .Marcador; print "He imprimido esto ", i++, " veces.^"; jump Marcador; ]; |
Este programa tiene una etiqueta, Marcador. Una instrucción que
consista sólo en un punto y luego un identificador significa "pon una
etiqueta aquí y llámala así".
![]() ![]() |
Los programas en Inform tienen la habilidad de guardar
"instantáneas" de su propio estado y de devolverse a sí mismos a
ese estado anterior. Esta instantánea incluye valores de variables,
el punto donde se está ejecutando el código, etc. Del mismo modo que
no podemos saber si el universo tiene solo seis mil años de
antigüedad, como afirman los creacionistas, sino que ha sido creado
hace poco, junto con un buen montón de fósiles cuidadosamente
falsificados por Dios para hacernos creer que es más antiguo, un
programa en Inform no puede saber si ha estado ejecutándose todo el
rato o si ha sido reiniciado recientemente. Las instrucciones
necesarias son save y restore:
Este es un raro ejemplo de una característica de Inform que puede
depender del "estado de salud" de la máquina en la que se ejecute:
por ejemplo, si todo el espacio en disco está lleno, |
Cuando se imprime un texto, normalmente cada caracter se imprime
exactamente como se especificó en el código fuente. Hay cuatro
caracteres, sin embargo, que tienen significados especiales. Como
ya se ha explicado, ^ significa "imprime un retorno de
carro". El caracter ~, que significa "imprime unas
comillas", es necesario dado que las comillas normales
terminarían la cadena de texto a imprimir. Así,
"~Mira~, dice Pedro. ~Los calcetines pueden saltar.~^Juana está de acuerdo." |
se imprime como
"Mira", dice Pedro. "Los calcetines pueden saltar." Juana está de acuerdo. |
El tercer caracter especial que queda es @, que se usa para los
caracteres acentuados y otros efectos inusuales, como se describe más
abajo6.
Finalmente, \ se reservaba para indicar que la cadena no termina en
esta línea de código, sino que continúa en la siguiente. Esto ya no es
necesario en las nuevas versiones de Inform, pero se mantiene para que
los programas antiguos todavía funcionen. Si deseas imprimir los
símbolos ~, ^, @ o \, sigue leyendo.
El texto entrecomillado puede ocupar más de una línea. Cuando Inform lee una instrucción como esta
print "Muchos dicen mal de mí,
y yo digo mal de muchos;
mi decir es más valiente,
por ser tantos y ser uno.";
|
los finales de línea son reemplazados por un espacio (y
todos los espacios que hay al principio de la siguiente línea,
son ignorados). Por tanto, el texto que imprimiría sería:
"Muchos dicen mal de mí, y yo digo mal de muchos; mi decir es
más valiente, por ser tantos y ser uno." (Hay una excepción:
si el último carácter de la línea es ^, entonces no se
sustituye el salto de línea por un espacio, sino que se ignora
sin más. La siguiente línea impresa comenzaría con el primer
carácter distinto de blanco que hay en la siguiente línea de la
cadena).
Hasta ahora, para imprimir cosas sólo hemos usado la orden
print, tanto para imprimir números como cadenas (esto es, trozos de
texto encerrados entre comillas dobles "). Puesto que Inform es
básicamente un lenguaje para escribir aventuras conversacionales, lo
suyo es el texto, y proporciona unas cuantas utilidades más para
imprimir.
new_line
es un comando que simplemente imprime una línea nueva (tambíen conocida como retorno de carro, como si hubieramos empujado la palanca de una máquina de escribir mecánica, para moverla de nuevo al margen izquierdo y hacerla avanzar una línea). Es equivalente a
print "^"
pero es una abreviatura cómoda. De forma análoga,
spaces <número>
imprime una secuencia de espacios, donde <número> representa la cantidad de espacios a imprimir.
inversion
imprime el número de versión del compilador Inform que se ha usado para compilar el programa (por ejemplo, podría imprimir "6.15").
box <cadena_1> ... <cadena_n>
muestra una caja en video inverso, centrada en la pantalla, que contiene cada una de las cadenas en una línea separada. Suele usarse para hacer aparecer citas literarias. Por ejemplo:
box "Passio domini nostri" "Jesu Christi Secundum" "Joannem"; |
sacaría en un rectángulo de vídeo inverso:
Passio domini nostri Jesu Christi Secundum Joannem |
(el comienzo del libreto de Arvo Pärts "La Pasión de San Juan").
Normalmente el texto se muestra en un tipo de letra "normal" (o "Roman"). El aspecto exacto que tendrá, dependerá de la máquina en que se ejecute. En muchas máquinas (por ejemplo, al ejecutarse bajo WinFrotz o IznoguZ), se usará un tipo de letra "proporcional", también llamado "de ancho variable", como la letra del manual que estás leyendo. En este tipo de letra una "w" es más ancha que una "i". Este texto es mucho más cómodo de leer para el ojo, pero hace muy difícil imprimir diagramas construidos a base de texto. Por ejemplo, la instrucción:
print "+-----------+
^+ Hola +
^+-----------+^";
|
imprimirá algo bastante irregular, si en el tipo de letra
usado los caracteres "-", "+" y " " (espacio) no
tienen exactamente el mismo ancho. Pero a veces querrás
hacer un diagrama así (para representar un mapa esquemático,
por ejemplo, o imprimir una tabla). Por ello existe la
instrucción font:
font on
font off
La instrucción font off cambia el tipo de letra a otro que tenga
ancho fijo (como por ejemplo el tipo de letra courier); la
instrucción font on vuelve al tipo de letra original. Aparte de
esto, hay unos pocos tipos de letra más:
style roman
cambia a un tipo de letra "Roman" recto (el tipo por defecto). También hay:
style bold
style underline
style reverse
Estos estilos hacen que las letras salgan con diferente aspecto en
pantalla, aunque el aspecto concreto depende del intérprete y del
sistema operativo que estés usando. El estilo bold debe sacar un
tipo de letra "destacado" de alguna forma. En intérpretes que tengan
acceso a diferentes tipos de letra (como WinFrotz, por ejemplo),
usarán un tipo en negrita para esto. En otros intérpretes sin acceso a
tipos de letra (como DOS Frotz), el texto saldrá de otro color más
brillante.
El estilo underline es para remarcar el texto de alguna forma. Según
el intérprete, puede aparecer subrayado, o bien en cursiva, o bien
simplemente de otro color más llamativo.
Finalmente, reverse indica que se intercambien el color de fondo y
el de la letra, por ejemplo, letras azules sobre fondo amarillo, si el
texto normal aparece en letras amarillas sobre fondo azul.
Inform puede usarse para hablar idiomas distintos del inglés: hay
prueba de ello en italiano, alemán, francés y español. Para estos
idiomas es necesario incorporar letras acentuadas, y para ello se usa
el carácter "escape" @. En las últimas versiones del compilador (a
partir de la 6.15), los acentos se pueden introducir también
"directamente", siempre que se use un editor basado en la
codificación ISO-Latin17.
Si, por cualquier razón, no puedes usar letras acentuadas en tu
ordenador, aún así puedes escribir juegos que usen acentos en su
salida, gracias al caracter de escape @. Detrás de @ pones un
símbolo que indica el tipo de acento deseado, y seguidamente la letra
que recibirá el acento. Estas son las opciones:
@^ | pone un circunflejo sobre la letra siguiente: a,e,i,o,u,A,E,I,O,U |
@' | pone un acento agudo en la letra siguiente: a,e,i,o,u,y,A,E,I,O,U,Y |
@' | pone un acento grave en la letra siguiente: a,e,i,o,u,A,E,I,O,U |
@: | pone una diéresis en la letra siguiente: a,e,i,o,u,A,E,I,O,U |
@c | pone una cedilla en la letra siguiente: c, C |
@~ | pone una virgulilla en la letra siguiente: a,n,o,A,N,O |
@\ | pone una barra cruzando la letra siguiente: o,O |
@o | pone un anillo sobre la letra siguiente: a,A |
Además de los acentos, hay otras combinaciones para producir símbolos especiales:
@ss | La ß alemana |
@<< | Comillas españolas |
@>> | |
@ae | ligaduras |
@AE | |
@oe | |
@OE | |
@th | Acentos de islandia |
@et | |
@Th | |
@Et | |
@LL | símbolo de la libra |
@!! | Abrir admiración española |
@?? | Abrir interrogación española |
Por ejemplo:
print "Les @oeuvres d'@Aesop en fran@ccais, mon @'el@`eve!"; print "Na@:ive readers of the New Yorker will re@:elect Mr Clinton."; print "Carl Gau@ss demostr@'o el Teorema Fundamental del @'Algebra."; |
Si tu teclado puede producir esos símbolos, entonces no necesitas usar estos molestos códigos de escape, sino que puedes usar los símbolos directamente. Así, por ejemplo:
print "Les @oeuvres d'@Aesop en français, mon élève!"; print "Naïve readers of the New Yorker will reëlect Mr Clinton."; print "Carl Gauß demostró el Teorema Fundamental del Álgebra."; |
![]() |
El ecape @ tiene otros dos usos. Uno de ellos sirve para evitar el
problema de que es imposible imprimir un "@". Dos @ seguidas y
un número detrás, representa al carácter cuyo código es ese
número. Los casos más útiles son:
|
![]() ![]() |
El segundo uso es mucho más oscuro, y bastante poco útil. Inform
mantiene una lista con 32 pseudo-variables, en las que puede
almacenar texto. Estas variables no tienen nombre, sino simplemente
un número de 0 a 31 para indentificarlas.
Los valores de esas cadenas pueden asignarse con la instrucción
asignaría el texto "seta venenosa" a la cadena número 0. Hay razones técnicas por las que la asignación debe utilizar un texto literal, y no el valor almacenado en otra variable. |
Finalmente, es hora de hablar de print. Hay dos formas: print y
print_ret. La única diferencia es que la segunda forma imprime un
retorno de carro al final del texto y causa un retorno de la rutina
que se está ejecutando en ese momento, retornando el valor true. Por
tanto print_ret debe leerse como "imprime y después retorna". La
instrucción
print_ret "Ya está bien."; |
es equivalente a
print "Ya está bien.^"; rtrue; |
De hecho, aún puede abreviarse más, y escribirse sin poner
siquiera print_ret:
"Ya está bien."; |
Aunque los recién llegados a Inform a menudo se lían con el hecho de que esta instrucción de aspecto inocente, cause en realidad unr retorno de la rutina, la verdad es que es una abreviatura muy útil que compensa realmente cuando se escriben aventuras conversacionales. Observa que al compilar el progrma:
[ Main; "Hola, vamos a imprimir un número..."; print 45*764; ]; |
Inform producirá el siguiente aviso:
line 3: Warning: This statement can never be reached. > print 45*764; |
debido a que la primera cadena que hay dentro de Main es
en realidad un print_ret abreviado, de modo que el texto es
impreso, después se imprime un retorno de carro, e inmediatamente se
retorna de la función Main. Como el mensaje de aviso nos indica, no
hay forma de que la línea 3 pueda ser ejecutada.
¿Qué podemos imprimir? La respuesta es: "una lista de términos
separados por comas". Por ejemplo el print:
print "El valor es ", valor, "."; |
contiene tres términos. Un término puede ser una de las cosas siguientes:
| <una cantidad numérica> | Se imprime como un número en decimal, con signo |
| <texto entre comillas> | Se imprime el texto |
(<regla>) <cantidad> | La cantidad se imprime según una cierta regla |
Inform proporciona una serie de reglas preparadas, y también permite que el programador cree reglas nuevas. Las reglas más importantes son:
(char) | imprime el carácter cuyo código es <cantidad> |
(string) | imprime el texto representado por <cantidad> |
(address) | imprime la palabra que hay en esa dirección |
La última se usa raramente, y sólo para imprimir palabras del diccionario del juego.
![]() |
La forma print (string) ... necesita una pequeña explicación. El
programa
imprime el texto "¡Hola!". Mientras que
lo que imprime es un número misterioso. Esto se debe a que internamente las cadenas de texto son representadas por números8. |
Las restantes reglas proporcionadas por el lenguaje son para usar juntocon la Librería, y se detallan en la capítulo sobre descripción de objetos. Resumiendo brevemente:
(the) | Imprime un artículo definido y el nombre del objeto |
(The) | Lo mismo, pero con la inicial en mayúsculas |
(name) | Lo mismo, pero sin artículo |
(a) | Lo mismo, pero con un artículo indefinido |
(number) | Escribe el número con palabras |
(property) | (para depuración) imprime el nombre de esa propiedad |
(object) | (para depuración) imprime el nombre interno del objeto |
Observa que (the) en minúsculas es diferente a (The) en
mayúsculas. ¡Esto es bastante inusual!. Los nombres de directivas, y
de variables pueden mezclar mayúsculas y minúsculas, porque no tiene
efecto. RaNa significa lo mismo que rana. En cambio las palabras
reservadas del Inform como print o (name) tienen que estar en
minúsculas (con la excepción de (The)).
Para crear una regla nueva, simplemente escribe una rutina con ese
nombre. La regla ya puede ser usada en un print poniéndola entre
paréntesis.
![]() |
Para hacer más fácil el trabajo al programador español, la librería
InformATE define las reglas (el), (un), etc... Sin embargo,
estas reglas no son parte de Inform, sino que están definidas en la
librería. Debido a ello, existen algunas limitaciones:
|
Gracias a las dos rutinas siguientes, podemos imprimir un número en forma hexadecimal sin signo. Se usarían así:
print (hex) 16339; |
lo que producirá la salida "3fd3". Las funciones serían estas:
[ hex x y; y = (x & $ff00) / $100; x = x & $ff; print (hdigit) y/$10, (hdigit) y, (hdigit) x/$10, (hdigit) x; ]; [ hdigit x; x = x % $10; if (x<10) print x; else print (char) 'a'+x-10; ]; |
Una vez que se han definido estas rutinas, (hex) y (hdigit) pueden
usarse en cualquier lugar del programa como nuevas reglas para
print.
Inform proporciona un pequeño conjunto de funciones pre-programadas
internamente pero que se usan en la misma forma que las funciones
programadas por el usuario. Todas ellas, excepto 2, son para el manejo
de objetos y se tratan en la
sección sobre objetos. Explicaremos aquí las otras
dos: random e indirect.
random tiene dos formas. La primera:
random(N)
devuelve un número elegido al azar entre 1, 2, ...N. La cantidad N tiene que ser siempre positiva, y menor de 32767 para que la rutina funcione correctamente. La segunda forma:
random(cantidad1, cantidad2, ...)
devuelve una de esas cantidades, elegida al azar de forma uniforme. Por tanto la instrucción
print (string) random("rojo", "verde", "azul", "amarillo", "naranja");
|
imprimirá aleatoriamente uno de esos colores, todos ellos con la misma probabilidad de ser elegidos. Análogamente
print random(13,17); |
tiene un 50% de probabilidades de imprimir 13, y otro 50% de imprimir 17.
![]() ![]() |
La otra función interna es indirect, que tiene un uso bastante
avanzado. La instrucción:
indirect(funcion, arg1, arg2, ...)
llama a esa funcíón pasándole esos argumentos. Por tanto equivale a:
funcion(arg1, arg2, ...)
pero tiene la virtud adicional de que
tiene un 50% de probabilidades de llamar a
|
![]() ![]() |
El programador de InformATE raramente necesitará leer datos del
teclado en la práctica, ya que en todas las situaciones del juego las
rutinas de parsing de la librería se ocuparán de ello. Sin
embargo, por completar esta sección, se trata aquí la instrucción
La sintaxis es
donde la <rutina> es opcional. Si se proporciona una, se la llamará justo antes de que se efectúe la lectura del teclado. Es habitual poner ahi una rutina que actualice la "linea de estado" del juego (las primeras líneas de la pantalla). Lo que hace esa instrucción es leer una línea de texto (es decir, espera hasta que el usuario haya terminado de teclear una línea y haya pulsado Intro), copia el texto que el usuario ha escrito en el array <array de texto> y después intenta comprender lo que se ha escrito (mirando si las palabras individuales están en el diccionario del juego), dejando los resultados de esta "comprensión" en el array <buffer de parsing>. Antes de ejecutar esta instrucción, el array de texto ha tenido que
ser inicializado, indicando el máximo número de letras que se van a
aceptar. Este número debe estar almacenado en el elemento 0 del
<array de texto>. Una vez que
leerá una línea de 60 caracteres como máximo, y después la
imprimirá en pantalla. (El array Observa que en el ejemplo anterior no hemos especificado buffer de
parsing (hemos puesto 0 en su lugar. Esto causa que |
![]() | ![]() | ![]() | El lenguaje de las Rutinas |