• 🏆 Texturing Contest #33 is OPEN! Contestants must re-texture a SD unit model found in-game (Warcraft 3 Classic), recreating the unit into a peaceful NPC version. 🔗Click here to enter!
  • It's time for the first HD Modeling Contest of 2024. Join the theme discussion for Hive's HD Modeling Contest #6! Click here to post your idea!

[vJASS] Random unit from group

Status
Not open for further replies.
Level 19
Joined
Oct 12, 2007
Messages
1,821
Hey there.
I've been googling around a bit but couldn't find a solid solution or answer.

Is there anyone that knows of a good way or snippet resource to get a random unit from a group without using BJ's or anything?
 

Deleted member 219079

D

Deleted member 219079

What's wrong with function GroupPickRandomUnit takes group whichGroup returns unit?

Edit: More to answer your question, you could recreate that function in a more optimized fashion if you want.
 
Level 19
Joined
Oct 12, 2007
Messages
1,821
What's wrong with function GroupPickRandomUnit takes group whichGroup returns unit?

Edit: More to answer your question, you could recreate that function in a more optimized fashion if you want.


Well, it turns up red in my editor and I've been told that this should always be avoided. If this is an exception, then please let me know. :)
 

Deleted member 219079

D

Deleted member 219079

Hive user Malhorne is working on a list of friendly BJs. Basically that function is:
JASS:
function GroupPickRandomUnit takes group whichGroup returns unit
    // If the user wants the group destroyed, remember that fact and clear
    // the flag, in case it is used again in the callback.
    local boolean wantDestroy = bj_wantDestroyGroup
    set bj_wantDestroyGroup = false

    set bj_groupRandomConsidered = 0
    set bj_groupRandomCurrentPick = null
    call ForGroup(whichGroup, function GroupPickRandomUnitEnum)

    // If the user wants the group destroyed, do so now.
    if (wantDestroy) then
        call DestroyGroup(whichGroup)
    endif
    return bj_groupRandomCurrentPick
endfunction
JASS:
function GroupPickRandomUnitEnum takes nothing returns nothing
    set bj_groupRandomConsidered = bj_groupRandomConsidered + 1
    if (GetRandomInt(1,bj_groupRandomConsidered) == 1) then
        set bj_groupRandomCurrentPick = GetEnumUnit()
    endif
endfunction
I think that is just fine, but if you want to get rid of the bj_wantDestroyGroup, you'll need to rewrite those functions.
 
Level 23
Joined
Apr 16, 2012
Messages
4,041
as Jondrean said, if you want custom made function, it will work the exact same way, with the exact same body excluding bj_wantDestroyGroup, and at that point, you can just stick with the BJ.

Remember, dont reinvent the wheel, unless necessary(like for learning)
 
Level 19
Joined
Mar 18, 2012
Messages
1,716
That should work aswell, can't say if it is a benefit. Also clears the group (may be a disadvantage)
Requires UnitIndexer

JASS:
    //! textmacro FirstOfGroupHead takes NAME, GROUP
        loop
            set $NAME$ = FirstOfGroup($GROUP$)
            exitwhen $NAME$ == null
            call GroupRemoveUnit($GROUP$, $NAME$)
    //! endtextmacro
    
    //! textmacro FirstOfGroupEnd 
        endloop
    //! endtextmacro

JASS:
    function GroupPickRandomUnitEx takes group whichGroup returns unit
        local integer array index// !
        local integer counter = 0
        local unit u
        
        
        //! runtextmacro FirstOfGroupHead("u", "whichGroup")
        
            set counter = counter + 1
            set index[counter] = GetUnitUserData(u)
        
        //! runtextmacro FirstOfGroupEnd()
        
        if counter == 0 then
            return null
        endif
        return GetUnitById(index[GetRandomInt(1, counter)])
    endfunction
 

Deleted member 219079

D

Deleted member 219079

If you don't want to use UI that indexes every goddamn unit on the map, use this instead:
JASS:
globals
    unit array uArr
    integer tempInt
endglobals
function RandomUnitFromGroupEnum takes nothing returns nothing
    set tempInt = tempInt + 1
    set uArr[tempInt] = GetEnumUnit()
endfunction
function RandomUnitFromGroup takes group g returns unit
    set tempInt = 0
    call ForGroup(g, function RandomUnitFromGroupEnum)
    return uArr[GetRandomInt(1,tempInt)]
endfunction

Edit: If the group has a chance of being empty, use this instead:
JASS:
globals
    unit array uArr
    integer tempInt
endglobals
function RandomUnitFromGroupEnum takes nothing returns nothing
    set tempInt = tempInt + 1
    set uArr[tempInt] = GetEnumUnit()
endfunction
function RandomUnitFromGroup takes group g returns unit
    set tempInt = 0
    set uArr[1] = null
    call ForGroup(g, function RandomUnitFromGroupEnum)
    return uArr[GetRandomInt(1,tempInt)]
endfunction
 
Level 19
Joined
Oct 12, 2007
Messages
1,821
I see a lot of options.
Currently I'm using a unit indexer.

