Jump to content
IGNORED

[IntyBASIC] - Handling an array of strings


GroovyBee

Recommended Posts

Great stuff!

 

Now to take it to the next level, I have about 90 strings. I was going to use macro features of my text editor to wrap everything as you did in the sample, is that the most sensible approach? What I want to do is take a set of strings and scroll them horizontally "up" the screen. I originally thought that I could use an array of strings, but that datatype is not supported I now understand. Here is the look I am trying to go for, except instead of 3 elements, I will have 90 so I need to keep track of the set position so I can hide and show in the visible window.

 

 

post-31694-0-84013100-1481729038_thumb.gif

 

 

 

 

 

 

 

' An array of pointers to strings.
ArrayOfStrings:
data varptr Msg1(0)
data varptr Msg2(0)
data varptr Msg3(0)

' String #1
Msg1:
asm DECLE @@Msg1End-@@Msg1Start
asm @@Msg1Start:
data "Hello"
asm @@Msg1End:

' String #2
Msg2:
asm DECLE @@Msg2End-@@Msg2Start
asm @@Msg2Start:
data "Intellivision"
asm @@Msg2End:

' String #3
Msg3:
asm DECLE @@Msg3End-@@Msg3Start
asm @@Msg3Start:
data "Programmers"
asm @@Msg3End:

 

 

 

 

Thanks for all ideas!

 

 

Find attached a way of handling an array of strings that are each of arbitrary length.

@nanochess: Feel free to add it to the next release of IntyBASIC.

Comments/suggestions?

  • Like 1
Link to comment
Share on other sites

If you have a bunch of strings and you want to select and print them randomly, then an array of strings is the perfect tool.

 

But, if you just want to print a list of strings sequentially to the screen, it seems like overkill! I would suggest:

 

1. Put the strings in one big data list,

2. Use the scroll command to move the screen up.

3. Print the next line at the bottom of the screen.

4. Clear the rest of the bottom line if necessary.

5. Terminate the list with a zero (since the string length would normally not be zero).

 

Done!

 

Here is a quick hacked example:

 

post-14916-0-78728300-1481818989_thumb.gif < click to animate.

 

And the code:

zz.bas

 

Catsfolly

 

 

 

 

 

  • Like 1
Link to comment
Share on other sites

5. Terminate the list with a zero (since the string length would normally not be zero).

This may or may not work depending on how the strings are stored. If you put the strings directly into IntyBASIC data statements then the compiler will automatically subtract 32 from each ASCII value in the string, before putting the value in ROM. Thus a space (" ") will be encoded as a zero and cause early termination. Your version of the TEXT macro uses the AS1600 STRING directive which does no such preprocessing, so in that case, zero is a valid terminator.

Link to comment
Share on other sites

This may or may not work depending on how the strings are stored. If you put the strings directly into IntyBASIC data statements then the compiler will automatically subtract 32 from each ASCII value in the string, before putting the value in ROM. Thus a space (" ") will be encoded as a zero and cause early termination. Your version of the TEXT macro uses the AS1600 STRING directive which does no such preprocessing, so in that case, zero is a valid terminator.

No, I'm not checking each individual character of a string for a zero terminator, only the first element, which is the string length. When I encounter a string of zero length in my list, I assume the list is finished.

  • Like 1
Link to comment
Share on other sites

No, I'm not checking each individual character of a string for a zero terminator, only the first element, which is the string length. When I encounter a string of zero length in my list, I assume the list is finished.

 

That's how I handle strings as well. The length is on the first byte of the string array, and it must not be zero. Therefore a zero word will mark the end of the strings table.

 

-dZ.

  • Like 1
Link to comment
Share on other sites

Is it possible to only scroll the right half of the screen with this technique? I want to keep columns 0-10 static because I have another image to show there. The docs and contrib\scroll.bas both seem to indicate that scrolling is a whole screen affair (I can't think of an Inty game that doesn't scroll the whole screen actually).

 

Thanks.

 

If you have a bun[snip]

Catsfolly

 

 

 

 

 

Edited by First Spear
  • Like 1
Link to comment
Share on other sites

As far as I understand, the STIC registers are updated during VBL so when it comes to scrolling it is all or nothing. Thus some people have discussed methods to "counter-scroll" items that are supposed to be static on screen, but doing that for 10 columns times 12 rows may be very cumbersome, if possible at all.

  • Like 1
Link to comment
Share on other sites

Is it possible to only scroll the right half of the screen with this technique? I want to keep columns 0-10 static because I have another image to show there. The docs and contrib\scroll.bas both seem to indicate that scrolling is a whole screen affair (I can't think of an Inty game that doesn't scroll the whole screen actually).

 

Thanks.

 

This example uses the "scroll" command to move the text up on the screen. The scroll command operates on the whole screen.

 

To scroll only the right half of the screen, you would have to write a routine to move the text up on the screen that operates only on the right half of the screen.

 

This could be written in IntyBasic, but without trying it I don't know if it would be fast enough - maybe an assembly routine would be necessary. I have to get ready for work, so I can't try it now...

 

