Por una conjunción copulativa; viajando en el tiempo

En lo que va de mes he trabajado en dos de mis proyectos: el módulo de redifusión en formato Atom 1.0 para Simplilo; y el formato de datos de La legionela del pisto.

Es un ejercicio mental que me gusta: repartir mi tiempo entre proyectos principalmente «útiles» y proyectos principalmente «deliciosos», como es el caso de los dos mencionados. Me gusta pasar de un lenguaje complejo, potente, actual y muy popular como PHP, que se ejecuta en un servidor de páginas hipertextuales, a un lenguaje sencillo, limitado, «antiguo» y olvidado (pero encantadoramente creativo y cómodo) como Beta BASIC, que se ejecuta en una ZX Spectrum. Es un ejercicio que me ayuda a no perder la perspectiva, a no olvidar los orígenes.

Trabajar en 2010 con una ZX Spectrum 128, una computadora de 1985, aunque sea por medio de un emulador como Fuse, es hacer un delicioso viaje en el tiempo, a una época en que un octeto de más o de menos tenía toda la importancia de sus ocho bitios, ninguno menospreciable; una época en que la limitación de recursos no era sentida como tal; una época en que cualquier descubrimiento era un nuevo mundo al alcance de la mano. Ahora los nuevos mundos informáticos me resultan agobiantes por demasiados; suelen ser complejísimos y casi siempre son inabarcables por una sola persona. Por eso me gusta viajar en el tiempo y pasear sin prisa por aquella otra época, para mí entrañable.

Siempre me ha gustado leer código fuente. Pero a menudo leo código de programadores expertos escrito de cualquier forma, tanto en su aspecto como en su funcionamiento. He llegado a la conclusión de que la potencia de las computadoras actuales induce a la pereza, a no afinar los algoritmos, a no ahorrar memoria, a no ahorrar tiempo de proceso, a no fijarse en los detalles. A veces me pregunto qué podría lograrse sumando la potencia de las máquinas y lenguajes actuales con el genio y la creatividad de tantos programadores de hace un cuarto de siglo, que dieron vida a muchas pequeñas maravillas en unas pocas docenas de kibioctetos de memoria y con tres y pico megaciclos de procesador.

Pensaba en todo ello mientras estos días trabajaba en varios algoritmos para La legionela del pisto. Por ejemplo, el dilema de una simple conjunción copulativa:

Es un pequeño pero elegante signo de inteligencia, por parte del programa, imprimir una simple conjunción «y» ante el último elemento de una lista. Entre Hay salidas hacia norte, sur, oeste. y Hay salidas hacia norte, sur y oeste. hay un pequeño mundo algorítmico. En el primer caso, distinguir cuándo hay que imprimir coma y cuándo punto es muy fácil (coma ante cada elemento, empezando con el segundo, y punto al terminar la lista); pero, en el segundo caso, saber cuándo imprimir la conjunción «y» no es tan fácil: es necesario saber por anticipado cuántos elementos tiene la lista. Esto sería trivial en un lenguaje moderno (incluso interpretado, como PHP), ejecutándose en una computadora actual; pero es un cierto desafío en Beta BASIC en una ZX Spectrum. Hacerlo de una u otra manera puede significar una diferencia significativa de tiempo de ejecución.

Muestro a continuación un par de ejemplos del código de La legionela del pisto que ilustran el problema de la conjunción copulativa. Son versiones ya descartadas, porque desde que las escribí he cambiado el formato de las matrices de datos, pero eso no afecta al fondo de la cuestión.

La versión sin conjunción copulativa simplemente construye una lista de salidas y la imprime o no según tenga algún elemento o esté vacía; también tiene en cuenta el número de elementos hallados para imprimir correctamente el plural de la palabra «salidas»:

1770 DEF PROC action_SALIDAS_fast
1780   LOCAL i,exit,exits,t$
       LET exits=0,t$=""
1790   FOR i=fNorth TO fDown
1800     LET exit=!ent#(location,i),exit=exit-lockedDoor*(exit>lockedDoor)
         IF exit THEN LET d$=!ent$(i, TO nameLength)
           trim d$
           LET d$=(", " AND exits)+d$,exits=exits+1
           COPY d$ TO t$
1810   NEXT i
1820   IF NOT exits THEN tell "No hay salidas."
       ELSE
         tell "Hay salida"+("s" AND exits>1)+" hacia: "+t$+"."
1830 END PROC

La versión con conjunción copulativa debe hacer un recuento previo de los elementos de la lista, para saber cuál será el último a la hora de imprimirlos:

1670 DEF PROC action_SALIDAS_slow
1680   LOCAL i,exit,exits,s$,t$,listed,d$
       LET exits=0,listed=0
1690   FOR i=fNorth TO fDown
         LET exit=!ent#(location,i),exit=exit-lockedDoor*(exit>lockedDoor),exits=exits+(exit<>0)
       NEXT i
1700   IF NOT exits THEN tell "No hay salidas."
         GO TO 1760
1710   LET t$="Hay salida"+("s" AND exits>1)+" hacia "
1720   FOR i=fNorth TO fDown
1730     LET exit=!ent#(location,i),exit=exit-lockedDoor*(exit>lockedDoor)
         IF exit AND exit<lockedDoor THEN LET d$=!ent$(i, TO nameLength)
           trim d$
           LET d$=(", " AND (listed AND (listed<>(exits-1))))+(" y " AND (listed=(exits-1) AND listed))+d$,listed=listed+1
           COPY d$ TO t$
1740   NEXT i
1750   tell t$+"."
1760 END PROC

Un método más rápido que utilicé después consiste en aprovechar el primer recuento de elementos para conservar éstos en un formato intermedio y así acelerar el segundo bucle, el que construye el texto final a imprimir.

Durante los viajes en el tiempo, hasta una simple conjunción copulativa tiene su importancia y requiere cuidado y atención.

Páginas relacionadas

Alien-B
Juego de invasores escrito en Beta BASIC para ZX Spectrum 128.
De los pixeles a las palabras; una palabra tras otra
Apuntes dispersos de un (retro)programador. 29 de noviembre de 2010.
La legionela del pisto
Juego de aventuras de texto para ZX Spectrum 128, escrito en Beta BASIC 4.0+D con formato BBim.