Hacía mucho tiempo que no me acercaba a TIS-100, y hace un rato, en un hueco, pensé en entrar en alguno de los puzzles que no había conseguido hacer antes, lo que me llevó a este multiplicador de señal. Y parece que quizá, después de años luchando con python, con juegos como este, con pseudo código, al final es posible que mi cerebro esté aprendiendo de algún modo. De un problema al que hace algo más de un año no conseguía encontrar ni el comienzo de una solución, aunque fuera remoto, he pasado a separar rapidamente un contador, un generador de números y un sumador.
Es una tontería y no tiene ningún misterio, pero a mí me hace muchísima ilusión haber sido capaz de plantearlo y resolverlo. Los resultados no son espectaculares pero a mí, desde luego, me bastan.
El nodo de arriba a la izquierda es un contador del primer factor. Comprueba que no es cero, lo manda a la derecha, le resta uno y vuelve a empezar. Cuando llega a cero manda un cero a la derecha y toma un número nuevo de arriba. Tal y como he decidido hacerlo este factor no puede ser nunca cero, porque es el que indica las veces que tiene que sumarse el otro. Podría ser perfectamente al revés, claro.
# CUENTA ATRAS
MOV UP ACC # mueve arriba a la memoria ACC
INI: # etiqueta de salida de INI
MOV ACC RIGHT # mueve la memoría ACC a la derecha
JEZ OUT # si ACC es cero salta a OUT
SUB 1 # réstale uno a ACC
JMP INI # salta a INI
OUT: # nada (vuelta al inicio)
El de arriba a la derecha almacena el otro factor, verifica que lo que ha recibido a la izquierda no es cero y manda el número hacia abajo, y vuelve a hacerlo una y otra vez hasta que la izquierda le manda un cero. Cuando es un cero manda abajo un -1. El primer factor no puede ser cero pero este sí, y en caso de serlo mandará ceros hacia abajo hasta encontrarse con un cero en el nodo izquierdo, así que la señal de aviso de cambio no puede ser otro cero. En el ejercicio sólo se multiplican números positivos.
# ENVIA N ABAJO
MOV UP ACC # mueve arriba a ACC
INI: SAV # etiqueta de salida de INI, guarda ACC en BAK
MOV LEFT ACC # mueve la izquierda a ACC
JEZ OUT # si ACC es cero vete a OUT
SWP # intercambia BAK con ACC
MOV ACC DOWN # mueve ACC abajo
JMP INI # salta a ini
OUT: MOV -1 DOWN # salida de OUT, mueve -1 abajo
El de abajo a la izquierda es sólo un buffer que seguro que podría quitar, simplemente recoge lo que tiene a la derecha y lo vuelve a colocar disponible para el nodo de la derecha.
# ALMACEN
MOV RIGHT RIGHT # mueve derecha a la derecha
El de abajo a la derecha va a sumar los números que manda el de arriba hasta que reciba la señal de empezar de cero, utilizando el nodo de la izquierda como almacén, y en ese momento manda el resultado final de la suma abajo. Este nodo (bueno, todos, pero este especialmente) seguro que se puede hacer de un modo mejor. Tienes dos sitios donde almacenar un número, ACC y BAK, pero la única forma de interactuar con BAK es ejecutar el comando SAV, que copia ACC en ella, y el comando SWP, que intercambia los valores de ambas, por eso tengo que utilizar LEFT. Coloco un cero en left al empezar para no tener que dividir el código entre el primer número de una secuencia y los demás.
# SUMA NUMEROS
MOV 0 LEFT # mueve cero a la izquierda
INI:MOV UP ACC # destino de INI, mueve arriba a ACC
JLZ OUT # si ACC es menor que cero vete a OUT
ADD LEFT # suma izquierda a ACC
MOV ACC LEFT # mueve ACC a la izquierda
JMP INI # salta a INI
OUT:MOV LEFT DOWN # mueve izquierda abajo.