HomeUser Control Panel (unavailable in archive)ForumsTutorialsArt GalleryResourcesMaps

[JASS] Array Index

05-10-2006, 06:30 PM#1
Sharingan
Hmm, is there a function for getting the index of a certain value within an array?
Example:
local string array blah
blah[1] = "OK"

Now i have the "OK" and want to retrieve the index (1) of blah...
GetIndexOfValue(OK, blah)?? >_<
05-10-2006, 06:33 PM#2
Vexorian
Old school loop until you find it.

Alternatively you can use game cache which is actually a great alternative for this case

Collapse JASS:
call StoreInteger(gc,"blah","OK",1)
05-10-2006, 09:21 PM#3
Vuen
Just search through the array with a loop. Like this:

Collapse JASS:
local integer i = 0
local integer index = -1
loop
    if str == blah[i] then
        set index = i
    endif
    exitwhen i > 1000 or not(index = -1)
    set i = i + 1
endloop
05-10-2006, 10:20 PM#4
Sharingan
Quote:
Originally Posted by Vexorian
Old school loop until you find it.

Alternatively you can use game cache which is actually a great alternative for this case

Collapse JASS:
call StoreInteger(gc,"blah","OK",1)

Hmm, i was thinking that looping might be too slow...
Anyway, this gamecache thing looks interesting, could you explain that a bit more?
05-11-2006, 01:53 AM#5
Vuen
Looping is not too slow. Not even close. In my map I have a 'translator' system set up, where it will automatically translate names like "custom_n00A" to "weaponshop" and back; this loops through a large translation table anytime anything gets messaged or any chat command is entered.

I also catch *all* chat messages and do string matches on them manually. The map checks each chat message for several hundred commands, because I provide a huge amount of redundency. It's full of chunks like this:

Collapse JASS:
    elseif (str == "gate") then
        call SelectUnitForPlayerSingle( GUI_D_P_Gate, pl )
    elseif (str == "elvengate") then
        call SelectUnitForPlayerSingle( GUI_D_P_ElvenGate, pl )
    elseif (str == "elven gate") then
        call SelectUnitForPlayerSingle( GUI_D_P_ElvenGate, pl )
    elseif (str == "demonicgate") then
        call SelectUnitForPlayerSingle( GUI_D_P_DemonicGate, pl )
    elseif (str == "demonic gate") then
        call SelectUnitForPlayerSingle( GUI_D_P_DemonicGate, pl )
    elseif (str == "demongate") then
        call SelectUnitForPlayerSingle( GUI_D_P_DemonicGate, pl )
    elseif (str == "demon gate") then
        call SelectUnitForPlayerSingle( GUI_D_P_DemonicGate, pl )
    elseif (str == "wall") then
        call SelectUnitForPlayerSingle( GUI_D_P_StoneWall, pl )
    elseif (str == "stonewall") then
        call SelectUnitForPlayerSingle( GUI_D_P_StoneWall, pl )
    elseif (str == "stone wall") then
        call SelectUnitForPlayerSingle( GUI_D_P_StoneWall, pl )
    elseif (str == "line") then
        call SelectUnitForPlayerSingle( GUI_D_P_Line1, pl )
    elseif (str == "wallline") then
        call SelectUnitForPlayerSingle( GUI_D_P_Line1, pl )
    elseif (str == "wall line") then
        call SelectUnitForPlayerSingle( GUI_D_P_Line1, pl )

My map does a completely absurd amount of string matching, and there is no slowdown whatsoever. Don't worry, you're golden.
05-11-2006, 01:28 PM#6
Vexorian
Looping is terribly slow.

Fact is that in this case gamecache is much better. Code will be easier to write and everything will be faster

The hard thing is to have a global gamecache variable that is initialized before every other line uses it. Let's name it gc


Collapse JASS:
function gcthing takes nothing returns gamecache
     if (udg_gc==null) then
          // senseless, but necessary:
          call FlushGameCache(InitGameCache("goo.dat"))
          set udg_gc=InitGameCache("goo.dat")
     endif
 return udg_gc
endfunction

That is a function in the custom script section so every trigger can use it if it wants.

