2 Dimensional Arrays

tooltiperror

Super Moderator
Reaction score
231
How does one use multiplication to create 2 Dimensional Arrays properly? I'm trying to simulate a 2D Table, because Table doesn't natively support two dimensions. If you need to know why, it's because I want one slot in the table to be one unit's handle ID, and the other slot a different unit's ID.
 

tooltiperror

Super Moderator
Reaction score
231
But isn't there a way without hashtables? I hate using hashtables if I don't have to.
 

Bribe

vJass errors are legion
Reaction score
67
There is no way an n(0) search of that magnitude is going to beat the speed of a hashtable native. If you don't like the way they look, do this (the functions get inlined):

JASS:
function Save takes agent a, agent b, integer value returns nothing
    SaveInteger(hash, GetHandleId(a), GetHandleId(b), value)
endfunction
function Load takes agent a, agent b, returns integer
    return LoadInteger(hash, GetHandleId(a), GetHandleId(b))
endfunction
//
//
call Save(GetTriggerUnit(), GetSpellTargetUnit(), 'T')
set i = Load(GetAttacker(), GetTriggerUnit())
 

Weep

Godspeed to the sound of the pounding
Reaction score
400
JASS:
//pseudocode
globals
    constant integer bMax = 15
    anytype array OneDimension
endglobals

function TwoDimension takes integer a, integer b returns anytype
    return OneDimension[bMax*a+b] //0 <= b < bMax
endfunction
 

Bribe

vJass errors are legion
Reaction score
67
I think Weep is trying to explain to you how to do 2-D arrays, which are in the format of:

JASS:
n * 3 + 0
n * 3 + 1
n * 3 + 2


However, you can't just do that with handles. Hashtables don't index values that ridiculously high as 13 billion * 13 billion last I checked. So he was doing a different style of "Table" index which (unfortunately) won't work properly in every situation.
 

tooltiperror

Super Moderator
Reaction score
231
I suppose using Table is useless if I might as well use a hashtable then.

Edit: I'm realizing that what I'm trying to do is pretty stupid with a hashtable.

In a nut shell, I'm trying to make it so if a unit is killed by the spell, and they are revived and kill the original hero who used the spell, they get the spell. I've got the killing part down fine, but I'm not sure how to store that they've been killed exactly. If the unit is killed by the spell, I would set [LJASS]BooleanArray[Casting Unit, Killed Unit][/LJASS] to true. Then, if a unit is killed, and [LJASS]BooleanArray[Killed Unit, Killing Unit]==true[/LJASS], then I add the spell. But the problem is, when a unit is revived, doesn't it get a new Handle Id?
 

saw792

Is known to say things. That is all.
Reaction score
280
Heroes (and heroes only) are guaranteed to have the same handle id when revived, since information still exists about heroes while dead for the purpose of them reviving thus they aren't removed from memory. Your hashtable method should work for this situation. I'd probably combine it with an AIDS struct or something depending on exactly how you wanted it to work.

EDIT: Beaten, and we said exactly the same thing :p
 

tooltiperror

Super Moderator
Reaction score
231
I don't think I'm going to use AIDS, it's pretty much over kill to just keep track of a boolean. But it's good that heroes keep their Handle Id's.

Thanks, all who answered.
 

Bribe

vJass errors are legion
Reaction score
67
In a nut shell, I'm trying to make it like this:

If a unit is killed by the spell, revives, then kills the hero who killed it, the new killer acquires the spell.

I've got the killing part down fine, but I'm not sure how to store the fact that they were killed.
1. If the unit is killed by the spell, I would set BooleanArray[Casting Unit, Killed Unit] to true.
2. If a unit is killed, and BooleanArray[Killed Unit, Killing Unit]==true, then I add the spell.

Edited for readability. I had no idea what you were saying at first - that was one crazy paragraph!
 

Sevion

The DIY Ninja
Reaction score
413
Basically, what [ljass]OneDimension[bMax*a+b][/ljass] is is:

JASS:
TOTAL_NUM_OF_COLUMNS * PLAYER + CELL


So, if you have 12 columns (1 per player) and you want Player 4, Cell 4, you do:

JASS:
12 * 3 + 4 = 40


In the end, the array returned is [LJASS]OneDimension[40][/LJASS]

Basically, instances 0-12 are for Player 0, 13-24 are for Player 1 etc etc.

Think of it as a big cube.

12 Columns Wide
12 Rows High
12 Cells Deep

http://www.trump.de/magic-squares/magic-cubes/hugel-cube.gif

Using this diagram, the top left is the theoretical 2D Array The 58b-58f figures are the cells of each player (with Columns and Rows flipped ofc). Basically, each figure represents all of the cells each player holds.