We are talked about "crude scrolling" in this case (scrolling 8 bits at a time, like the example code). "Smooth scrolling" (1 bit at a time) can only happen on the whole screen.

 

If you can live with "crude scrolling" (on the Colecovision it's the only kind of scrolling they have), then there is no reason not to have independent scrolling windows on the Intellivision...

 

post-14916-0-44776800-1481930524.gif

 

Catsfolly

  • Like 2
Link to comment
Share on other sites

Solved the problem just using IntyBASIC commands :-

attachicon.gifArrayOfStrings.bas

 

 

 

 

But that still packs the strings one byte per DECLE. I think we can get away with packing them two per decle using additional macros. The "Print" routine would have to be smart enough to unpack during output.

 

I have macros and routines for this in Assembly. Would they be worth translating/wrapping to work with IntyBASIC?

 

-dZ.

Link to comment
Share on other sites

But that still packs the strings one byte per DECLE. I think we can get away with packing them two per decle using additional macros. The "Print" routine would have to be smart enough to unpack during output.

 

I have macros and routines for this in Assembly. Would they be worth translating/wrapping to work with IntyBASIC?

 

-dZ.

 

Hi dZ. I hacked modified GroovyBee's code to print packed strings, also in 100% IntyBasic.

 

It's specifically for packed strings, I can't think of an easy way to tell string types apart. Maybe by also storing sizeof(), or, terminating with $FF, and check if LEN()/2 points to it.

 

 

include "constants.bas"

'---- string is packed in 8-bit pairs. Data len(aString) is the string length, not size in memory
def fn TEXTPACKED(aString) = data len(aString): data packed aString

'---- packed strings ------
' Print the 1st packed string.
index=0			' The index of the packed string we are interested in.
#where=SCREENADDR(0,4)	' Where the packed string is going to on the screen.
colour=CS_WHITE        	' The string colour (Note: Only first 8 colours are allowed).
gosub PrintStringPacked	' Print the packed string on the screen.

' Print the 2nd packed string.
index=1
#where=SCREENADDR(0,5)
colour=CS_TAN
gosub PrintStringPacked

' Print the 3rd packed string.
index=2
#where=SCREENADDR(0,6)
colour=CS_BLUE
gosub PrintStringPacked

loop:
wait
goto loop
	
REM -------------------------------------------------------------------------
PrintStringPacked: procedure

' Get the start address in ROM of the string we need.
#addr=ArrayOfStringsPacked(index)

' Get the size of the packed string
length=peek(#addr)
#addr=#addr+1

' Print the packed string on screen.
WHILE length<>0		
	#data=peek(#addr)			' Get 16-bit value
	
	poke #where,(#data/256)*8+colour	' Write 1st 8-bit value to BACKTAB. (MSB)
	#where=#where+1				' Move to the next position on screen.
	
	length=length-1
	IF length=0 THEN EXIT WHILE		' Finished? Exit..
	
	poke #where,(#data AND $FF)*8+colour	' Write 2nd 8-bit value (LSB)
	#where=#where+1				' Move to the next position on screen.
	
	#addr=#addr+1				' Move to the next character location in ROM.
	length=length-1
WEND

end
REM -------------------------------------------------------------------------
REM PrintStringPacked - END

' An array of pointers to packed strings.
ArrayOfStringsPacked:
data varptr Msg1P(0)
data varptr Msg2P(0)
data varptr Msg3P(0)

' String #1
Msg1P:
TEXTPACKED("Hello Again")

' String #2
Msg2P:
TEXTPACKED("Intellivision")

' String #3
Msg3P:
TEXTPACKED("Programmers!")

 

 

 

  • Like 4
Link to comment
Share on other sites

Hi dZ. I hacked modified GroovyBee's code to print packed strings, also in 100% IntyBasic.

 

It's specifically for packed strings, I can't think of an easy way to tell string types apart.

 

Why would you need to? Assume that calling PrintStringPacked() will be called with a packed string, and Bob's your uncle.

 

Unless you mean how to know when a string ends and another one begins? Storing the length on the first byte allows you to know how long your loop is. The string index table will take care of the beginning pointer for each string.

 

-dZ.

Link to comment
Share on other sites

Is it possible to only scroll the right half of the screen with this technique? I want to keep columns 0-10 static because I have another image to show there.

If the left side image is reasonably simple and uses MOBs for colour highlights then you can prepare vertically pre-shifted graphics in GRAM and use those while scrolling the whole screen up pixel by pixel.

Link to comment
Share on other sites

 

Why would you need to? Assume that calling PrintStringPacked() will be called with a packed string, and Bob's your uncle.

 

Unless you mean how to know when a string ends and another one begins? Storing the length on the first byte allows you to know how long your loop is. The string index table will take care of the beginning pointer for each string.

 

-dZ.

 

Oh, I meant just having one PrintString function that prints them all. (both packed and unpacked). I already used PrintStringPacked() with the wrong non-packed strings...

Link to comment
Share on other sites

 

Oh, I meant just having one PrintString function that prints them all. (both packed and unpacked). I already used PrintStringPacked() with the wrong non-packed strings...

 

Ah. Maybe that wouldn't be practical, unless you reserve a high-order bit of the first byte to mark the format, or something like that. You could also store meta-data in the string index table, along with the starting pointer.

 

-dZ.

Link to comment
Share on other sites

The sound of half a screen scrolling:

 

Here is a hack of my hack to just scroll half of the screen.

 

(Note: I have not updated my strings yet to GroovyBee's latest format yet.)

 

 

attachicon.gifmvi_0080.gif <- click to animate

 

Source code:

 

attachicon.gifzzz.bas

 

Catsfolly

 

 

Nice. Now try it with smooth scrolling, by counter-scrolling the "nice picture." ;)

  • Like 1
Link to comment
Share on other sites

  • 1 month later...

I am playing with some the variables, trying to define the beginning and ending column for the string. All of my strings are 8 characters in length exactly.

I do not understand the relationship between the #where variable and the BACKTAB_ADDR. Can you help me get a clue?

 

 

Thanks.

printloop:
	wait
	#addrs = BACKTAB_ADDR + 10
	for c = 0 to 10
		poke #addrs   , peek(#addrs + 20)	
		poke #addrs+1 , peek(#addrs + 21)	

		poke #addrs+2 , peek(#addrs + 22)	
		poke #addrs+3 , peek(#addrs + 23)	

		poke #addrs+4 , peek(#addrs + 24)	
		poke #addrs+5 , peek(#addrs + 25)	

		poke #addrs+6 , peek(#addrs + 26)	
		poke #addrs+7 , peek(#addrs + 27)	

		poke #addrs+8 , peek(#addrs + 28)	
		poke #addrs+9 , peek(#addrs + 29)
		#addrs = #addrs + 20	

	next c
	
	length = Msgs(#string_index)

	if length = 0 then goto restart
	#string_index = #string_index + 1
	#where = BACKTAB_ADDR + (11 * 20) + 10
	for  c=1 to length
		#data=((Msgs(#string_index) - 32) * 8 )+colour	' Get the character
		poke #where,#data  
		#string_index = #string_index+1
		#where = #where+1
	next c
	rem clear the rest of the line
zfill:
	if (c < 21) then poke #where,0 : c = c + 1 : #where = #where + 1 : goto zfill
	for c = 0 to 50	
		wait
		
	next c
	goto printloop

The sound of half a screen scro[snip]

 

  • Like 1
Link to comment
Share on other sites

 

I am playing with some the variables, trying to define the beginning and ending column for the string. All of my strings are 8 characters in length exactly.

I do not understand the relationship between the #where variable and the BACKTAB_ADDR. Can you help me get a clue?

 

 

Thanks.

printloop:
	wait
	#addrs = BACKTAB_ADDR + 10
	for c = 0 to 10
		poke #addrs   , peek(#addrs + 20)	
		poke #addrs+1 , peek(#addrs + 21)	

		poke #addrs+2 , peek(#addrs + 22)	
		poke #addrs+3 , peek(#addrs + 23)	

		poke #addrs+4 , peek(#addrs + 24)	
		poke #addrs+5 , peek(#addrs + 25)	

		poke #addrs+6 , peek(#addrs + 26)	
		poke #addrs+7 , peek(#addrs + 27)	

		poke #addrs+8 , peek(#addrs + 28)	
		poke #addrs+9 , peek(#addrs + 29)
		#addrs = #addrs + 20	

	next c
	
	length = Msgs(#string_index)

	if length = 0 then goto restart
	#string_index = #string_index + 1
	#where = BACKTAB_ADDR + (11 * 20) + 10
	for  c=1 to length
		#data=((Msgs(#string_index) - 32) * 8 )+colour	' Get the character
		poke #where,#data  
		#string_index = #string_index+1
		#where = #where+1
	next c
	rem clear the rest of the line
zfill:
	if (c < 21) then poke #where,0 : c = c + 1 : #where = #where + 1 : goto zfill
	for c = 0 to 50	
		wait
		
	next c
	goto printloop

 

BACKTAB_ADDR is the address of the data that will appear at the upper left hand corner of the tv screen.

 

#where = BACKTAB_ADDR would point to the upper left hand corner data.

 

Since there are 20 characters across on the Intellivision display, the next row of characters would start at:

#where = BACKTAB_ADDR + 20

 

The next row of characters would start at:

#where = BACKTAB_ADDR + 40

 

So, in general, the address of the first character in a row would be (assuming that the top row is row 0):

#where = BACKTAB_ADDR + (row_number * 20)

 

In the code above we have the line:

 

#where = BACKTAB_ADDR + (11 * 20) + 10

 

This points to the 11th row, starting at the 10th character. This is at the very end of the screen memory, so if your code writes more than 10 characters starting at this position (which it appears to do) , it will corrupt memory beyond the end of the backtab memory, which could cause the program to crash.

 

Does this help?

 

Catsfolly

 

 

P.S. Constants.bas has a nice macro that does the calculations automatically:

#where = screenadrs(10,11)

The first number is the column and the second number is the row..

Edited by catsfolly
  • Like 1
Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...