Generación de números aleatorios en Z80 (u otro de 8 bits)

Foro dedicado a la programación en todo tipo de sistemas clásicos.
Avatar de Usuario
PabloMarmol
Amstrad PCW 8256
Amstrad PCW 8256
Mensajes: 169
Registrado: 03 Sep 2012, 17:32
Sistema Favorito: Spectrum 16Kb/48Kb
primer_sistema: Spectrum 16Kb/48Kb
Primera consola: Nintendo NES/Clónica
Ubicación: León, España
Gracias dadas: 12 veces
Gracias recibidas: 13 veces

Re: Generación de números aleatorios en Z80 (u otro de 8 bits)

Mensajepor PabloMarmol » 08 Nov 2018, 15:57

Bubu escribió:resulta que R depende del número de instrucciones que se han ejecutado, en cada una se incrementa 1 este registro.
Depende de los bytes que ocupe el opcode, R se incrementará en 1 por cada byte de la instrucción. Las instrucciones cuyo opcode ocupe 2, pues R=R+2, etcétera.
Bubu escribió:Así las cosas, como los pogramas siempre ejecutan exácticamente el mismo número de instrucciones cá vez que los ejecutamos, sisnifica que sieeeempre que leemos la 1ª vez el registro R, siempre tié el mismo valor. Y cuando lo leemos la 2ª vez, siempre tié ese otro valor, etc.

Eso del mismo valor solo pasará si entre lecturas de R no sales de un bucle y ejecutas 128 instrucciones de 1 byte (por ejempo), para que dé una vuelta completa el contador de R, no?
*EDITO*
Vale, ya veo que te referías a leer R al comienzo de un programa, en el caso de que se use un emulador, y que este no aleatorice "el estado de la máquina" al arrancar.

Avatar de Usuario
explorer
MSX Turbo R
MSX Turbo R
Mensajes: 322
Registrado: 11 May 2014, 17:10
Sistema Favorito: Atari ST
primer_sistema: Atari 800XL/600XL
consola_favorita: Atari 2600
Primera consola: Atari 2600
Ubicación: Valladolid, España
Gracias recibidas: 78 veces
Contactar:

Re: Generación de números aleatorios en Z80 (u otro de 8 bits)

Mensajepor explorer » 09 Nov 2018, 04:47

Bubu escribió:De esa rutina no entiendo esta instrucción ld e, (hl). ¿Aónde está apuntando hl? ¿A la ROM? ¿A la RAM? ¿Y si esa zona está llena de ceros o $FF's?

Da igual dónde esté apuntando... A cualquier parte. Es lo que luego se meterá en E para luego sumarlo a HL.
Al final, es realizar un pequeño cálculo para que dé resultados "aleatorios". Esta vez, tomando la propia memoria RAM y ROM como variables.

Avatar de Usuario
Bubu
Atari 1040 STf
Atari 1040 STf
Mensajes: 971
Registrado: 04 Abr 2018, 23:10
Sistema Favorito: Spectrum 16Kb/48Kb
primer_sistema: Spectrum 16Kb/48Kb
consola_favorita: Atari 2600
Primera consola: Nintendo GameBoy
Gracias dadas: 22 veces
Gracias recibidas: 43 veces

Re: Generación de números aleatorios en Z80 (u otro de 8 bits)

Mensajepor Bubu » 20 Nov 2020, 21:40

Me había olvidado de este jaleo... Al final lo implementé de esta guisa:

Código: Seleccionar todo

; Genera un número aleatorio entre mín y máx
; Es aleatorio si el tiempo pasado entre la llamada anterior y la actual lo es
; IN:      b = máx
;      c = mín
; OUT:   c = número aleatorio entre mín y máx
; Ejemplo   ld bc, 0x0702 para generar un número entre 2 y 7
get_rnd:      
      ld a, b
      sub c
      ld b, a
gr1
      ld a, r
      and %00000001
      add a, c
      ld c, a
      djnz gr1
      ret


Sé que ir sumando de 1 en 1 la aleatoriedad no es lo más óptimo en cuanto a velocidad, pero para el uso que le voy a dar, que es calcular dónde voy a situar los sprites de los enemigos va sobradísima.
Última edición por Bubu el 20 Nov 2020, 23:11, editado 1 vez en total.
Si algo funciona... ¡¡NO LO TOQUES!! ¡¡NI DE COÑA!!

Avatar de Usuario
Bubu
Atari 1040 STf
Atari 1040 STf
Mensajes: 971
Registrado: 04 Abr 2018, 23:10
Sistema Favorito: Spectrum 16Kb/48Kb
primer_sistema: Spectrum 16Kb/48Kb
consola_favorita: Atari 2600
Primera consola: Nintendo GameBoy
Gracias dadas: 22 veces
Gracias recibidas: 43 veces

Re: Generación de números aleatorios en Z80 (u otro de 8 bits)

Mensajepor Bubu » 20 Nov 2020, 23:10