In this diagram, there are 5 Columns, 5 Rows, and 5 Cells.

So, we have 5 players, 5 cells.

Our array formula for Player 4, Cell 2 would be:

JASS:
// If we display it as [x][y]
Array[3][2] = Array[5 * 3 + 2] = Array[17]


I suppose I'll review this post later... It's pretty late and I'm not even sure if I wrote it right.
 

kingkingyyk3

Visitor (Welcome to the Jungle, Baby!)
Reaction score
216
Wow, delimited array index.
A "fake" hashtable with O(n) search within 2d linked list.
I think Jesus4Lyf did it(Does not work) in TableX thread, but my version is working well.
JASS:
/* 
Double Array by kingking

Usage :
  //! runtextmacro DoubleArray ("<public/private/none>","<Name>","<Type of variables>","<Default value/null value>")
  set <Name>[parent][child] = data
  <Name>[parent][child] = data
  
    RemoveSavedData :
    <Name>[parent].remove(child) 
    (Always do this, if you are attaching random index to it. It is used to maintain the speed.)
    
    HaveSavedData :
    <Name>[parent].have(child)
    
    FlushChildTable :
    <Name>[parent].clear()
  
 Pros :
 Delimited array index.
 
 Cons :
 O(n) search, low speed.
 Can only handle 8190 data, for maximum.
 (Decreases when more parent array index is used.)

    Concept :
    This library is based on linked list.
    2D doubly linked list is used. =D
    
    this.prev.prev.up       this.prev.up           this.up             this.next.up        this.next.next.up
          $                      $                    $                    $                      $
    this.prev.prev      #    this.prev      #       this        #       this.next    #     this.next.next
          $                      $                    $                    $                      $
    this.prev.prev.down     this.prev.down        this.down           this.next.down      this.next.next.down
    
    # -> Horizontal list
    $ -> Vertical list
*/
library DoubleArray

    //! textmacro DoubleArray takes SCOPE, NAME, TYPE, DEFAULT
    $SCOPE$ struct $NAME$ extends array
        private static integer array arrayStack
        private static integer arrayStackLevel = 0
        private static integer arrayRead = 0
        private static method getIndex takes nothing returns thistype
            if arrayStackLevel == 0 then
                set arrayRead = arrayRead + 1
                set arrayStack[0] = arrayRead
            else
                set arrayStack[0] = arrayStack[arrayStackLevel]
                set arrayStackLevel = arrayStackLevel - 1
            endif
            debug if arrayStack[0] > 8191 then
                debug call BJDebugMsg("DoubleArray error! No more data can be stored. Please use .remove(index) to clean up some spaces.")
            debug endif
            return arrayStack[0]
        endmethod
        private integer index
        private thistype prev
        private thistype next
        private thistype down
        private thistype up
        //2D linked list, vertical and horizontal.
        static method operator [] takes integer index returns thistype
            local thistype this = thistype(0).next
            
            loop
            exitwhen this == 0
                if .index == index then
                    return this
                endif
                set this = this.next
                //Search in horizontal list.
            endloop
            
            //Not found?
            set this = thistype.getIndex()
            //Create a new node for index
            set this.index = index
            
            set thistype(0).prev.next = this
            set this.next = thistype(0)
            set this.prev = thistype(0).prev
            set thistype(0).prev = this
            //Link node to horizontal list.
            
            set this.down = this
            set this.up = this
            //Head as vertical list.
            return this
        endmethod
        private $TYPE$ data
        private method releaseIndex takes nothing returns nothing
            set arrayStackLevel = arrayStackLevel + 1
            set arrayStack[arrayStackLevel] = this
            set this.index = 0x28829022
            set this.down.up = this.up
            set this.up.down = this.down
            //Unlink from vertical list.
            set this.data = $DEFAULT$
        endmethod
        method operator [] takes integer index returns $TYPE$
            local thistype new
            local thistype ori = this
            set this = this.down
            
            loop
            exitwhen this == ori
                if this.index == index then
                    return this.data
                endif
                set this = this.down
                //Search in vertical list.
            endloop
            //Not found?
            
            return $DEFAULT$
        endmethod
        method operator []= takes integer index, $TYPE$ data returns nothing
            local thistype new
            local thistype ori = this
            
            set this = this.down
                
            loop
            exitwhen this == ori
                if this.index == index then
                    set this.data = data
                    return
                endif
                set this = this.down
                    //Search in vertical list.
            endloop
                
            //Not found?
            set this = thistype.getIndex()
            set this.index = index
                
            set ori.up.down = this
            set this.down = ori
            set this.up = ori.up
            set ori.up = this
                
            set this.data = data
        endmethod
        method remove takes integer index returns nothing
            local thistype ori = this
            set this = this.down
                
            loop
            exitwhen this == ori or this.index == index
                set this = this.down
                //Search in vertical list.
            endloop
                
            if this.index == index then
                call this.releaseIndex()
                //Remove node from vertical list.
            endif
        endmethod
        method have takes integer index returns boolean
            local thistype ori = this
            set this = this.down
                
            loop
            exitwhen this == ori or this.index == index
                set this = this.down
                //Search in vertical list.
            endloop
            
            return this.index == index
        endmethod
        method clear takes nothing returns nothing 
            local thistype ori = this
            set this = this.down
            
            loop
            exitwhen this == ori
                call this.releaseIndex()
                //Iterate through whole list and remove all nodes in list.
            endloop
        endmethod
        private static method onInit takes nothing returns nothing
            set thistype(0).index = 0x28829022
        endmethod
    endstruct
    //! endtextmacro
    
