Jump to content

Photo

looking for faster method to check for blank spaces


30 replies to this topic

#1 pmgraphics OFFLINE  

pmgraphics

    Space Invader

  • 49 posts

Posted Wed May 8, 2019 5:09 PM

I have a game program using graphics mode1. I want to check after each level is there are less than 35 blank spaces on the screen. My code below works but it is slow. Is there a quicker way in basic to do the same thing?

 

500 SPC=0:WIN=0
510 FOR RD=1 TO 18:FOR RB=1 TO 22
515 SETCOLOR 0,1+RD/2,1+RB/2
520 CHK=SCREEN+RD+20*RB:IF PEEK(CHK)=0 THEN SPC=SPC+1
530 NEXT RB:NEXT RD
540 IF SPC<35 THEN WIN=1:GOTO 800
 
Thanks


#2 flashjazzcat ONLINE  

flashjazzcat

    Quadrunner

  • 14,611 posts
  • Location:United Kingdom

Posted Wed May 8, 2019 5:14 PM

It's difficult to perform iterations like these quickly in BASIC. Can you not keep a running tally of blank spaces rather than counting them up at the end? Presumably you know how many spaces exist at the start of a level, so when a space is revealed or overwritten, you could update the running total.

#3 NuY OFFLINE  

NuY

    Chopper Commander

  • 226 posts

Posted Wed May 8, 2019 5:45 PM

No idea if speed will increase with these but the code will be shorter:

 

1. This can be done in one FOR loop and line 520 simplified:

510 FOR RD=SCREEN+1 TO SCREEN+496
520 IF PEEK(RD)=0 THEN SPC=SPC+1
530 NEXT RB:NEXT RD
 
2. Use Boolean expression to increment the counter, so the IF in line 520 becomes:
 
SPC=SPC+1*(PEEK(CHK)=0)
 
3. POP the FOR loops if the count reaches 35 or more, seeing as less than 35 is the win condition - if more are counted then there's no need to count the rest (unless you use that count elsewhere).
 
All the above can be combined of course.

Edited by NuY, Wed May 8, 2019 5:45 PM.


#4 pmgraphics OFFLINE  

pmgraphics

    Space Invader

  • Topic Starter
  • 49 posts

Posted Wed May 8, 2019 7:34 PM

It's almost working. When I know there is only 34 blank spaces on the screen. The code reports that SPC = 51 crating an infinite loop elsewhere in the code since there are only 34 spaces and it is trying to do something with 35 spaces that it thinks are on the screen.

500 SPC=0:WIN=0
510 FOR RD=SCREEN+1 TO SCREEN+496
515 REM SETCOLOR 0,1+SPC/3,10
520 SPC=SPC+1*(PEEK(RD)=0)
530 NEXT RD
540 IF SPC<34 THEN WIN=1:GOTO 800


#5 pmgraphics OFFLINE  

pmgraphics

    Space Invader

  • Topic Starter
  • 49 posts

Posted Wed May 8, 2019 8:13 PM

I got it working. I changed SCREEN+496 to SCREEN+458 and using your code seems made it about 3 seconds quicker.

I don't know why not including the screen border, which has no spaces and calculating the following SCREEN+(18+20*22) works.

 

Thanks.

 

>flashjazzcat: I can't explain it but tracking the spaces wouldn't work well.


Edited by pmgraphics, Thu May 9, 2019 7:53 PM.


#6 Rybags ONLINE  

Rybags

    Gridrunner

  • 16,146 posts
  • Location:Australia

Posted Fri May 10, 2019 7:00 AM

Already mentioned but -

 

You have a SETCOLOR with embedded calculations inside the loop - that alone is adding heaps of overhead.

Rule #1 is keep unnecessary stuff out of such loops, do precalculations once wherever possible.

 

The logic method you have there is almost right.  No need to multiply by 1.

 

520 SPC=SPC+(PEEK(RD)=0)



#7 pmgraphics OFFLINE  

pmgraphics

    Space Invader

  • Topic Starter
  • 49 posts

Posted Fri May 10, 2019 8:49 AM

I have the setcolor in the loop to give the player some feedback, while the game searches for blank spaces, opposed to an apparent frozen screen. I removed the 1* thanks.

 

Prior to removing 1* and setcolor it took 12-13 seconds to search for the blank spaces

Removing the 1* saved 1 second

Removing the setcolor saved almost 6 seconds, but then the player is staring at a non-responsive screen for about 7 seconds. It's a toss up to have something to look at over saving 6 seconds before the next level starts.


Edited by pmgraphics, Fri May 10, 2019 10:34 AM.


#8 danwinslow OFFLINE  

danwinslow

    River Patroller

  • 2,595 posts