I just have one kind of a condition to be checked and I wonder how to make it.
Ever unit has a fictional health bar for reasons that take some time to explain (not relevant). This fictional health is saved in an integer with array with the unit ID called Unit_TempHP[UnitId].
I want the 'Random unit of group' function to have an option (in this case boolean) to check for units that have a positive TempHP value only, or just include 'ficitonal dead' units too.

This was my attempt, but it doesn't work at all.
With the use of some text messages I found out that "call GroupRandomUnit(g, true) returns null all the time.
(Edit: TempGroup is a private global. I didn't forget to 'CreateGroup()')

Does anyone know what I should change in my approach? Or does anyone have an idea how to work more efficient?

JASS:
function GroupRandomUnit takes group g, boolean temphp returns unit
    local unit u = null
    local integer i = 0
    local integer t = 0
    local unit chosen = null
    
    loop
    set u = FirstOfGroup(g)
    exitwhen u == null
        if Unit_TempHP[GetUnitId(u)] > 0 and temphp == true then
            call GroupAddUnit(TempGroup, u)
            set i = i + 1
        elseif temphp == false then
            call GroupAddUnit(TempGroup, u)
            set i = i + 1
        endif
        call GroupRemoveUnit(g, u)
    endloop
    set t = GetRandomInt(1, i)
    
    loop
    set u = FirstOfGroup(TempGroup)
    exitwhen u == null
        if i == t then
            set chosen = u
        endif
        call GroupRemoveUnit(TempGroup, u)
        set i = i - 1
    endloop
    
    return chosen
endfunction
 
Level 12
Joined
Oct 16, 2010
Messages
680
I don't like the BJ random unit func coz the first u has 100% chance to be picked the 2nd has 50 the 3rd 33 and so on...

u make a lot of unneeded steps

JASS:
function GroupRandomUnit takes group g, boolean temphp returns unit
    local unit u = null
    local integer t = 0
    local integer curmax = 0
    local unit chosen = null
    
    loop
        set u = FirstOfGroup(g)
        exitwhen u == null
        if (Unit_TempHP[GetUnitId(u)] > 0 or temphp == false then
            set t = GetRandomInt(1,100)
            if t>curmax then
                set curmax=t
                set chosen=u
            endif
        endif
        call GroupAddUnit(TempGroup,u)
        call GroupRemoveUnit(g, u)
    endloop
    
    loop
        set u = FirstOfGroup(g)
        exitwhen u == null
        call GroupAddUnit(g,u)
        call GroupRemoveUnit(TempGroup,u)
    endloop

    return chosen
endfunction

if u don't want to leak chosen u can use a global tempunit var instead

EDIT: sry edited:p u DO need tempgroup
 
Level 19
Joined
Oct 12, 2007
Messages
1,821
I don't like the BJ random unit func coz the first u has 100% chance to be picked the 2nd has 50 the 3rd 33 and so on...

u make a lot of unneeded steps, u don't need tempgroop coz g already IS function as a tempgroup
do just this

JASS:
function GroupRandomUnit takes group g, boolean temphp returns unit
    local unit u = null
    local integer t = 0
    local integer curmax = 0
    local unit chosen = null
    
    loop
        set u = FirstOfGroup(g)
        exitwhen u == null
        if (Unit_TempHP[GetUnitId(u)] > 0 and temphp == true) or temphp == false then
            set t = GetRandomInt(1,100)
            if t>curmax then
                set curmax=t
                set chosen=u
            endif
        endif
        call GroupRemoveUnit(g, u)
    endloop
    
    return chosen
endfunction

Thanks.
That makes sence!
Going to try it out right away.
 
Level 22
Joined
Sep 24, 2005
Messages
4,821
@Lender: your script has a chance to return a null unit even though there are valid units within the processed group, the 100% chance on the first unit check on the BJ function has a valid purpose, you just didn't understand it.
 
Level 19
Joined
Oct 12, 2007
Messages
1,821
Hmm. I don't understand what you edited for.
Does this mean the group 'g' will remain empty without the edited part?
 
Level 19
Joined
Oct 12, 2007
Messages
1,821
sry chobibo:/ I know what is it for I just forget to add to the lines...

JASS:
function GroupRandomUnit takes group g, boolean temphp returns unit
    local unit u = null
    local integer t = 0
    local integer curmax = 0
    local unit chosen = FirstOfGroup(g)
    
    loop
        set u = FirstOfGroup(g)
        exitwhen u == null
        if (Unit_TempHP[GetUnitId(u)] > 0 or temphp == false then
            set t = GetRandomInt(1,100)
            if t>curmax then
                set curmax=t
                set chosen=u
            endif
        endif
        call GroupAddUnit(TempGroup,u)
        call GroupRemoveUnit(g, u)
    endloop
    
    loop
        set u = FirstOfGroup(g)
        exitwhen u == null
        call GroupAddUnit(g,u)
        call GroupRemoveUnit(TempGroup,u)
    endloop

    return chosen
endfunction

Shouldn't it be this in the end?

JASS:
loop
        set u = FirstOfGroup(TempGroup)
        exitwhen u == null
        call GroupAddUnit(g,u)
        call GroupRemoveUnit(TempGroup,u)
    endloop
 
Status
Not open for further replies.
Top