endlibrary

JASS:
library Table
//***************************************************************
//* Table ???
//* ------------
//*
//*   set t=Table.create() - instanceates a new table object
//*   call t.destroy()     - destroys it
//*   t[1234567]           - Get value for key 1234567
//*                          (zero if not assigned previously)
//*   set t[12341]=32      - Assigning it.
//*   call t.flush(12341)  - Flushes the stored value, so it
//*                          doesn't use any more memory
//*   t.exists(32)         - Was key 32 assigned? Notice
//*                          that flush() unassigns values.
//*   call t.reset()       - Flushes the whole contents of the
//*                          Table.
//*
//*   call t.destroy()     - Does reset() and also recycles the id.
//*
//*   If you use HandleTable instead of Table, it is the same
//* but it uses handles as keys, the same with StringTable.
//*
//*  You can use Table on structs' onInit  if the struct is
//* placed in a library that requires Table or outside a library.
//*
//*  You can also do 2D array syntax if you want to touch
//* mission keys directly, however, since this is shared space
//* you may want to prefix your mission keys accordingly:
//*
//*  set Table["thisstring"][ 7 ] = 2
//*  set Table["thisstring"][ 5 ] = Table["thisstring"][7]
//*
//***************************************************************

    //! runtextmacro DoubleArray ("private","Hashtable","integer","0")
    
    private struct GTable
        method reset takes nothing returns nothing
            call Hashtable[this].clear()
        endmethod

        private method onDestroy takes nothing returns nothing
            call this.reset()
        endmethod
    endstruct
    
    //! textmacro Table__make takes name, type, key
    struct $name$ extends GTable

        method operator [] takes $type$ key returns integer
            return Hashtable[this][$key$]
        endmethod

        method operator []= takes $type$ key, integer value returns nothing
            set Hashtable[this][$key$] = value
        endmethod
        
        method flush takes $type$ key returns nothing
            call Hashtable[this].remove($key$)
        endmethod

        method exists takes $type$ key returns boolean
            return Hashtable[this].have($key$)
        endmethod
        
        static method flush2D takes string firstkey returns nothing
            call $name$(- StringHash(firstkey)).reset()
        endmethod
        
        static method operator [] takes string firstkey returns $name$
            return $name$(- StringHash(firstkey) )
        endmethod

    endstruct
    //! endtextmacro

    //! runtextmacro Table__make("Table","integer","key" )
    //! runtextmacro Table__make("StringTable","string", "StringHash(key)" )
    //! runtextmacro Table__make("HandleTable","handle","GetHandleId(key)" )

endlibrary

Modified Table is working with the cooperation of DoubleArray(I tested by attaching 100 data to it, it did return correct value.)
 

Nestharus

o-o
Reaction score
84
edit
Now that I read the thread and see he wants to use handle ids, I guess you would do [handleIdKiller, handleIdDead, spellStack] and loop through all the spells between that relationship. This would allow a unit to be killed multiple times by the same unit with different spells and make that unit be able to take those spells.

You only need a stack as the stack can easily clear out, a list is totally unneeded for this >.<.. really, you don't even need a stack as you can store the spell Ids directly if you hash the handle ids to make the numbers smaller.

[id1*8192+id2, counter, spell]

if counter != 0, then obviously have spells. Just decrease the counter until 0. This would ensure that you could 2^32-1 spells stored between each unit relationship. You would also need a list of all relationships between units, meaning if the killer dies, it clears out those lists = ).

This obviously seems a little complex, but this is actually stuff very similar to what I've been doing in a Spawn system = ).
 
General chit-chat
Help Users
  • No one is chatting at the moment.

      The Helper Discord

      Staff online

      • Ghan
        Administrator - Servers are fun

      Members online

      Affiliates

      Hive Workshop NUON Dome World Editor Tutorials

      Network Sponsors

      Apex Steel Pipe - Buys and sells Steel Pipe.
      Top