Pues no, así no es exácticamente como lo hice, lo acabo de catar y siempre me genera el mismo número, y eso porque la iteración que hago, al tardar siempre lo mismo, r siempre sufre el mismo incremento, y al hacer and %00000001 pues simpre vale 0, o siempre alterna 0 y 1, o siempre vale 1.
En fins... voy a mirar cómo lo implementé realmente.
Si algo funciona... ¡¡NO LO TOQUES!! ¡¡NI DE COÑA!!

Avatar de Usuario
Bubu
Atari 1040 STf
Atari 1040 STf
Mensajes: 971
Registrado: 04 Abr 2018, 23:10
Sistema Favorito: Spectrum 16Kb/48Kb
primer_sistema: Spectrum 16Kb/48Kb
consola_favorita: Atari 2600
Primera consola: Nintendo GameBoy
Gracias dadas: 22 veces
Gracias recibidas: 43 veces

Re: Generación de números aleatorios en Z80 (u otro de 8 bits)

Mensajepor Bubu » 25 Nov 2020, 23:16

Bueno, ya he visto cómo lo tengo implementado, pero ni me acuerdo por qué lo tengo así, ni de dónde lo saqué, ni nada:

Código: Seleccionar todo

V_RND_SEED:    DEFB   0   ; Actualizar este valor con el registro r
                     ; siempre que el tiempo pasado entre la
                     ; actualización anterior y la actual sea
                     ; indeterminada
; Genera un número aleatorio de 8 bits
; OUT : a = número aleatorio
; MOD:   a
get_rnd:
      push de
      ld a, (V_RND_SEED)
      ld d, a
      rrca
      rrca
      rrca
      xor 0x1F
      add a, d
      sbc a, 0xFF
      ld (V_RND_SEED), a
      pop de
      ret


La verdad es que no entiendo para nada para qué hace los rrca, el xor, el add, etc. El caso es que el funcionamiento es el siguiente: al ejecutar el pograma, siempre se le pide al usuario que pulse una tecla. Al pulsarla, el registro "r" valdrá el tiempo que lleva el Z80 ejecutando instrucciones, por tanto "r" será totalmente aleatorio.
Y entonces, ¿por qué no usar direstamente "r" a partir de ahí para generar números aleatorios? Pues por lo siguiente:

imaginemos que necesito generar 20 1's y 0's seguidos aleaorios, porque un 1 significa que voy a mostrar un enemigo verde, y un 0 que voy a mostrar un enemigo rojo, y quiero mostrar 20 enemigos a la vez. Entonces, si hago esto:

Código: Seleccionar todo

ld b, 20
otro:
ld a, r
and %00000001
call muestra_enemigo
djnz otro


Esto tiene un problemón, porque lo he comprobado. El tiempo que tarda el and, el call y el djnz es determinista, es decir, en cada iteración tarda exactamente N tiempo. Por tanto, r siempre adquirirá estos valores: r(0), r(0)+N, r(0)+2N, r(0)+3N, etc
Y como cojo el último bit, resulta que me salían 20 enemigos verdes, o 20 enemigos rojos, o 10 verdes y 10 rojos. Matemático.

Por tanto "r" sólo sirve para generar números aleatorios SIEMPRE que haya pasado un tiempo aleatorio la última vez que leí "r".

Hasta aquí bien, lo entiendo, sé que no basta con "ld a, r", pero, ¿alguien entiende la rutina esa que he ponido antes?
Si algo funciona... ¡¡NO LO TOQUES!! ¡¡NI DE COÑA!!

Avatar de Usuario
explorer
MSX Turbo R
MSX Turbo R
Mensajes: 322
Registrado: 11 May 2014, 17:10
Sistema Favorito: Atari ST
primer_sistema: Atari 800XL/600XL
consola_favorita: Atari 2600
Primera consola: Atari 2600
Ubicación: Valladolid, España
Gracias recibidas: 78 veces
Contactar:

Re: Generación de números aleatorios en Z80 (u otro de 8 bits)

Mensajepor explorer » 26 Nov 2020, 10:44

Lo del efecto de "números repetidos" por leer el registro R, es algo que ya hemos comentado antes.

El algoritmo de generación de números aleatorios es parecido a los que comentamos en el hilo "Generación de números aleatorios en Z80 (u otro de 8 bits)" que tú mismo iniciaste el 7 de noviembre de 2018, los llamados generadores lineales congruenciales (tomar la semilla, transformarla por ejemplo con una multiplicación o desplazamiento, y añadirle una operación matemática o lógica con una constante).

El que has puesto hace esta operación (si no me he equivocado en la interpretación):

Código: Seleccionar todo

a =  a +  ( (a % 8) * 32 + (a / 8) ) ^ 31 + 1


Me parece que es de la familia de los llamados "generadores de números Xorshift", ya que está haciendo una operación matemática XOR de un número con una versión desplazada de la semilla. La multiplicación por 32 es lo mismo que desplazar 5 bits a la izquierda, y dividir por 8 es lo mismo que desplazar 3 bits a la derecha.

