3D array

Started by stuh505, Fri 14/05/2004 03:33:57

Previous topic - Next topic

stuh505

I found this topic in the tech archives (because I'm getting guilty asking so many questions so now I'm trying to look things up)

http://www.adventuregamestudio.co.uk/yabb/index.php?topic=6918.0

which is very pertinent because Scorpious wrote a function for a 2d array...but I need a 3d array.  I'm sure it can be done this way as well...but my mind is a bit fried.  Anyone want to write it?  eh?  eh? 

Scorpiorus

#1
You can either replace tile's int type with a struct and declare a 1D array within the struct thus making it 3d or implement without the use of struct, as follows:

#define WIDTHÃ,  100
#define HEIGHT 100
#define DEPTHÃ,  100

// the value of TOTAL must be equal to (WIDTH*HEIGHT*DEPTH)
#define TOTAL 1000000

int array[TOTAL];


function SetElement(int k, int i, int j, int value) {
   if (i<0 || i>=HEIGHT || j<0 || j>=WIDTH || k<0 || k>=DEPTH) {
      Display("error: out of bounds"); QuitGame(0);
   }
   array[WIDTH*HEIGHT*k + i*WIDTH+j] = value;
}

function GetElement (int k, int i, int j) {
   if (i<0 || i>=HEIGHT || j<0 || j>=WIDTH || k<0 || k>=DEPTH) {
      Display("error: out of bounds"); QuitGame(0);
   }
   return array[WIDTH*HEIGHT*k + i*WIDTH+j];
}

EDIT: forgot the 'return' keyword.

And below a clever explanation of how tha all work ;D

Gilbert

#2
It's just simple maths.

Say if you want to make a (3 * 4 * 5) array, there will be a total of (3 * 4 * 5) = 60 elements. So you need to define:

int blah[60];

Generally if you want the [ a ][ b ][ c ]-th element, you may refer it to
((a*4 +b)*5 + c)-th element. (note that a, b, c starts from 0).

For example, if you wantÃ,  [ 1 ][ 3 ][ 2 ]-th element, you just calculate index= (1*4 + 3)*5 + 2 = 37, so the required entry is blah[37].

You can define a function to calculate the index, example:
function CalIndex(a,b,c){
Ã,  return ((((a*4)+b)*5)+c);
}


To calculate back the "a" "b" "c" indices (say from a single index d), you can use the following calculations (note:division in ags is integer division):
a = d/(4 * 5);
b = (d/5)%4;Ã,  Ã,  //we can use mod now for V2.61+
c = (d%(4 * 5))%5;

You can write functions for them in similar way.

Note that the above calculations involve using the % (mod) operator, which is only available in V2.61+ (not yet official released), if you want to have them without using mod, you can do:

a = d/(4 * 5);
b = (d/5) - (a * 4);
c = (d - (a *4 * 5)) - (b * 5);

stuh505

 :DÃ,  thanks Scorp

yeah, Gilbot...I understand the concept, I just didn't want to derive "((a*4 +b)*5 + c)-th element" that part...it's a bit confusing

before this gets moved into the tech archive...i have 1 more related question..

can i define the contents of this at declaration, or do I need to individually set each element?

Scorpiorus

#4
Quote from: stuh505 on Fri 14/05/2004 05:29:52yeah, Gilbot...I understand the concept, I just didn't want to derive "((a*4 +b)*5 + c)-th element" that part...it's a bit confusing
The thing is that's a generic way of implementing of an array. Following this formula you can easily create any-dimension arrays. It is also faster for AGS to calculate the result index. Btw, WIDTH*HEIGHT*k + i*WIDTH+j is actually equal to (HEIGHT*k + i)*WIDTH+j as you see. I just wrote it in that layered fashion to show how it's achieved.

For instance a 5-dimensional array:

(((a*B+b)*C+c)*D+d)*E+e

a,b,c,d,e - indexes
A,B,C,D,E - their max values+1

Quotecan i define the contents of this at declaration, or do I need to individually set each element?
Nope, I am afraid. If you need to set specific values for each element you have to set them manually (or read from existing file). You can use an absolute indexation though:

array[ 0]=1;
array[ 1]=13;
array[ 2]=15;
....
array[ TOTAL-1]=11;

Gilbert

#5
Maybe I'll illustrate this further with pictures:
Teh original array:

when hashed into a 1-D array:


so for example the [1][3][2]-th element would be the (5 * 20 + 3 * 5 + 2)-th (same formula expanded, see 5*4=20) element in the 1D-array.


For the declaration part, like scorpion mentioned, you can't declare them all at once "on-the-fly" currently, if you really need to declare a large array with varioyus data, you may try using some external files so the game will load its content to fill in the array(s), see the file related functions of the manual.

stuh505

QuoteNope, I am afraid. If you need to set specific values for each element you has to set them manually (or read from existing file). You can use an absolute indexation though:

array[ 0]=1;
array[1]=13;
array[2]=15;
....
array[TOTAL-1]=11;

aieee

at least I am dealing with a "small" 3d array so I only have 460 elements...

Scorpiorus

#7
Quote from: Gilbot V7000a on Fri 14/05/2004 06:22:26Maybe I'll illustrate this further with pictures
Wow!! Nice figures Gil. Fits in just well ;)


One more thing I'd like to mention about using of arrays. It is vital to ensure we access array elements that are inside array's bounds.

Doing something like this most likely corrupt your game script data:

int array[ 3 ]; // possible element index is 0, 1 and 2
Valid access:
array[  0 ] = 1; // valid
array[  1 ] = 2; // valid
array[  2 ] = 3; // valid

Invalid access:
array[ -1 ] = 1; //will corrupt a variable that is allocated before array;
array[  7 ]Ã, = 2; //will corrupt a variable located at some memory address after array
array[  3 ]Ã, = 3; //will corrupt a variable located just after array;

That's why making appropriate functions for accessing the elements of array and asserting the input parameters validation is a way to go.



Gilbert

Yeah  it's always important to remember that when you declare an array, the index runs from 0 to size - 1.

I think this info should be put somewhere in the sticky threads of the Beg. tech. forum :) (if it wasn't done so).

ollj

the problem with pseudo-multidimensional arrays, and any strided list, is that it involves a lot of integer multiplications and divisions, and that's just inefficient.

Snarky

1. No one asked.
2. Even if multidimensional arrays are built into a language, the system still needs to multiply indices under the hood (or do an extra lookup per dimension for each array access), so the basic "inefficiency" is still there. Generally, a solution is not "inefficient" if no better solution exists.
3. This thread is eleven years old!

You don't have to post every thought that comes into your head.

Crimson Wizard

#11
Ollj, I see that you keep posting in old threads? (Now I had too :tongue:)

Quote from: Snarky on Wed 08/07/2015 15:58:14
2. Even if multidimensional arrays are built into a language, the system still needs to multiply indices under the hood (or do an extra lookup per dimension for each array access), so the basic "inefficiency" is still there. Generally, a solution is not "inefficient" if no better solution exists.

Well, in real programming language you can make array of arrays; this solution let you avoid math calculations, OTOH it will have to dereference number of memory addresses.

For the sake of completeness, In AGS script you can do that by introducing a struct:
Code: ags

struct ArrayElement
{
    int sub_array[NUMBER_OF_ELEMENTS];
};

Unfortunately, AGS does not support dynamic arrays in structs, so this kind of solution will be working, but pretty ugly (and probably memory inefficient).

Snarky

That's why I said "or do an extra lookup per dimension for each array access." I would expect a memory lookup to be more expensive than an integer MULT in most cases where it would matter, but that clearly depends on the precise architecture of your system and how the language is implemented on the machine-code level.

Crimson Wizard

#13
Quote from: Snarky on Wed 08/07/2015 16:52:12
That's why I said "or do an extra lookup per dimension for each array access."
Oops, I might have overlooked that part of your phrase. I am reading too fast sometimes. Sorry.

SMF spam blocked by CleanTalk