aquí introducimos el uso del dispositivo controlador en la computadora uxn varvara: esto nos permitirá añadir interactividad a nuestros programas y empezar a discutir el flujo de control en uxntal.
codificar los estados de los botones de esta manera nos permite presionar y leer muchas de estas teclas al mismo tiempo.
## el byte de la tecla
el byte de la tecla almacena el código ascii de la tecla del teclado que se está pulsando en ese momento.
la diferencia entre el byte 'de la tecla' y el byte 'de botón' puede ser confusa, especialmente cuando se ejecuta varvara desde uxnemu donde los botones están en el mismo lugar que las teclas.
una posible manera de recordar podría ser pensar en el byte 'botón' como refiriéndose a un controlador de gamepad.
## el vector del controlador
en el contexto de la programación de uxn, un vector se refiere a una dirección en la memoria principal donde se asigna a uxn para que salte cuando ocurra un evento específico.
en el caso del vector controlador, este evento específico consiste en cada vez que se pulsa o suelta una tecla.
en otras palabras: uxn saltará a la dirección asignada como vector controlador, cada vez que se pulse o suelte una tecla.
la siguiente línea de código asignaría ese vector, utilizando la dirección absoluta de la etiqueta en-controlador:
hasta ahora nuestros programas uxntal han seguido un flujo lineal: comienzan en la dirección 0100 y terminan en la primera instrucción BRK que se encuentra.
podemos pensar en estos programas como rutinas de configuración: configuran los colores del sistema, pueden dibujar o imprimir algunas cosas y luego dejan a uxn esperando. ¿qué estaría esperando uxn?
este utiliza el procedimiento de dibujo de sprites que probamos el día anterior, pero hace que ocurra solo cuando se pulsa una tecla. al principio, la pantalla está vacía, y cuando pulsamos una tecla, se dibuja un cuadrado:
podemos pensar en los resultados empujados por estas instrucciones como banderas booleanas: son 01 si la comparación fue verdadera y son 00 si fue falsa.
.Controlador/tecla DEI ( lee la tecla y la empuja hacia abajo en la pila )
LIT 'a ( empuja el código ascii del carácter 'a' )
EQU ( compara ambos bytes y empuja 01 si son iguales, 00 si no )
```
EQU2, NEQ2, GTH2 y LTH2 funcionarán de la misma manera, pero comparando cortos en lugar de bytes.
## instrucciones lógicas
uxntal tiene tres instrucciones lógicas a nivel de bit.
pueden funcionar como operadores lógicos que utilizan como operandos las banderas dadas por las instrucciones de comparación que hemos comentado anteriormente:
lo siguiente empujará hacia abajo en la pila una bandera que indica si el byte tecla está entre 30 y 39 inclusive, usando 01 para representar 'verdadero' y 00 para representar 'falso':
como estos indicadores solo utilizan el bit menos significativo (el bit más a la derecha) para codificar su valor, un AND a nivel de bits es equivalente a un AND lógico convencional.
un "exclusive-OR", o también "o-exclusivo", es una operación lógica que tiene un resultado de verdadero solo cuando una u otra entrada es verdadera. si ambas entradas son verdaderas, o si ambas entradas son falsas, el resultado es falso.
basándose en este comportamiento, esta instrucción puede utilizarse para invertir el valor de una bandera utilizando un valor especial en el que el o los bits que queremos invertir se pongan a 1. este tipo de valores se llaman máscaras.
por ejemplo, el siguiente código empujará una bandera correspondiente a que la te sea mayor o igual a 20, calculando primero si es menor que 20 y luego invirtiendo el resultado:
.Controlador/tecla DEI ( lee la tecla y la empuja a la pila )
#20 LTH ( ¿es menor que 20? empuja la bandera a la pila )
#01 EOR ( invierte el bit más a la derecha de la bandera y empuja el resultado a la pila )
```
cuando la bandera original es verdadera, lo que significa que el valor de la tecla es menor que 20, el EOR la invertirá y la hará falsa: el valor NO es mayor o igual que 20:
```
0000 0001 ( verdadero )
EOR 0000 0001 ( máscara )
----------
0000 0000 ( falso )
```
como podemos ver, debido a que los dos bits de entrada son 1, el bit de salida es 0.
cuando la bandera original es falsa, lo que significa que el valor NO es menor que 20, el EOR lo invertirá y lo hará verdadero: el valor es mayor o igual que 20:
ok, ahora nuestros programas pueden identificar y almacenar en banderas si un valor (como la tecla de teclado leída) es un valor específico, o dentro de algún rango.
¿cómo podemos usar estas banderas para tener comportamientos condicionales en nuestros programas, donde se toman diferentes acciones dependiendo de los resultados?
¡introduzcamos otro conjunto de nuevas instrucciones para que uxn rompa su flujo lineal!
* JMP: "jump" o salto incondicional a la dirección de la pila ( direc -- )
* JCN: "conditional jump" o salto condicional: toma una dirección y un valor de la pila, y si el valor no es 00, salta a la dirección; en caso contrario continúa con la siguiente instrucción ( valor direc -- )
estas direcciones de un byte son relativas y pueden considerarse positivas y negativas: indican cuántos bytes hay que saltar en la memoria principal desde la posición actual del contador de programa, ya sea hacia delante (positivo) o hacia atrás (negativo). el rango de estas direcciones relativas es de -128 a 127 inclusive.
en modo corto, las direcciones que toman estas instrucciones son absolutas (es decir, de dos bytes de longitud), pero el valor que toma JCN para decidir sigue siendo un byte.
## runas para direcciones
hay varias runas que se refieren a direcciones y etiquetas. uxnasm las lee y las convierte a los valores binarios correspondientes.
nótese el uso de sub-etiquetas "dentro" (después) de en-controlador.
también note como la expresión ,&subetiqueta corresponde a la dirección relativa (,) que se necesita para saltar a esa ubicación en el código nombrado con una sub-etiqueta local (&).
estas direcciones relativas, de un byte, son utilizadas por JCN o JMP.
.Controlador/teclaDEI LIT '1 EQU ( ¿es la tecla '1'? )
,&color-1 JCN ( salta al color-1 si es el caso )
.Controlador/tecla DEI LIT '2 EQU ( ¿es la tecla '2'? )
,&color-2 JCN ( salta al color-2 si es el caso )
Controlador/tecla DEI LIT '3 EQU ( ¿es la tecla '3'? )
,&color-3 JCN ( salta al color-3 si es el caso )
( en cualquier otro caso, terminar )
BRK
&color-1
( dibujar el sprite en el fondo )
( usando el color 1 para el contorno )
#01 .Pantalla/sprite DEO
BRK
&color-2
( dibujar sprite en el fondo )
( usando el color 2 para el contorno )
#02 .Pantalla/sprite DEO
BRK
&color-3
( dibujar sprite en el fondo )
( usando el color 3 para el contorno )
#03 .Pantalla/sprite DEO
BRK
BRK
```
observe cómo las condiciones se escriben una tras otra: siempre que una bandera es falsa, JCN permite a uxn continuar con la siguiente instrucción en memoria.
también note que este código no está optimizado para el tamaño o la velocidad, sino para la legibilidad.
estaría en ti, por ejemplo, realizar una aritmética con el valor de la tecla que se pulsó para calcular el color a asignar al sprite - ¡podrías inspirarte en tu macro IMPRIMIR-DÍGITO del día 1!
hasta ahora hemos estado usando la pila como un lugar para almacenar operandos de instrucciones y sus resultados, ¡pero aún no hemos usado todo el potencial de este entorno basado en la pila!
en modo corto, POP2, DUP2, SWP2, NIP2, OVR2 y ROT2 realizan las mismas acciones pero utilizando cortos en lugar de bytes.
## ejemplos
vamos a utilizar estas instrucciones de muchas maneras diferentes durante los próximos días.
los siguientes son algunos ejemplos basados en fragmentos de código que ya hemos discutido.
ten en cuenta que el uso de estas instrucciones puede contribuir a que el código sea difícil de seguir o leer, por lo que siempre será una buena idea utilizarlas dentro de macros o tener comentarios en el código explicando lo que está sucediendo :)
### dígito ascii: duplicar e intercambiar
discutimos anteriormente este segmento de código, que empuja una bandera que responde si la tecla que se pulsa tiene un código ascii entre 30 y 39, ambos inclusive (es decir, calcula si un byte tiene un código ascii correspondiente a un dígito decimal)
```
.Controlador/tecla DEI ( lee la tecla y la empuja a la pila)
#2f GTH ( ¿es mayor que 2f? empuja la bandera a la pila )
Controlador/tecla DEI ( lee la tecla y la introduce en la pila )
#3a LTH ( ¿es menor que 3a? empuja la bandera a la pila )
en el caso que acabamos de discutir la entrada es la tecla que se presiona, pero podríamos fácilmente tener como entrada cualquier otro valor de la pila.
esto implica que podríamos escribir la rutina como una macro:
una máscara AND es un valor especial que utilizaremos para mantener o perder bits específicos de otro valor dado, como el byte del botón del controlador.
en nuestra máscara AND, estableceremos como 1 los bits en las posiciones en las que queramos mantener el valor de los bits de entrada. las posiciones en las que los bits de la máscara sean 0 se convertirán en 0 en la entrada.
por ejemplo, digamos que queremos ver si el bit número 4, que corresponde al botón Arriba, está encendido o apagado, independientemente del estado de los otros botones.
así vemos cómo la máscara nos permite aislar efectivamente el bit que nos importa, independientemente del estado de los otros bits.
aplicar esta máscara sería tan sencillo como escribir:
```
#10 AND ( aplicar máscara 0001 000 )
```
## ejemplo: dibujar con flechas y Ctrl
=> ./img/screenshot_uxn-draw-with-keyboard.png captura de pantalla de un posible resultado de la ejecución del siguiente programa; muestra un rastro dibujado con cuadrados rellenos o delineados.
el siguiente programa uxntal permite dibujar utilizando las teclas de las flechas y la tecla Ctrl (botón A).
* convertir los incrementos y decrementos de las coordenadas en macros que tomen la dirección del puerto como entrada y realizar una operación equivalente. estas dos líneas deberían funcionar usando la misma macro:
recuerde que .Pantalla/x es una dirección literal en la página cero, es decir, empuja un byte correspondiente a la dirección de la sub-etiqueta Pantalla/x :)
* crea un simple tablero de tres-en-raya para dos jugadores: una tecla dibuja una X, otra dibuja una O y las flechas permiten elegir la casilla a dibujar.
* JCN: salto condicional: toma una dirección y un valor de la pila y si el valor no es 00, salta a la dirección; en caso contrario continúa con la siguiente instrucción ( valor direc -- )