• 🏆 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!

looping or if-statements?

Status
Not open for further replies.
Level 15
Joined
Nov 30, 2007
Messages
1,202
I try to condense my code by using loops, but some times that requires a few additional setup functions this has caused me to reach the OP limit and now I'm at a loss having spent so much time trying to device complicated ways for the code to work.

Lets take an example:

JASS:
    if A then
        //Similar code block
    elseif B then
        //Similar code block
    elseif C then
        //Similar code block
    endif
 
    // vs
 
    local integer i = 0
    loop
        if A[i] then 
            // Similar Code block
        endif
        set i = i + 1
        exitwhen i == 3
    endloop
This is the simplest example, they both have 3 conditions depending on something that can be indexed writing the latter one is faster, if you exclude he time it takes to arrange the index for the conditions. It's usually less overall code, however it has additional lines which execute because it's inside a loop. This scenario is obviously irrelevant but I use it to illustrate that maybe those 100's of lines for if-statements are not so bad after all?

Also note usually it's not as clear cut, some time you add additional if's and set the integers in some elaborate way making the overhead much bigger than this example.

=====

So my question I suppose, am I wrong to try to write shorter code and straying away from line upon line of if-statements if i'm doing the same thing in the end and more?
 
Level 24
Joined
Aug 1, 2013
Messages
4,657
Code should be written according to natural logic.
Ussually an if statement (or rather switch cases) are more logical.

However, if you have got it sorted out with indexing, you might just have that number as a direct approach.
"call EvaluateTrigger(actions[a])"

Loops are kinda cool. If they make sense, then it is fine to use them, but it is all your choice.
 

Dr Super Good

Spell Reviewer
Level 64
Joined
Jan 18, 2005
Messages
27,201
for perfomance looping is always bad and should be inlined for low-count entries (2-12 blocks)
In real life for simple loops unwinding can often be slower due to the pipeline nature of processors.

In JASS loops are usually slower as every named field is resolved at runtime (no static linking). If your code is hitting the op limit it might be due to bad complexity or you simply need to run more threads. The op limit often is not helpful as one can make performance intensive triggers that hit the op limit after dropping many frames or simple triggers which hit the op limit without dropping a single frame. Bypass the oplimit by using global state and starting new threads.
 
Level 19
Joined
Dec 12, 2010
Messages
2,069
In real life for simple loops unwinding can often be slower due to the pipeline nature of processors.

In JASS loops are usually slower as every named field is resolved at runtime (no static linking). If your code is hitting the op limit it might be due to bad complexity or you simply need to run more threads. The op limit often is not helpful as one can make performance intensive triggers that hit the op limit after dropping many frames or simple triggers which hit the op limit without dropping a single frame. Bypass the oplimit by using global state and starting new threads.
depends on many things, but jump ops are costly next to ops usually used within loop
 
Level 15
Joined
Nov 30, 2007
Messages
1,202
Or do something like
JASS:
if A or B or C then
    //Similar Code Block
endif

Alas they are merely similar and not identical. :p

Alright i started to rewrite the entire thing but it's behaving really strangely, especially with the values of uud_1 and uud_2 which should be UnitUserData for the saved integer. But i some times get the same number for both and the combination 3 and 20 is popular as well.

