HomeUser Control Panel (unavailable in archive)ForumsTutorialsArt GalleryResourcesMaps

Multidimensional Arrays

05-08-2004, 11:34 PM#1
Shimrra
I've heard that multidimensional arrays are not possible in Warcraft. What exactly is a multidimensional array and is there any way to simulate it? Thank you towhoever gives me assistance on this subject.
05-09-2004, 12:11 AM#2
weaaddar
Multidimensional array (2d or otherwise) is basically an array of arrays.
In java for instance you create it in such a notion new int[2][2] creating a 2x2 array.
The first subscript is the array you are referencing and the second subscript is the array index.

There is a 2d array in jass, its called gamecache.
05-09-2004, 12:38 AM#3
Shimrra
Could you explain how you create the multidimensional arrays in Jass? I'm not overly experienced in either, but I can read most Jass and I hae used game cache. I thank you for any assistance you might give.

Post scriptum: I have recently been informed that this is actually possible to do in GUI, but I was not informed how...
05-09-2004, 12:53 AM#4
joseka
Well you could create a fake bidimensional array (array[a][b]) creating an single array with a size equal to a*b (array[a*b]) . If you need for exaple to go to position array[1][2] you multiply 1*size_of_array_in_A + 2 and gotcha...... ,size_of_array_in_A is the size of [a] in your array...
05-09-2004, 01:01 AM#5
Shimrra
Could you perhaps create an example trigger showing both how to create and extract from an array of that type? Unfortunately, I was a little confused about your post...
05-09-2004, 01:42 AM#6
toxicseaweed3
you can make a 2d ray in GUI. for every additional row of information you wish to store you would need an additional arrayed variable so for an example i'll make a little array.

Quote:
Actions
For each (Integer A) from 1 to 10, do (Actions)
Loop - Actions
Set Array[(Integer A)] = (Integer A)
For each (Integer B) from 1 to 10, do (Actions)
Loop - Actions
Set Array[SubArray[(Integer B)]] = (Integer B)

What this does is first define the row, then it defines all the colums within the row. Sense i'm too lazy i just had it store the number of the loop it was on. Don't see how this could be very flexible though, Integers, Reals, would probably be ideal though i think you could do the same thing for maybe units.
05-09-2004, 01:47 AM#7
weaaddar
GAME CACHE is a multidimensional array.
Where as you use label and category as your first and secondary subscript respectively.

Let say you'd like to store all units owned by each player. A good idea would be to use gamecache to store them instead of creating an array for each unit and using the subscript as reference.

(//Not coded method GetNextUnit(player p) will return the next unit owned by the player, and null if the player has no more units).
Code:
function h2i takes handle h returns integer
   return h
   return 0
endfunction
function i2u takes integer i returns unit
   return i
   return null
endfunction
------
// In some func
local integer i=0
local unit u=null
local integer j
local gamecache gc=InitGameCache("units")
local string s=""
loop
  exitwhen i>MAX_PLAYER_NUMBER
  set s=I2S(i)
  set j=0
  loop
    set u=GetNextUnit(Player(i))
    exitwhen u==null
    call StoreInteger(gc,s,I2S(j),h2i(u))
    set j=j+1
  endloop
set i=i+1
endloop

Now inside the gamecache InitGameCache("units") is every unit owned by any player, now if you want to get the sixth unit owned by player six its just be a simple.
set unit u=i2u(GetStoredInteger(InitGameCache("units"),"5","5"))

However, this method I showed doesn't keep track of array length generally you may want to store the last value of j as something like gc,I,length. I.e. some property of the object.
05-09-2004, 01:50 AM#8
toxicseaweed3
i think the thing is that he doesn't know how to write jass and i sure as hell don't see how i could use a loop to read a gamecache though your little code just taught me something new about jass :)
05-09-2004, 01:54 AM#9
weaaddar
Right well, he said he could understand some jass. Anyway Nearly all my projects use multidimensional arrays and gamecache is even more flexible then most. I generally use it as part of a class system. Where as I make private variable have a name as there third field and then concatanate a number to it. (i.e. An array called Johnny to reference element 6 You would have to type "Johnny5")
05-09-2004, 02:01 AM#10
ThyFlame
Hmm.. Since it's variable[variable2[x]]

Can't you just say tempVariable = Variable2[X] and use variable[tempVariable]
05-09-2004, 06:34 AM#11
th15
Shimra, I used multidimensional arrays in my tank commanders map. In my map, there are 8 players. Each player can have up to 9 turrets. Now, I have to move these turrets to the position of the player's tank every 2 seconds. I could have created 1 array for each player and referenced the arrays 8 times. But thats just a pain in the ass. What I did instead is use a form of multidimensional array.