Avatar de Usuario
Bubu
Atari 1040 STf
Atari 1040 STf
Mensajes: 971
Registrado: 04 Abr 2018, 23:10
Sistema Favorito: Spectrum 16Kb/48Kb
primer_sistema: Spectrum 16Kb/48Kb
consola_favorita: Atari 2600
Primera consola: Nintendo GameBoy
Gracias dadas: 22 veces
Gracias recibidas: 43 veces

Re: Generación de números aleatorios en Z80 (u otro de 8 bits)

Mensajepor Bubu » 26 Nov 2020, 17:21

Estos algoritmos me imagino que serán exácticamente lo mismo que generar un array de 256 números con el propio algoritmo, grabarlos en memoria, y cada vez que el pograma necesite un número, se va al array y coge el siguiente que toque.
Voy a generar los 256 números a ver qué sale.

Partiendo de SEED = 0, obtengo los siguientes:

Código: Seleccionar todo

{
32,    60,    213,   122,    203,   49,   107,   222,   162,   238,   176,   186,   2,   98,   182,   127,
111,   97,   149,   66,   154,   231,   202,   16,   46,   8,   39,   34,   126,   78,   36,   192,
200,   207,   181,   94,   50,   140,   26,   119,   104,   123,   236,   110,   64,   88,   109,   31,
27,   152,   165,   80,   102,   57,   114,   196,   75,   194,   9,   72,   95,   83,   201,   240,
242,   51,   173,   87,   76,   227,   70,   29,   218,   30,   251,   91,   208,   214,   155,   7,
6,   230,   169,   212,   89,   142,   92,   241,   18,   112,   130,   210,   23,   20,   178,   252,
...
}


Uffff, no parece que no entran en ciclo, lo cual podría deberse a que lo que hace el algoritmo es desordenar los bits de la semilla, pero no pierde información ninguna. Así, dada una semilla, se obtiene otra única, irrepetible. Voy a analizar el código a ver si es cierto eso de que sólo desordena los bits.
Última edición por Bubu el 26 Nov 2020, 17:42, editado 1 vez en total.
Si algo funciona... ¡¡NO LO TOQUES!! ¡¡NI DE COÑA!!

Avatar de Usuario
Kusfo
MSX Turbo R
MSX Turbo R
Mensajes: 403
Registrado: 17 Jul 2012, 13:05
Sistema Favorito: Amstrad CPC
primer_sistema: Amstrad CPC
consola_favorita: Sega Master System
Primera consola: Sega Master System
Ubicación: Warcelona
Gracias dadas: 1 vez
Gracias recibidas: 8 veces

Re: Generación de números aleatorios en Z80 (u otro de 8 bits)

Mensajepor Kusfo » 26 Nov 2020, 17:28

Bubu escribió:Estos algoritmos me imagino que serán exácticamente lo mismo que generar un array de 256 números con el propio algoritmo, grabarlos en memoria, y cada vez que el pograma necesite un número, se va al array y coge el siguiente que toque.
Voy a generar los 256 números a ver qué sale.


Yo eso es lo que hago en la Master. Además me resulta útil para sacar siempre la misma secuencia (aunque eso también lo podría hacer repitiendo la misma seed)
Amstrad CPC6128 + Spectrum +2A + SONY MSX2 HB-F1 + Commodore Amiga 500 + Sega SC-3000 + Sega Mark III + Sega Master System + Sega Megadrive + Sega Saturn+ Sega Dreamcast + Nintendo Nes + Super Nintendo + Nintendo 64 + Nintendo Gamecube + PC-Engine

Avatar de Usuario
Bubu
Atari 1040 STf
Atari 1040 STf
Mensajes: 971
Registrado: 04 Abr 2018, 23:10
Sistema Favorito: Spectrum 16Kb/48Kb
primer_sistema: Spectrum 16Kb/48Kb
consola_favorita: Atari 2600
Primera consola: Nintendo GameBoy
Gracias dadas: 22 veces
Gracias recibidas: 43 veces

Re: Generación de números aleatorios en Z80 (u otro de 8 bits)

Mensajepor Bubu » 26 Nov 2020, 18:13

Sí, lo que pasa es que el array ocupa 256 bytes, y esto se ahorra si me lo genera "en caliente" un algoritmo, jiji.
Lo que sí me queda claro, es que pa no repetir siempre la misma secuencia, intentaré que ca vez que el usuario pulse una tecla por lo que sea, astualizar la semilla (V_RND_SEED en mi función) con el registro "r" de ese momento.
Si algo funciona... ¡¡NO LO TOQUES!! ¡¡NI DE COÑA!!


Volver a “Programación”

¿Quién está conectado?

Usuarios navegando por este Foro: No hay usuarios registrados visitando el Foro y 3 invitados