JASS:
library FortificationSys initializer Init
    globals
        private constant integer N = 0
        private constant integer S = 1
        private constant integer E = 2
        private constant integer W = 3
        private constant integer OPEN_NORTH = 1
        private constant integer OPEN_SOUTH = 2
        private constant integer OPEN_EAST = 4
        private constant integer OPEN_WEST = 8

        private constant integer D2X2 = 2
        private constant integer D4X4 = 4
        private constant integer D6X6 = 6
        private constant integer HEIGHT_0 = 0
        private constant integer HEIGHT_1 = 1
        private constant integer HEIGHT_2 = 2
        private constant integer PATH_4X4_LVL1_4CROSS     = 'B000'
        private constant integer PATH_4X4_LVL1_TCROSS     = 'B001'
        private constant integer PATH_4X4_LVL1_DEADEND     = 'B002'
        private constant integer PATH_4X4_LVL1_BOX         = 'B003'
        private constant integer PATH_4X4_LVL1_LTURN    = 'B004'
        private constant integer PATH_4X4_LVL1_PASS        = 'B005'

        private hashtable hash = InitHashtable()
        private group tmpGroup = CreateGroup()
    endglobals

    private function pow takes integer x, integer n returns integer
        local integer i = 0
        local integer num = 1
        loop
            exitwhen i == n
            set num = num*x
            set i = i + 1
        endloop
        return num
    endfunction

    struct Pathing
        private unit u
        private real ux
        private real uy
        private integer data = 0
        private boolean array canOpen[4]
        private static real array gridX
        private static real array gridY

        static thistype array pathing

        private static method onInit takes nothing returns nothing
            set thistype.gridX[N] = 0. 
            set thistype.gridY[N] = 128.
            set thistype.gridX[S] = 0. 
            set thistype.gridY[S] = -128
            set thistype.gridX[E] = 128 
            set thistype.gridY[E] = 0
            set thistype.gridX[W] = -128
            set thistype.gridY[W] = 0
        endmethod

        private method openSide takes integer side returns nothing
            set .data = .data + pow(2, side)
        endmethod

        private method closeSide takes integer side returns nothing
            set .data = .data - pow(2, side)
        endmethod

        static method searchForNearbyNodes takes integer uud_1 returns nothing
            local integer uud_2
            local integer i = 0
            local integer m
            local integer k
            loop
                set uud_2 = LoadInteger(hash, R2I(pathing[uud_1].ux + thistype.gridX[i]), R2I(pathing[uud_1].uy + thistype.gridY[i]))
                call BJDebugMsg(R2S(pathing[uud_1].ux + thistype.gridX[i]) + " , " + R2S(pathing[uud_1].uy + thistype.gridY[i]))
                if not (uud_2 == 0) then
                    set m = i - (i/4)*4
                    if m == 1 or m == 3 then
                        set k = m - 1
                    else
                        set k = m + 1
                    endif
                    if uud_1 == uud_2 then
                        call BJDebugMsg("Bug detected!")
                    endif
                    //call BJDebugMsg("uud_1 = " + I2S(uud_1))
                    //call BJDebugMsg("uud_2 = " + I2S(uud_2))
                    //call BJDebugMsg("m = " + I2S(m))
                    //call BJDebugMsg("k = " + I2S(k))
                    if pathing[uud_1].canOpen[m] and pathing[uud_2].canOpen[k] then
                        call pathing[uud_1].openSide(m)
                        call pathing[uud_2].openSide(k)
                        call GroupAddUnit(tmpGroup, pathing[uud_2].u)
                    endif
                    call BJDebugMsg("--")
                endif
                set i = i + 1
                exitwhen i == 4
            endloop
     
        endmethod

        static method spawn takes unit u, integer h, integer d, boolean n, boolean s, boolean e, boolean w returns nothing
            local integer i = GetUnitUserData(u)
            set pathing[i] = .allocate()
            set pathing[i].u = u
            set pathing[i].ux = GetUnitX(u)
            set pathing[i].uy = GetUnitY(u)
            set pathing[i].canOpen[N] = n
            set pathing[i].canOpen[S] = s
            set pathing[i].canOpen[E] = e
            set pathing[i].canOpen[W] = w
            call GroupAddUnit(tmpGroup, pathing[i].u)
            call thistype.searchForNearbyNodes(i)
            call SaveInteger(hash, R2I(pathing[i].ux), R2I(pathing[i].uy), i)
        endmethod
    endstruct

    private function OnConstructionFinish takes nothing returns boolean
        local unit u = GetFilterUnit()
        local integer id = GetUnitTypeId(u)
        local integer i = GetUnitUserData(u)

        call Pathing.spawn(u, HEIGHT_1, D4X4, true, true, true, true)

        set u = null
        return false
    endfunction

    private function Init takes nothing returns nothing
        local trigger t0 = CreateTrigger()
        local integer i = 0
        local player p
        loop
            set p = Player(i)
            call TriggerRegisterPlayerUnitEvent(t0, p, EVENT_PLAYER_UNIT_CONSTRUCT_FINISH, function OnConstructionFinish)
            set i = i + 1
            exitwhen i == 12
        endloop
    endfunction
endlibrary
 
Level 15
Joined
Nov 30, 2007
Messages
1,202
whenver you use loop or if, it's faster to put the most used case in the very top. tho thats not always possible

Good advice i'll try to remember it, not applicable in this scenario though.

The above bug is no longer occurring, don't think I really changed a thing so no idea what was going on... We could play the game "Spot the difference" but i doubt that would be a good time for anyone involved. ^^
 
Last edited:
Status
Not open for further replies.
Top