banks, types, and arrays

Blitz3D Forums/Blitz3D Beginners Area/banks, types, and arrays

I have some code that basically uses 3-4 arrays each about 10,000 units in length. I have about 50 objects of one type, all cubes. I basically cycle through each type object, doing what I need to, then clearing the arrays. I want to store the arrays for each object independently now, but could not figure out how to create arrays in type fields. Is there a way to do this? Is it better/easier to after each one store the array in a bank, then load it at the beginning? Is it faster just to use banks for the whole thing?

Just as a side note, all of the arrays are related, one being a binary heap and the others giving more information about the items in the binary heap.

You can use non-dynamic one-dimensional 'Blitz' arrays inside Type objects:
Type blah
Field hurray[20] ;square brackets
End Type

..but if you want dynamism then banks might be better.

Thanks beaker! By non-dynamic do you mean they can't change shape or is it like a constant, you can't change the value once you give it one?

It means you can't resize them. You can change their contents as often as you like, though.

Why does blitz have two array formats? Why not combine them into one? Is there a specific difference between them (like speed) other than one can be resized but can't go in a type field while the other can't be resized but can go in a type field?

One is legacy BASIC style, the other is more flexible (apart from the things already mentioned) - ie. you can hold them in types, make them local, pass them to functions etc.

Thanks beaker and big10p for all your help. It really cleared up a lot about arrays!

An alternative for storing containers (lists of things, including arrays) in objects

I can't reccomened octothorpes container classes enough!

Alternatively you could use a array in bank system like mine below, which Octothorpe also helped me with (you're the man!).

;Multi-dimensional array object using banks.
Type array
    Field BankHND%     ;Memory bank handle.
    Field Dim1%        ;Size of first array element.
    Field Dim2%        ;Size of second array element.
    Field Dim3%        ;Size of third array element.
    Field Dim4%        ;Size of fourth array element.
    Field Dim5%        ;Size of fifth array element.
End Type

Function array_Create.array( nDim1%, nDim2%=1, nDim3%=1, nDim4%=1, nDim5%=1 )

	Local Err$ = "Invalid dimension size specified in array_Create()"
	Assert( nDim1%>0, Err$ ):Assert( nDim2%>0, Err$ ):Assert( nDim3%>0, Err$ )
	Assert( nDim4%>0, Err$ ):Assert( nDim5%>0, Err$ )

	Local nArray.array	= New array
	nArray\Dim1%		= nDim1
	nArray\Dim2%		= nDim2
	nArray\Dim3%		= nDim3
	nArray\Dim4%		= nDim4
	nArray\Dim5%		= nDim5
	nArray\BankHND%		= CreateBank( ( nDim1 *nDim2 *nDim3 *nDim4 *nDim5 ) *4 )
	Return nArray
End Function

Function array_Destroy%( this.array )
	Assert( Not this=Null, "Null 'array' object in array_Destroy()" )
	FreeBank( this\BankHND% )
	Delete this
End Function

Function array_Copy.array( this.array )
	Assert( Not this=Null, "Null 'array' object in array_Copy()" )

	Local nArray.array = New array
	Local Size% = BankSize( this\BankHND% )

	nArray\Dim1%	= this\Dim1%
	nArray\Dim2%	= this\Dim2%
	nArray\Dim3%	= this\Dim3%
	nArray\Dim4%	= this\Dim4%
	nArray\Dim5%	= this\Dim5%
	nArray\BankHND%	= CreateBank( Size% )
	CopyBank( this\BankHND%, 0, nArray\BankHND%, 0, Size% )
	Return nArray
End Function

Function array_WriteVal%( this.array, nValue%, nDim1%, nDim2%=0, nDim3%=0, nDim4%=0, nDim5%=0 )
	Assert( Not this=Null, "Null 'array' object in array_WriteVal()" )
	Local nOffset% = array_GetOffset( this, nDim1%, nDim2%, nDim3%, nDim4%, nDim5% )
	PokeInt( this\BankHND%, nOffset% *4, nValue% )
End Function

Function array_ReadVal%( this.array, nDim1%, nDim2%=0, nDim3%=0, nDim4%=0, nDim5%=0 )
	Assert( Not this=Null, "Null 'array' object in array_ReadVal()" )
	Local nOffset% = array_GetOffset( this, nDim1%, nDim2%, nDim3%, nDim4%, nDim5% )
	Return PeekInt( this\BankHND%, nOffset% *4 )
End Function

;Implementation function only.
Function array_GetOffset%( this.array, nDim1%, nDim2%, nDim3%, nDim4%, nDim5% )
	Assert( Not this=Null, "Null 'array' object in array_GetOffset()" )

	Local Error = False
	If nDim1% >= this\Dim1% Then Error = True
	If nDim2% >= this\Dim2% Then Error = True
	If nDim3% >= this\Dim3% Then Error = True
	If nDim4% >= this\Dim4% Then Error = True
	If nDim5% >= this\Dim5% Then Error = True

	Assert( Error=False, "Array index out of bounds!" )

	Local nOffset% = nDim1%
	nOffset% = nOffset% +nDim2% *this\Dim1%
	nOffset% = nOffset% +nDim3% *this\Dim2%
	nOffset% = nOffset% +nDim4% *this\Dim3%
	nOffset% = nOffset% +nDim5% *this\Dim4%
	Return nOffset%
End Function


You'll also need this:
Function Assert( Condition%, Message$ )
        If not Condition% then RunTimeError( Message$ )
End Function


How fast is pokeint and peekint compared to using arrays with brackets? From what I know this is slower, but am unsure. I originally tried to implement something like this, but got so bogged down...this would have helped alot

I'm pretty certain it's slightly slower, but the advantage is that you can have multi-dimensional arrays within types, or local arrays etc...

for 2d arrays I have just been saveing it to a 1d array using the equation (arraywidth*y)-(arraywidth-x). with x and y being the 2d coordinates to store in the 1d array. To convert from 1d to 2d: y = ceil(n/arraywidth)
temp = ((ceil(n/arraywidth))-(floor(n/arraywidth)))
x = arraywidth-temp
This makes it so if you go left to right for each row, it goes
1 2 3 4 5
6 7 8 9 10...

Would using this method of converting 2d to 1d and back again be faster than the posts above?

Thanks for the praise, Jams. :)