Posted Fri May 10, 2019 9:11 AM

It's been a long time since I did any BASIC, but I think you can dim a string and then go into the symbol table and mess with the address such that BASIC thinks it is at the screen data location. Maybe that would allow faster processing, but not sure. I do think it would be pretty easy to have a small USR routine (with or without the string manipulation above) that would be REALLY fast.



#9 Rybags ONLINE  

Rybags

    Gridrunner

  • 16,146 posts
  • Location:Australia

Posted Fri May 10, 2019 7:32 PM

You could save a bit more time by putting the entire loop within a single Basic line - there's a bit of processing overhead every time a new line starts.

Also, there's plenty of saving by having the loop near the beginning of your program instead of in the middle.

In fact, with Atari Basic it's good practice to put all loops and subs that need extra speed help near the start of program, and just put a GOTO at the start to skip over them.



#10 Nukey Shay OFFLINE  

Nukey Shay

    Sheik Yerbouti

  • 21,967 posts
  • Location:The land of Gorch

Posted Sat May 11, 2019 6:43 AM

USR routine:

  pla
  lda #0
  sta $D4
  sta $D5
  ldx #$E4
loop:
  lda screen,x
  bne notblank
  inc $D4
  bcc notblank
  inc $D5
notblank:
  lda screen+$E4,x
  bne notblank2
  inc $D4
  bcc notblank2
  inc $D5
notblank2:
  dex
  bne loop
  rts

Just POKE in the 16 bit values for screen and screen+$E4.  You can execute it right from a string (does not need DIMensioning).

The value returned is the number of spaces.  Note: if that number will always be less than 256, the bcc/inc$D5 lines can be removed.


Edited by Nukey Shay, Sat May 11, 2019 7:42 AM.


#11 Nukey Shay OFFLINE  

Nukey Shay

    Sheik Yerbouti

  • 21,967 posts
  • Location:The land of Gorch

Posted Sat May 11, 2019 9:26 AM

Creating a USR routine within an undimensioned string:

Just run a short program that prints the CHR$ translation of the opcodes...

 

atari001.jpg

 

Position the cursor on the printed text and hit enter to add the line to the program.

Lines 200 - 240 would be what you use in your actual program (or wherever you initially set the GFX mode).

 

Useage from then on: SPC=USR(A)

 

It'll count them in a flash, so you can kill time with a loop with your setcolor instruction if you want a moment or three to pass.


Edited by Nukey Shay, Sat May 11, 2019 10:00 AM.


#12 danwinslow OFFLINE  

danwinslow

    River Patroller

  • 2,595 posts

Posted Sat May 11, 2019 10:38 AM

Nice :) ^



#13 ricortes OFFLINE  

ricortes

    Dragonstomper

  • 688 posts

Posted Sat May 11, 2019 2:49 PM

Fairly easy to return the value too if you are up for it i.e.

X=USR...

X can and ~does return an integer. Usually just a zero unless you specifically stuff a value to it.



#14 Nukey Shay OFFLINE  

Nukey Shay

    Sheik Yerbouti

  • 21,967 posts
  • Location:The land of Gorch

Posted Sat May 11, 2019 3:11 PM

The above routine does.  The value returned for USR is whatever exists at $D4/$D5 (decimal 212 & 213).

 

USR routines can also pass 16 bit arguments the other way.  That is why they require a PLA instruction to start out...that is the number of arguments used in the USR command being pulled off the stack.  The rest are pulled off in reverse order (MSB first, then LSB).



#15 pmgraphics OFFLINE  

pmgraphics

    Space Invader

  • Topic Starter
  • 49 posts

Posted Sat May 11, 2019 11:47 PM

USR routine:

  pla
  lda #0
  sta $D4
  sta $D5
  ldx #$E4
loop:
  lda screen,x
  bne notblank
  inc $D4
  bcc notblank
  inc $D5
notblank:
  lda screen+$E4,x
  bne notblank2
  inc $D4
  bcc notblank2
  inc $D5
notblank2:
  dex
  bne loop
  rts

Just POKE in the 16 bit values for screen and screen+$E4.  You can execute it right from a string (does not need DIMensioning).

The value returned is the number of spaces.  Note: if that number will always be less than 256, the bcc/inc$D5 lines can be removed.

I never got beyond basic as a kid. It would be great to learn how and what to do with the above.



#16 Nukey Shay OFFLINE  

Nukey Shay

    Sheik Yerbouti

  • 21,967 posts
  • Location:The land of Gorch

Posted Sun May 12, 2019 4:07 AM

The Basic routine in the screenshot above puts it in memory. It is relocatable, so you can POKE it into page 6 if you want to.

 

