RANDOMIZE Todo sobre numeros aleatorios y llamadas a C.M. Para empezar Si alguien se pregunta cual es la relacion entre numeros aleatorios y llamadas a rutinas de usuario en codigo maquina... La rpta. es Sinclair. ya que es en su Basic que la sentencia RANDOMIZE hace ambas cosas. Esta es pues una recoleccion de todos mis apuntes sobre todas estas sentencias y funciones asociadas o relacionadas. I - Numeros aleatorios I.a - RANDOMIZE Esta sentencia permite generar una nueva semilla (seed) para el generador de numeros aleatorios. Existe en algunas versiones de BASIC bajo la forma abreviada de RAND, RANDOM y en otras como RANDOMISE, si con S en vez de Z. Y en aquellas versiones en las que ni siquiera existe, es reemplazado por una sintaxis de la funcion RND misma asociada a esta. Basic Darmouth Acepta tanto RANDOMIZE o su forma breve RANDOM sin parametros desde su version 4. Si esta al comienzo de un programa, la semilla de RND cambiara cada vez que se ejecute con RUN. Basic Microsoft sintaxis: RANDOMIZE [] donde: exp = valor de la semilla del generador de números aleatorios. Opcional. De omitirse el programa hace la sigte. pregunta: Random Number Seed (-32768 to 32767)? - numero de semilla aleatorio? antes de ejecutar el RANDOMIZE. Esta sentencia es inexistente en los BASICs de APPLE, Atari, Commodore, MSX, BBC, Tandy Color o Dragon 32 y Oric. En el PDP-8e existe como RAN. TRS-80 Basic nivel II sintaxis: RANDOM carece de parametros y debe ser la primera sentencia del programa que requiera valores RND. Basic Sinclair sintaxis: RANDOMIZE [] donde: exp = valor opcional para el generador de números aleatorios. Sin parametros actua igual que el RANDOM de Darmouth y TRS80. Tanto el Basic del Spectrum, como el de SAM y Amstrad comparten la misma sentencia y sintaxis. En el ZX81 es RAND y en el QL es RANDOMISE pero aplicando la misma sintaxis. I.b - RND Esta es la funcion por excelencia para la creacion de valores aleatorios ya que son muy necesarios en la creacion de juegos o rutinas matematicas para calculo de probabilidad o estadisticas. Existe en practicamente en todas las versiones de BASIC ya sea con parametros (opcional o no) o sin ninguno. Formato 1 de RND sintaxis: RND(x) esta es la version que existe en aquellos BASICs la mayoria sin sentencia RANDOMIZE. Ejemplos en el C=64: LET RAND = RND(-1) - equivale a RANDOMIZE de otros Basics RAND = RND(-TI) - equivale a RANDOMIZE TIME o VAL(TIME$) RND(1) - genera un valor entre 0 y 1.0 INT(RND(0)*X) - genera valor entero entre 0 y X (RND(0)*(X-Y)+Y) - genera valor entre Y y X En el TRS80 y Dragon 32: RND(0) - genera un valor entre 0 y 1.0 RND(x) - genera un valor entero entre 1 y X En el Basic de Atari: RND(0) - genera un valor entre 0 y 1 pero nunca 1, donde el parametro es un valor de relleno que no afecta en nada al resultado. En el Basic Applesoft: RND(1) - o cualquier parametro, genera un valor entre 0 y 1 RND(0) - repite el ultimo valor generado por el RND anterior RND(-X) - equivale a RANDOMIZE x Basic Entero del Apple II: RND({-}x) - genera un valor entero entre 0 y X Oric 1 y Atmos: RND(x) - opera de modo similar al Apple II Formato 2 de RND sintaxis: RND{(x)} donde x = un parametro opcional Esta es la version existente en las versiones como Mbasic o GWbasic de Microsoft. Sintaxis similar en el BBC Basic y Amstrad CPC. Basica y GWbasic: RND = RND(0) - repite el ultimo valor generado INT(RND*X)+Y - genera valor entero entre Y y X+Y-1 Basic BBC: RND - genera un entero aleatorio de 32-bits. RND(-n) - semilla n de la sequencia, equivale A RAND n RND(0) - repite el último valor de RND(1) RND(1) - genera un número entre 0 y 0.999999999 RND(n) - genera un entero aleatorio entre 1 y n. Amstrad CPC RND - la misma sintaxis que en Basica Formato 3 de RND sintaxis: RND sin parametros, es la version presente en el Basic Sinclair y similares. Basic Darmouth: RND - no requiere de parametros, da valor entre 0 y 1. ZX81 y Spectrum: RND - carece de parametros como el RND de Darmouth BetaBasic: RNDM(0) - equivale a RND pero dos veces y medio mas rapido RNDM(x) - genera un valor entero entre 0 y X inclusive Superbasic de QL: RND - sin parametros es igual al del Spectrum RND(x) - genera un valor entero entre 0 y X RND(x TO y) - genera un valor entero entre X e Y SAM basic: RND - sin parametros es igual al del Spectrum RND(x) - genera un valor entero entre 0 y X inclusive II - Llamadas a rutinas de usuario en codigo maquina II.a - USR Breve por USeR o USuaRio. Esta funcion permite invocar a una subrutina en codigo maquina, tras lo cual se continua con el programa en BASIC. Curiosamente su sintaxis varia un poco segun cada version de micro. En el Apple II: USR n - donde n es puesto en el acumulador de coma flotante que se ubica en la memoria desde 157 a 163. Enseguida ejecuta la instruccion JSR $000A, bifurcando a las posiciones de 10 al 12, las cuales deben contener un JMP que vaya a la pos. inicial de dicha subrutina que debe de terminar en RTS y devolver un valor numerico real. En el C=64: USR(v) - donde v es puesto en el acumulador de coma flotante, para enseguida ejecutar una subrutina en c.m. cuya dir. de comienzo se POKEa en las direcciones 785 y 786 de lo contrario se obtiene un error de "ILLEGAL QUANTITY" (cantidad ilegal). Al retornar devuelve un valor al programa Basic que lo invoca. En el UK-101 y Superboard II: USR(y) - ejecuta código máquina cuya dirección está en los bytes $0011/0012. El valor Y es obtenido a traves de las variables del sistema del BASIC en la página cero. En el Atari: USR(exp1{,exp2{,exp3,...}}) - deja de ejecutar BASIC por un momento y va a ejecutar las rutinas de código máquina que comienzan en la dirección exp1 y coloca el número resultante en una variable X que sea usada para su invocacion. Los demas parametros son opcionales y pasan informacion a la rutina en c.m. En el Basic BBC: USR(dir) - llama a una rutina en código máquina que empieza en 'dir' y devuelve un entero. En el Spectrum: USR dir - opera de modo identico al del BBC. Existente en el Basic del ZX81 y SAM, pero no en el Superbasic del QL. Tampoco existe en el Basic del CPC. En el GWbasic y TRS80: USR{n}(v) - donde n = una de 10 llamadas de usuario del 0 al 9 y v = un valor que es pasado a la rutina en c.m. invocada por USR. Requiere de la sentencia: DEFUSR= - donde n = un valor del 0 al 9 de usuario y dir = la posicion de memoria donde empieza la rutina c.m. a llamar. GWbasic requiere ademas de: DEF SEG=dir - asigna la direccion dir del segmento actual a la que hará referencia un BLOAD, BSAVE, CALL, PEEK, POKE o USR posterior. GWbasic tambien requiere que DEF USR tenga un espacio de separacion a diferencia del TRS80. II.b - CALL Esta sentencia que significa LLAMAR, lo que hace es transferir el control de un programa Basic a una subrutina en c.m., actuando de un modo similar a GOSUB. sintaxis: CALL dir donde: dir = una variable o constante asignando una dir. de memoria, ya sea ne la ROM o una subrutina creada por el usuario en la RAM. Esta sentencia existe en la mayoria de BASICs ya sea Microsoft o que son compatibles con este. No esta presente en las versiones de Sinclair o Atari. CALL existe sin embargo en el Superbasic del QL y SAM. En el C=64: sintaxis: SYS dir{,exp,...} pasa el control a una rutina en C.M. que comienza en la pos. de memoria 'dir'. SYS es breve por SYSTEMa y puede aceptar parametros que son los que el c.m. requeriria segun como el usuario lo haya programado. Este comando es exclusivo de todas las maquinas hechas por Commodore. En el Spectrum Debido a que no existe ninguna sentencia CALL, SYS o similar en el ZX Spectrum (ni en el ZX81) es que se eligio la combinacion sigte.: sintaxis: RANDOMIZE USR dir Esta es la instruccion por excelencia en cualquier porgrama de Sepctrum para ejecutar una rutina en c.m. En un viejo "gomas" esto tiene mucho mas sentido, ya que gracias al tipico modo de tipear de Sinclair, una palabra tan larga omo esta no se tipea letra a letra sino que con solo pulsar T en modo K, te la ponia en pantalla y USR pulsando L en modo E. Pero en un 128k o +3, si tiene uno que tipearlo todo letra a letra, lo que lo hace menos corto de tipear. RANDOMIZE ejecuta el USR sin hacer mas pero en realidad tiene como un pto. en contra que en realidad coge cualquier valor resultante y lo usa como semilla del valor de RND. Debido a eso y para evitar afectar los resultados aleatorios del programa debemos ver otras alternativas como son... sintaxis: LET var= USR dir Esta es la instruccion usada por excelencia por practicamente todas las otras versiones de BASIC ya sea que tengan o no CALL o RAND. Tiene la ventaja ejecutar el USR y a la vez almacenar el resultado que es devuelto en una variable para su posterior uso. El otro es el poder usar palabras que den algo de claridad de lo que hace el USR como es por ejemplo LET call=USR xxx que se podria trraducir como 'asignar la llamada a usuario xxx' o LET err=USR dos, que es usado en el caso del Betadisco o Beta128 para capturar errorer del disco en un TRdos. sintaxis: PRINT USR dir Esta es otra orden muy usada tambien. Y ene ste caso lo que hace es ejecutar el USR y al final mostrar en pantalla el resultado devuelto por la rutina invocada en USR, ya sea util o no dicha rpta. Otras posibles alternativas: sintaxis: INPUT USR dir Esta es mi instruccion preferida a PRINT USR, debido a que opera igual pero sin imprimir nada en pantalla. En realidad lo hace en la zona baja pero INPUT borra automaticamnte esa zona y por eso no se ve nunca nada. sintaxis: RESTORE USR dir Podria servir de alternativa en vez de RAND. Tiene como contra que afecta a la lectura de lineas DATA por READ, por lo que podria usarse solo si el programa no requiere de DATAs. sintaxis: LPRINT USR dir Esto tambien puede ser una alternativa a PRINT USR, siempre que no se tenga una impresora coenctada y activa. sintaxis: OPEN #USR dir,"k" Esta es otra orden que se me ocurrio usar para ejecutar la libreria de funciones de Microhobby para generar ficheros en el +3. sintaxis: CLOSE #USR dir Por la misma razon del caso anterior, pero funciona optimanente si el resultado devuelto por la funcion es siempre cero, ya que otro valor mayor de 3 haria que CLOSE genere error . Otras raras alternativas: sintaxis: GOTO USR dir Muy util solamente si quisiera ejecutar el USR y al mismo tiempo usar el resultado devuelto para saltar a una linea que se desee. sintaxis: GOSUB USR dir Por la misma razon del caso anterior, pero si USR devolviese un valor no deseado, terminariamos yendo a cualquier linea menos la esperada. sintaxis: RUN USR dir Al igual que en los caos anteriores, solamente si se desea ejecutar de nuevo el programa (si el resultado es 0) o a partir del valor devuelto por USR para su ejecucion. En el Spectrum 128 y +3 A partir de la version 128k de Investronica, el cual tenia un modo de comandos directos en la zona de INPUT, y era usado como calculadora es que se podia tipear USR xxx como comando directo. Esto aun es posible de hacer en la version britanica del 128k asi como el +2 y +3 sin ir ahora a la zona baja o entrar en la calculadora. Mas raras alternativas: INK USR x, PAPER USR x, BORDER USR x, estas funcionarian si el C.M. me devuelve un valor valido de color. PAUSE USR x, si el C.M. afecta la pausa a proposito. BEEP z,USR x si busco generar un sonido con la ejecucion del C.M. IF USR x THEN... si quiero crear una condicion con el resultado de USR. Mas raros aun serian PLOT, DRAW, CIRCLE, solo si el USR afecta a los graficos. OUT, LIST y LLIST por igual. Y para cerrar UN CURIOSO TRUCO La sentencia RANDOMIZE tiene como fin y parametro un valor que como ya se dijo es la semilla del generador de numeros aleatorios, desde cero hasta 65535 el cual es almacenado en la variable del sistema SEED (es decir semilla) cuyas direcciones son 23670-71. Esto nos ofrece la posibilidad de dividir un valor entero en la forma de 2 octetos que luego podemos leer ya sea con PEEK en BASIC o por una rutina en C.M. mediante su correspondiente instruccion en ensamblador. Y hasta aqui todas mis notas sobre RANDOMIZE y las instrucciones que se asocian a esta sentencia tanto en el Spectrum como en otros BASICs. (c)2023 zx_if1@hotmail.com