mindstorms: Yes, because you're avoiding two function calls, any and all error checking, and index calculations for dimensions you're not using. Also, I've heard banks are slow - although I suspect and hope this is only in Debug mode.

By the way, if you use integer math you can simplify your 1d-to-2d index calculations:

x% = n% mod width%
y% = n% / width%

And why isn't your 2d-to-1d index calculation simply:

n% = x% + y% * width%

Octothorpe: the equation is (arraywidth*y)-(arraywidth-x). Say you have a "2d array" stored as a 1d array that is 5x5. It would look something like this:

1 2 3 4 5
|_____________
1 | 1 2 3 4 5
2 | 6 7 8 9 10
3 |11 12 13 14 15
4 |16 17 18 19 20
5 |21 22 23 24 25
(the numbers won't line up... it automatically takes away extra spaces when posting)

say you have 2d coord of 4,3 that need to be changed to 1d coord. with your way it is 4+3*5 = 19, this is not right. It is 5 units too far. The correct equation is (x+y*width)-width. Using the commutative property, you can change this to (y*width)-(width-x), which is easier for me to understand, so I use that form.

For your 2d to 1d y, it can't be y = n/width, because this will return the wrong number when it rounds down. You need the program to round up to make the y valid, which is accomplished with ceil.

Thanks for the mod one, It is alot shorter than my way. In fact, my code for doing it is basicaly the math for mod, all written out. I am unsure of which is faster, though. Probably mod. Thanks!

Arrays start at zero :)

     0  1  2  3  4
  +----------------
0 |  0  1  2  3  4
1 |  5  6  7  8  9
2 | 10 11 12 13 14
3 | 15 16 17 18 19
4 | 20 21 22 23 24


The calculations I gave above are the standard way to treat a 1d array like a 2d array. That's exactly what languages which support multi-dimensional arrays instrinsicly do under the hood (optionally with some bounds-checking.)

I think a modulo operation only takes one cpu instruction. Converting ints to floats, rounding them, then converting them back would take a few.

If you insist on doing things your way, I would think this version of your equation would make more sense: n% = x% + (y% - 1) * width%

I'm sorry, I forgot to tell you that I completely ignore the zero spot and start right on 1. I then dim them 1 (2d) or 2 (1d) longer than they need to be. This means that I start the boxes at the second row and column, ignoring both.

      0  1  2  3  4  5
    +------------------
0   | -  -  -  -  -  -
1   | -  1  2  3  4  5
2   | -  6  7  8  9 10
3   | - 11 12 13 14 15
4   | - 16 17 18 19 20
5   | - 21 22 23 24 25



I just assumed everyone did this, because 0 is fairly useless to me, and I never use it. I always use arrays this way, I never even thought of making use of 0-after all, you can't have an object be at the edge fo the map, you have to start one square in. Sorry, and Thanks!

I'm sorry to have given you the wrong idea of what I meant. I was mearly comparing the two, and came up with your way as faster. I am sorry to have sounded so negative.

if you wanted the graph to look like this:

      0  1  2  3  4 
    +---------------
0   |21 22 23 24 25
1   |16 17 18 19 20
2   |11 12 13 14 15
3   | 6  7  8  9 10
4   | 1  2  3  4  5




would the equations for converting 2d to 1d be x+((height-y)*width)?

It would have been faster to test this yourself than draw out that table! ;)

height = 5
width = 5

For y = 0 To 4
	For x = 0 To 4
		Locate x*50, y*50
		Print x+((height-y)*width)
	Next
Next


How come I can't think of those things? Thanks a bunch! Anayways, I didn't draw out the table, I copied it from a prieveious post, then changed the numbers in the middle. It took about two seconds to do.