Collapse store:
local gamecache gc=gcthing()
call StoreInteger(gc,"fruits","Orange",1)
call StoreInteger(gc,"fruits","Apple",2)
// 
call StoreInteger(gc,"fruits","Lemon",1345)

set gc=null


Collapse get:
function GetFruitNumber takes string s returns integer
    if ((s=="") or (s==null)) then
         return 0
    endif
    return GetStoredInteger(gcthing(),"fruits",s)
endfunction
05-12-2006, 01:09 AM#7
weaaddar
A linear loop may be bad on a large number of strings in a language like java, but to war3 they're pretty much equivoical as a number of ints. If the number is small like say 10 ints it shouldn't be a problem. equivalence tests on strings take the same time on ints as strings (with good reason). The only problem is you can't do a binary search on strings since string content comparisons in jass are even worse then in java.

The "speedup" for log(n) search time might will be killed by the linear test time for small arrays. Remember, that = is constant but LexicallyGreater or whatever is not. If you have a huge number of strings then it might be worth it.
05-12-2006, 07:03 AM#8
Sharingan
That gamecache thing amazes me to no end....just a few more questions:
Collapse JASS:
call StoreInteger(gc,"fruits","Orange",1)
Are "fruits" and "Orange" just random strings that would make the gamecache 2 dimensional?
Like, i could get the stored Integer like this
Collapse JASS:
call GetStoredInteger(gcthing(), s ,"Orange")

Edited by Blade.dk. Reason: Replaced code tags with jass tags.
05-12-2006, 07:12 AM#9
PipeDream
Yup! Hash tables are fantastic! And if you reserve one character for a delimiter (or if you're really clever you can do with out), you can make your arrays infinite dimensional. Also, note that capitalization is ignored by the hash algorithm: "Orange" and "orange" will access the same string.
05-12-2006, 08:31 AM#10
Vuen
Quote:
Originally Posted by weaaddar
A linear loop may be bad on a large number of strings in a language like java, but to war3 they're pretty much equivoical as a number of ints. If the number is small like say 10 ints it shouldn't be a problem. equivalence tests on strings take the same time on ints as strings (with good reason).

Exactly. For something like this, it's perfect; looking up the index in a String array is no different than any other object, because it's all just pointers. An integer comparison is dirt cheap, even in Warcraft. This is how my own map runs seamlessly even with an absurd number of String comparisons.

Quote:
Looping is terribly slow.

Fact is that in this case gamecache is much better. Code will be easier to write and everything will be faster

Nope. Anitarf measured the speed of using global arrays as 4 times faster than using a Gamecache. Or did I misunderstand this post?
http://wc3campaigns.net/showpost.php...9&postcount=22

Anyway the point he's making, and that I agree with, is that neither one makes any significant difference, so use whichever you want. I prefer looping for this sort of index-finding; I just find it simpler and cleaner than using a Gamecache. Personal preference I guess.
05-12-2006, 09:01 AM#11
PipeDream
You gave an example with 1000 elements! did you mean game cache is 250x faster? OK, exaggeration. Whatever works for you, but game cache, besides being morally correct performance wise ;), 1) naturally packages a clean interface 2) dynamic allocation 3) passing! None of your treasured abstract interface with arrays...
05-12-2006, 10:16 AM#12
Sharingan
How is loop-comparing over 50 indexed arrays 10 times faster than to "pick" out a stored data from a gamecache?
I doubt it's even cleaner, wait, it is definitely not cleaner...
Or are you saying that
Collapse JASS:
if OK == 1 then
set blah = 1
elseif OK == 2 then
set blah = 2
elseif OK == 3 then
set blah = 3
...
elseif OK == 50 then
set blah = 50
could possibly faster than
Collapse JASS:
local string(does integer work too?) i 
set bla = GetStoredInteger(gc, "OK", i)
I'm sure the scanning algorithm of getting stored datas is far cleverer than xx if-elses, or am i wrong?

Edited by Blade.dk. Reason: Replaced code tags with jass tags.

EDIT: ...
I just read somewhere that this gamecache thing is only used for singleplayer? -_-;;
I have been wondering that this
Code:
native	InitGameCache	string campaignFile
campaignFile would mean...
Where and how is this campaign file supposed to be? Can i import it into the map?