"Page 6"...i.e. the 256-byte area of memory starting at hex address $600 (1536 decimal), is left alone by Atari Basic and DOS...so you can place small machine-language programs there without worry of corruption.

 

To use page 6 instead, change the following lines:

 

5 A = 1536

30 POKE 1535+I,J

 

Erase lines 50 and 60, and there you go.

You can still call the routine via SPC=USR(A)

Or just use SPC=USR(1536) if you don't want to burn a variable name in the main program.

 

There's a thread around here someplace that has a disk image with a lot of small USR routines like these you can use to *drastically* speed up Basic bottlenecks (like moving P/M stuff around and such).



#17 Nukey Shay OFFLINE  

Nukey Shay

    Sheik Yerbouti

  • 21,967 posts
  • Location:The land of Gorch

Posted Sun May 12, 2019 4:55 AM

Found it

http://atariage.com/...c-turbocharger/

 

The author used character codes in strings tho, which are really hard to make out in print.  The disk images of all the routines were included in the Holmes archives...MrFish reposted them here (reply 14)

http://atariage.com/...ic-subroutines/



#18 pmgraphics OFFLINE  

pmgraphics

    Space Invader

  • Topic Starter
  • 49 posts

Posted Sun May 12, 2019 7:18 PM

I created line 200 with the ADR string. Do I replace line 520 with your lines 200 - 240? What if I want to make a change in the number of spaces to find (as in line 540) or find a different character?

500 SPC=0:WIN=0
510 FOR RD=SCREEN+1 TO SCREEN+458
515 SETCOLOR 0,SPC/3,9
520 SPC=SPC+(PEEK(RD)=0):IF SPC>35 THEN 610
530 NEXT RD
540 IF SPC<=34 THEN WIN=1:GOTO 2000


#19 Nukey Shay OFFLINE  

Nukey Shay

    Sheik Yerbouti

  • 21,967 posts
  • Location:The land of Gorch

Posted Mon May 13, 2019 4:27 AM

"Do I replace line 520 with your lines 200 - 240?"

Pay no attention to the line numbers I used...those were there just to keep the instructions sequential.

If you are using the string, you need to add a line (or lines) containing those POKE instructions -after- you set the graphics mode.  Those 4 POKE instructions set the screen address that the string uses to check for characters.

 

Once that is set up, your line 500 should read as follows:

500 WIN=0:SPC=USR(A)

Lines 510, 515, 520, and 530 are no longer needed.  The machine-language USR routine is replacing the job that loop was doing.

 

 

"What if I want to make a change in the number of spaces to find (as in line 540)"

Just change the 34 in line 540 to whatever the WIN condition is.  The USR routine is just counting the total.

 

 

"or find a different character?"

That would need a different routine...this is just checking for zeros (spaces).

 

  pla
  lda #0
  sta $D4
  sta $D5
  ldx #$E4
loop:
  lda screen,x
cmp #char
  bne notblank
  inc $D4
  bcc notblank
  inc $D5
notblank:
  lda screen+$E4,x
cmp #char
  bne notblank2
  inc $D4
  bcc notblank2
  inc $D5
notblank2:
  dex
  bne loop
  rts

 

4 bytes longer.  Notice the difference?



#20 Nukey Shay OFFLINE  

Nukey Shay

    Sheik Yerbouti

  • 21,967 posts
  • Location:The land of Gorch

Posted Mon May 13, 2019 4:42 AM

Better yet, you could make a generic routine so you can use the USR command a bunch of times to check for different types of characters...

  pla
  lda #0
  sta $D4
  sta $D5
  pla
  pla
  ldx #$E4
loop:
  cmp screen,x
  bne notblank
  inc $D4
  bcc notblank
  inc $D5
notblank:
  cmp screen+$E4,x
  bne notblank2
  inc $D4
  bcc notblank2
  inc $D5
notblank2:
  dex
  bne loop
  rts

That routine is adding an argument to the USR routine.  You'd use the PEEK value of whatever character you are searching for within the USR command itself.  To search for ! characters, you'd do this:

TOTAL=USR(A,1)

 

Checking for spaces in this case would be:

SPC=USR(A,0)

 

Do you want to see a string to use that method instead?


Edited by Nukey Shay, Mon May 13, 2019 4:51 AM.


#21 pmgraphics OFFLINE  

pmgraphics

    Space Invader

  • Topic Starter
  • 49 posts

Posted Mon May 13, 2019 12:56 PM

It would be great to have a routine that could search for any character. Thanks.

 

BTW: I added the string line and the four POKE instructions after my GR.17 at the top of my program. I get an ERROR 3 (Global variable symbol table full) when I run the program. Prior to it being run is my GOSUB to my character redefining instructions.

 

Update to Error 3:

I removed the +228 from line 230. I don't know what it means but it seemed out of place. Doing so resulted in no error 3 and the blank spaces were tallied very fast.


Edited by pmgraphics, Mon May 13, 2019 9:35 PM.


#22 Nukey Shay OFFLINE  

Nukey Shay

    Sheik Yerbouti

  • 21,967 posts
  • Location:The land of Gorch

Posted Tue May 14, 2019 2:29 AM

Similar oddities on this end...for some reason, branching instruction BCC refused to work properly.  No matter...I'll work around it!

 

Generic screen check program:

This uses 4 zero-page locations...203/204 to save the base address, 205/206 for the number of bytes to check

The program got a little longer due to the BCC problem, but it works (52 bytes total).

You can put it in a string or wherever you want.  No additional POKEs needed, so you can throw those lines away.

 
  pla           ;pull # of arguments

  pla           ;set start address

  sta 204

  pla

  sta 203

  pla           ;set # of bytes

  sta 206

  pla

  sta 205

  pla           ;set char to look for

  pla           ;   (LSB only)

  ldy #0        ;clear counter

  sty 212

  sty 213

  ldx #255      ;used for rollover check

loop

  cmp (203),y   ;current pos = character

  bne nomatch   ;branch if no

  inc 212       ;increase counter

  bne nomatch   ;branch if no rollover

  inc 213       ;increase counter*256

nomatch:

  inc 203       ;move to next byte to check

  bne bumpindex ;branch if no rollover

  inc 204       ;bump MSB of next byte to check

bumpindex

  dec 205       ;decrease the number of bytes left

  cpx 205

  bne loop

  dec 206

  cpx 206

  bne loop

  rts          ;no bytes left, return

;52 bytes total
 
DATA 104,104,133,204,104,133,203,104,133,206

DATA 104,133,205,104,104,160,0,132,212,132

DATA 213,162,255,209,203,208,6,230,212,208

DATA 2,230,213,230,203,208,2,230,204,198

DATA 205,228,205,208,234,198,206,228,206,208

DATA 228,96

Usage: var=USR(ProgramAddress,StartAddress,NumberOfBytes,Char)

 

as in...

SPC=USR(1536,SCREEN,458,0)

if the program is in page 6, SCREEN=PEEK(88)+256*PEEK(89), check 458 bytes total, look for character 0 (spaces)

 

atari003.jpg



#23 pmgraphics OFFLINE  

pmgraphics

    Space Invader

  • Topic Starter
  • 49 posts

Posted Tue May 14, 2019 10:05 AM

After I create the string do I assign it to a variable like the first example as in A=ADR(" ...the new string.. ") just after the graphics mode set?

In the usage example how do I then include the string in the SPC=USR(1536,SCREEN,458,0) line?

 

PS: I did not thoroughly test the first routine that only tallies spaces. When I knew there was about 90 spaces, SPC=USR(A) returned a value under 10. To test I created a scenario where there was 329 spaces each time, and SPC=USR(A) returned only 50, then 48, then 46, then 46, then 54. It seems the first routine is not calculating the correct number of blank spaces, or I have done something wrong. My code is below

 

dViEOR5.png

 

sRLGaWT.png


Edited by pmgraphics, Tue May 14, 2019 1:16 PM.


#24 pmgraphics OFFLINE  

pmgraphics

    Space Invader

  • Topic Starter
  • 49 posts

Posted Tue May 14, 2019 1:14 PM

I used the any character method in my code as follows, by replacing the 1536 in the USR statement with the variable A (seemed most logical to do).

5 GR.17:SCO=0:LI=6:GARD=0:SPC=0:ME=0
7 A=ADR("...the new string for any character...")
10 POKE 756,CH/256:SCREEN=PEEK(88)+256*PEEK(89):GOTO 600

500 SPC=USR(A,SCREEN,458,0):WIN=0
505 POSITION 0,23:? #6;SPC
510 FOR COL=0 TO 35:SETCOLOR 0,COL/3,9:NEXT COL
540 IF SPC<=34 THEN WIN=1:GOTO 2000
550 GOTO 610
 
Running the similar condition of 319 blank spaces, SPC=USR(A,SCREEN,458,0) always returns a count of 319. Looks like this method is working. :)

Edited by pmgraphics, Tue May 14, 2019 1:20 PM.


#25 sanny ONLINE  

sanny

    Moonsweeper

  • 396 posts
  • Location:Bavaria

Posted Tue May 14, 2019 3:20 PM

...for some reason, branching instruction BCC refused to work properly.  No matter...I'll work around it!

 

BCC probably works as it should, but INC doesn't change the carry flag...






0 user(s) are browsing this forum

0 members, 0 guests, 0 anonymous users