Karoshi MSX Community
05 de Julio de 2021, 09:30:49 pm *
Bienvenido(a), Visitante. Por favor, ingresa o regístrate.

Ingresar con nombre de usuario, contraseña y duración de la sesión
Noticias:
 
   Inicio   Ayuda Buscar Ingresar Registrarse  
Páginas: [1] 2 3 ... 5
  Imprimir  
Autor Tema: Optimizando los listadillos basic  (Leído 28555 veces)
0 Usuarios y 1 Visitante están viendo este tema.
Darth_Fistro
Karoshi Hero
*****
Mensajes: 507


Email
« : 25 de Enero de 2006, 04:11:01 pm »

He aquí una pequeña guía basada en pruebas que hice hace un par de años cuando empecé a programar en basic MSX, que puede que os resulte útil a los nuevos en el tema. El método fué hacer una serie de listados con operaciones matemáticas, bucles, sprites, etc. y al principio, inicializar TIME a cero, y mostrar su valor una vez terminado el bucle. Hice 5 pruebas en cada modalidad y saqué una media. No voy a publicar los números porque es una lata pero sí daré un resumen de los resultados, que es lo que interesa (conclusiones y moralejas varias, vamos)  Wink

Amos allá:

Empecemos por algo básico. Imaginemos:
Código:
20 for i=1 to 500
30 a=i-1
40 b=a*2
50 next i
-Si unimos las líneas 30 y 40 en una sola instrucción, separada por dos puntos (Smiley, obtenemos una mejora ridícula (no llega al 1%) pero ya nos da una pista... hay que intentar dentro de lo posible unir en una sola línea tantas instrucciones como sea posible.

-Si insertamos una línea, por ejemplo, la 25, con un REM, la cosa se ralentiza. Así que a usar los menos rems posibles, ya que hay que procesar una instrucción que en definitiva no hace nada.

-Quitando los espacios entre instrucciones también se gana algo de velocidad. Poquísimo, pero algo es algo.

-Ganamos algo más apreciable si sustituimos el NEXT I por NEXT. No hace falta indicar la variable.Eso sí, contad cuántos bucles estáis usando para no haceros un lío y que se queden FORs sin NEXTs o viceversa.

Sigamos con más cositas... los veteranos estarán durmiéndose  Wink pero para nosotros, estas cositas nos pueden salvar el culo en un momento de apuro.

Código:
if x>0 then goto 500

-Una expresión es cierta (-1) cuando vale distinta de cero. Así, si quiero saber si la coordenada x de mi nave no sobrepasa la derecha de la pantalla, sólo hay que hacer i x then goto 500. No hace falta la comparación, ya que será verdadera la condición si x<>0 en cualquier caso. Con esto ganamos velocidad.

-Es más, respecto al THEN GOTO 500, podemos quitar el GOTO y poner directamente THEN 500, y ganamos algo. Curiosamente, ganamos algo más si quitamos el then y dejamos sólo el goto, o sea, IF X GOTO 500

-EL CAMPEON CONTRA LAS MANCHAS... DEFINT
Si nuestras variables no necesitan decimales y su valor no va a sobrepasar 32768 o -32768, a usar variables enteras. Definidlas con DEFINT al principio del programa y veréis la diferencia. Eso sí, usad DEFINT antes de dar cualquier valor a las variables u os las borrará. Lo mismo con las matrices. Primero usad DEFINT y luego DIM, si no se borran.

-Una vez usemos variables enteras,p.e. con DEFINT A-Z, ya no hace falta p.e. hacer A=INT(RND(1)*10), nos basta con A=RND(1)*10, ya que de todas formas A es una variable entera, y ejecutar la función INT sólo nos quitará un tiempo de ejecución precioso.

-Chorradita al canto. Aprended TODAS las instrucciones basic porque todas tienen un uso concreto y se les puede sacar partido. Por ejemplo, como ejemplo chorra, en vez de hacer un FOR I=1 to 20:PRINT CHR$(166);:NEXT, usar mejor PRINT STRING$(20,166), que es 10 veces más rápido.

-Sprites. Usar VPOKE donde sea posible (en los casos en que no se necesiten valores mayores de 255 o menores de cero), pues daría error. Incluso vpokeando las coordenadas, color y nº de patrón, es más rápido que usar PUT SPRITE.

-Evitad el uso de paréntesis innecesarios. Es más rápido X=X+2*(D=7 OR D=8) que X=X+2*((D=7) OR (D=8))

-Tanto si usáis variables enteras como si no, la división entera \ es más rápida que la normal /. Pero mucho más rápida. Así que en vez de usar A=INT(B/2), usad A=B\2 y veréis la diferencia. Eso sí, tened en cuenta que esta división tiene la menor prioridad, o sea que metedla entre paréntesis o el ordenador ejecutará antes una suma, resta, etc. que tenga al lado. A=2+B\2 os lo hará como 2+B dividido entre 2, en vez de darle la prioridad a la división, que es lo normal.

-No usar IF NOT(A) que consume mucho. Usar IF A=0 o IF A<>.

-Es más rápido hacer A=B+B o A=B+B+B que A=B*2 o A=B*3 respectivamente. A partir de 4, ya no compensa.

-Gran mito caído. El apóstrofe ' es más lento que el REM, y para colmo ocupa más (que es lo que siempre repetían en las revistas).


Seguro que hay cosas que corregir y aportar mil ideas más. Así que lo mejor es dejar esto abierto y que cada uno nos vaya contando sus experiencias  Smiley
« Última modificación: 25 de Enero de 2006, 04:16:54 pm por Darth_Fistro » En línea

MSX FOREVER (hasta que saquen un ZX81 con TMS, PSG y 64K de RAM)
Darth_Fistro
Karoshi Hero
*****
Mensajes: 507


Email
« Respuesta #1 : 25 de Enero de 2006, 04:14:07 pm »

-El basic almacena las variables en una lista, a la que accede secuencialmente desde la primera posición. A medidas que usas variables, se van metiendo en esa lista, por tanto la última variable que has usado es la última que encuentra, y por tanto la más lenta. Moraleja::define primero (da un valor, un cero por ejemplo) las variables que más uses y luego las menos importantes.

-Por esa regla de tres, cuantas menos variables tengamos, mejor. Menos memoria y más rapidez de acceso. Así que si I, T, X o lo que sea no los usas fuera de un bucle y da igual cambiarlos, úsalos en vez de definir otra variable. Vale, es más lioso, pero más eficaz.
En línea

MSX FOREVER (hasta que saquen un ZX81 con TMS, PSG y 64K de RAM)
SapphiRe
Visitante
« Respuesta #2 : 25 de Enero de 2006, 04:18:07 pm »

Un truco más:

Las subrutinas que se ejecuten muchas veces y cuya velocidad sea crítica han de ir al principio del programa.

Y ahora la explicación:

Cuando se hace un salto de línea, el intérprete de BASIC recorre el listado DESDE EL COMIENZO para buscar la línea a la que tiene que saltar. Si la rutina está en una línea alta, se perderá muchísimo tiempo en este recorrido.

Moraleja: la primera línea del listado debería ser un GOTO xxx donde xxx representa la línea de inicio de la rutina de inicialización y presentación del juego. El menú (si lo tiene) también debería ir al final del listado. Las subrutinas que requieran velocidad, al principio.

Saludos
--
SapphiRe
En línea
Darth_Fistro
Karoshi Hero
*****
Mensajes: 507


Email
« Respuesta #3 : 25 de Enero de 2006, 04:19:19 pm »

-Una más. Es más rápido acceder a una variable matricial unidimensional que multidimensional. Así que es mejor definir p.e. un cuadro de juego de 8x8 como DIM A(64) que como DIM A(8,8). Tened en cuenta el acceso secuencial a las 64 casillas, que es más complicadillo (pero un pelín) y a cambio ganaréis en velocidad.
En línea

MSX FOREVER (hasta que saquen un ZX81 con TMS, PSG y 64K de RAM)
SapphiRe
Visitante
« Respuesta #4 : 25 de Enero de 2006, 04:27:01 pm »

Ya puestos, una rutina para mover las coordenadas X,Y de un Sprite leyendo el joystick. Supongamos que en J está el valor del joystick y que queremos mover un pixel el Sprite en las 8 direcciones:

X=X-(J=2)-(J=3)-(J=4)+(J=6)+(J=7)+(J=8)
Y=Y-(J=4)-(J=5)-(J=6)+(J=8)+(J=1)+(J=2)

Y ahora (como siempre) la explicación:

Una expresión booleana puede ser verdadera o falsa, pero el BASIC del MSX codifica el Falso como 0 y el Verdadero como -1. Si asumís este hecho se pueden hacer muchos apaños de velocidad Smiley

Saludos
--
SapphiRe refrescando el Basic
En línea
Imanok
Karoshi Hero
*****
Mensajes: 626


« Respuesta #5 : 25 de Enero de 2006, 04:31:51 pm »

Para todo el tema de espacios, comentarios y tal, vale MUCHO la pena probar el NestorPreter. Te puedes inflar a poner comentarios, nombres de variables largos, macros, etc, etc... que luego el programa en sí te queda en lo mínimo.
En línea
jltursan
Karoshi Forum's Guru
*******
Mensajes: 1516


¿Que es lo que has aprendido hoy?


WWW Email
« Respuesta #6 : 25 de Enero de 2006, 09:16:07 pm »

¡Muy buena la recopilación de trucos hasta ahora! Cheesy

Ahí va otro:

Si estamos trabajando en SC0 o en SC1 es muy probable que en algún momento tengamos que hacer un montón de PRINTs con sus correspondientes LOCATEs. En lugar de emparejar cada PRINT con su LOCATE, podemos estudiar si hay alguna solución equivalente utilizando las secuencias de escape que son bastante más rápidas que los LOCATE a la hora de, por ejemplo, ubicar el cursor en pantalla (sobre todo porque el intérprete se ahorra procesar esa operación).

Las secuencias son (también consultables en el MTH, capítulo TH-AP.TXT) :

Movimiento del cursor

<ESC> A    mueve el cursor hacia arriba
<ESC> B    mueve el cursor hacia abajo
<ESC> C    mueve el cursor hacia la derecha
<ESC> D    mueve el cursor hacia la izquierda
<ESC> H    mueve el cursor a la posición de inicio (home)
<ESC> Y <coordenada-Y+20H> <coordenada-X+20H>
      mueve el cursor a (X, Y)


Editar, borrar

<ESC> j    Borra la pantalla
<ESC> E    Borra la pantalla
<ESC> K    Borra hasta el final de la linea
<ESC> J    Borra hasta el final de la pantalla
<ESC> L    Insertar una linea
<ESC> M    Borrar una linea


Miscelaneas

<ESC> x4   Selecciona el cursor de bloque
<ESC> x5   Esconde el cursor
<ESC> y4   Selecciona el cursor de linea
<ESC> y5   Muestra el cursor

Por ejemplo, si por casualidad tenemos un "sprite" construido a partir de 3x3 (abc,def,ghi) carácteres, no necesitamos hacer tres LOCATEs con sus correspondientes PRINTs; si definimos el "sprite" en una cadena, con un único LOCATE+PRINT podremos presentarlo en pantalla :

Código:
10 S1$="abc"+CHR$(27)+"B"+CHR$(27)+"D"+CHR$(27)+"D"+CHR$(27)+"D"+"def"+CHR$(27)+"B"+CHR$(27)+"D"+CHR$(27)+"D"+CHR$(27)+"D"+"ghi"
20 LOCATE X,Y:PRINT S1$

Código:
10 A$=CHR$(27)+"Y"+CHR$(42)+CHR$(44)+"MSX RULES!!":PRINT A$
Equivalente a LOCATE 12,10:PRINT "MSX RULES!!"

No sólo es más compacto, sino que a poco que tengamos unos cuantos muñecos sacad la cuenta de los LOCATE y PRINT que se ahorran.
En línea

Doom dee doom dee doom
Imanok
Karoshi Hero
*****
Mensajes: 626


« Respuesta #7 : 26 de Enero de 2006, 10:52:18 am »

Hay alguna forma de mostrar por pantalla X patrones (consecutivos en la tabla de patrones) de manera más rápida que vpokeándolos uno por uno (ya sea con un FOR o con X vpokes)??
En línea
pitpan
Karoshi Forum's Guru
*******
Mensajes: 1812


« Respuesta #8 : 26 de Enero de 2006, 11:11:24 am »

Si son consecutivos en la tabla de nombres, lo que hago es inicializar la dirección inicial con un VPOKE y después mandar el resto con OUTs al VDP. Así no hace falta actualizar contadores, porque el registro apuntador de direcciones del VDP se autoincrementa sólo después de recibir cada byte. Pero cuidadín: ni se te ocurra hacer NADA que afecte a la VRAM mientras tanto, porque se volvería majareta.
En línea
Imanok
Karoshi Hero
*****
Mensajes: 626


« Respuesta #9 : 26 de Enero de 2006, 12:32:44 pm »

Si son consecutivos en la tabla de nombres, lo que hago es inicializar la dirección inicial con un VPOKE y después mandar el resto con OUTs al VDP. Así no hace falta actualizar contadores, porque el registro apuntador de direcciones del VDP se autoincrementa sólo después de recibir cada byte

Un ejemplillo, please... imagina que quieres copiar los patrones del 0 al 9, en la posición 0 de la pantalla.

Pero cuidadín: ni se te ocurra hacer NADA que afecte a la VRAM mientras tanto, porque se volvería majareta.

Qué tipo de cosas podrían afectar??... porque cuando copio patrones, hago eso, no puedo hacer otra cosa a la vez...
En línea
pitpan
Karoshi Forum's Guru
*******
Mensajes: 1812


« Respuesta #10 : 26 de Enero de 2006, 02:28:34 pm »

VPOKE&h1800,0:FORI=1TO9:OUT&h98,I:NEXT

Ya veis que uso el máximo de ofuscación disponible. Explicación:

VPOKE&h1800,0: escribe 0 en la posición 6144 de VRAM, habitualmente inicio de la tabla de nombres. Deja el apuntador de memoria del VDP apuntando ya a la posición 6145 (se autoincremente después de cada lectura/escritura).

OUT&h98,I: escribe el valor I en la posición de memoria VRAM a la que apunta actualmente el apuntador del VDP e incrementa en uno nada más terminar.

Resulta más claro con un ejemplo, espero.
En línea
Imanok
Karoshi Hero
*****
Mensajes: 626


« Respuesta #11 : 26 de Enero de 2006, 04:31:00 pm »

Comprendido... de esta forma copias los 10 patrones (uno a uno) en 10 posiciones consecutivas indicando sólo la primera posición... pero se puede hacer que se copien 10 patrones consecutivos indicando sólo el primer patrón de la tabla, en 10 posiciones consecutivas indicando sólo la primera posición?? (es un poco rebuscao...).
En línea
pitpan
Karoshi Forum's Guru
*******
Mensajes: 1812


« Respuesta #12 : 26 de Enero de 2006, 05:18:36 pm »

Pues no sé muy bien a lo que te refieres, pero podría ser algo así:

10 D=6144+32*8+15:P=45:GOSUB1000
...
...
1000 VPOKED,P:FORI=0TO9:P=P+1:OUT&h98,P:NEXT:RETURN

Si no te he entendido mal, claro.  Wink

Otra alternativa - no sé cual sería más rápida - es la siguiente:

1000 VPOKED,P:FORI=1TO9:OUT&h98,P+I:NEXT:RETURN

Ya me dirás.
En línea
Jon_Cortazar
Administrator
Karoshi Forum's God
********
Mensajes: 2777



WWW Email
« Respuesta #13 : 26 de Enero de 2006, 06:13:22 pm »

Sois unos freaks...  Spank
En línea

Jon Cortázar Abraido (aka El Viejo Archivero)
RELEVO Videogames
[Dioniso: La cafeína está haciendo su trabajo; yo espero hacer el mío.]
[pitpan: Me sigue pareciendo más productivo jugar al SNAIL MAZE que seguir esta discusión.]
Imanok
Karoshi Hero
*****
Mensajes: 626


« Respuesta #14 : 27 de Enero de 2006, 08:50:29 am »

Pues no sé muy bien a lo que te refieres, pero podría ser algo así:

10 D=6144+32*8+15:P=45:GOSUB1000
...
...
1000 VPOKED,P:FORI=0TO9:P=P+1:OUT&h98,P:NEXT:RETURN

Si no te he entendido mal, claro.  Wink

No va por ahí la cosa, ya que tu recorres los 10 patrones de la tabla con un FOR. A ver si me explico mejor:

-Imaginemos que tengo un set de patrones completo, con las fuentes de los carácteres en sus lugares correspondientes y tal.
-Imaginemos que yo quiero mostrar por pantalla "ABCDEFGHIJ" (o sea, 10 patrones consecutivos de la tabla) en la posición 6144 de la VRAM (el la posición '0' de la pantalla que vemos, si no lo he puesto mal).
-Se puede hacer lo anterior sin utilizar un bucle, diciéndole de alguna forma "cópiame 10 patrones de la tabla (de la 'A' a la 'J') a partir de la posición 6144 de la VRAM (de la 6144 a la 6153)"??

No se si me explico...
En línea
Páginas: [1] 2 3 ... 5
  Imprimir  
 
Ir a:  

Impulsado por MySQL Impulsado por PHP Powered by SMF 1.1.21 | SMF © 2013, Simple Machines XHTML 1.0 válido! CSS válido!