Basically my array extends from index 11 all the way to 98. Index 11 would refer to player 1's first turret. Index 21 refers to player 1's second turret and so on until index 91. So you see, index 98 actually refers to player 8's ninth turret.

This is useful when keeping track of groups of units unique to each player. I hope it helps you. The usefulness of a multidimensional array is such that it cuts the number of triggers my map needs to 1/8th of the number of triggers i'd need if i didn't have this array.

While my multidimensional array is hardly the most versatile or even a true multidimensional array, it works good enough for WC3 and needs nothing more than the GUI triggers.
05-09-2004, 04:28 PM#12
Cubasis
Hmm,

2d Arrays are like a table that reaches in 2 directions and each compartment in the table has a co-ordinate of x and y.

Normally in other languages when you want to set or retrieve data from a 2d array, You do: MyArray[0,5] or MyArray[0][5] (I like the first way more though).

So if we want to emulate this with WC3 1D arrays, we basicly need to apply a formula for it to get a unique 1d-index for every 2 2d-indexes.

Now, first, to clear out another confusion. WC3's arrays are dynamic in the way that every time you define one, you get access to a array with 8192 (or whatever it is exactly) elements. The Size field in the variable editor is not it's real size, but just a kind of child-safety (or noob-safety :D, lol) where it loops that many times, and initiates each of the elements from 0 - Size too "0" (or false, NULL or any equivilent). As if you accidently "use" a un-initiated element, your trigger will crash, as that element only contains garbage.

So... Arrays are in a sense size-less. BUT... if you use the following method to simulate 2d arrays, you WILL be putting a size-limit on one of your dimension/axis. So, you have to decide for yourself which dimension that you want to be able to grow.

The formula is the following (as Joseka already said): X * YLimit + Y

And notice that it's reccomended to have 2d-arrays 0-based. That is... The first index of either X and Y should be "0" (not 1).

So, if we wanted to store each of the 9 tanks of each of 8 players, we could set the player-index as Y, and thus, YLimit is "8". This way, the Tank-count is not "limited" so at a later time we could add more tanks.

But yeah, let's try this. For this example we are gonna set Player 1's 4'th tank to a new unit:

Set Tanks[3*8+0] = (Last Created Unit)

You can see that the formula becomes 24. Note that I use "0" for Player 1, and 3 for the 4-th tank.

If we wanted to loop through all the tanks, we would simply do the following:
Code:
Actions
   For each (Integer A) from 0 to 8, do (Actions) //Tanks
   Loop - Actions
      For each (Integer B) from 0 to 7, do (Actions)  //Players
         Loop - Actions
            Unit - Create Unit ......
            Set Tanks[(Integer A) * 8 + (Integer B)] = (Get Last Created Unit)

In reality it's more comfortable to do this in JASS, as then you can just make a tiny function:

function Ix8 takes integer x, integer y returns integer
return(x*8+y)
endfunction

(A slightly Edited variation of Weaaddar's function)

So then you could just (in JASS): set udg_Tanks[Ix8(8,7)] - too set the 9'th tank of the 8'th Player to something.



Anyhow, you can still easily do the exactly same using the Game Cache in GUI. Just create a GameCache variable, name it what you would name your 2d variable. Initiate it to <ArrayName>.w3v (or just almost anything you like, doesn't matter at all). Then you just refer to it like this:

Game Cache - Store 0 as (String(X)) of (String(Y)) in My2dArray

And then you can retrieve the stored data as:

Set Data = (Load (String(X)) of (String(Y)) from My2dArray)



Anyways, Hope this helps.

Cubasis
05-09-2004, 05:08 PM#13
Shimrra
OK, thanks for eveyone's help and especially to Cubasis for helping me with yet another of the more complex problems.
05-09-2004, 05:33 PM#14
linkmaster23
What I was going to say was, a lot simpler. Was just the X * MaxY + Y or revered, Y*MaxX + X. Example?

In dialog terms, say you had a maximum of 5 choices per Set. Now, On Set 1, (Which is X), you have 5 choices, (MaxY), and choice 3 was chosen, (Y). All together that would look like.

1 * 5 + 3 = 8

Now if you changed it around a bit, say, Set 5, Choice 3, it would be.

5 * 5 + 3 = 28

Understand?
05-10-2004, 04:50 AM#15
MysticGeneral
http://www.wc3campaigns.com/showthre...774#post523774

In the link above is a function I made that allows more than a 2d array... It's a matrix. Enjoy ^^