• 🏆 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!
  • 🏆 Hive's 6th HD Modeling Contest: Mechanical is now open! Design and model a mechanical creature, mechanized animal, a futuristic robotic being, or anything else your imagination can tinker with! 📅 Submissions close on June 30, 2024. Don't miss this opportunity to let your creativity shine! Enter now and show us your mechanical masterpiece! 🔗 Click here to enter!

[Solved] Problem with checking when an empty spot is surrounded

Status
Not open for further replies.
Level 13
Joined
Mar 24, 2013
Messages
1,105
JASS:
function Filter_Condition takes nothing returns boolean
return (IsUnitType(GetFilterUnit(), UNIT_TYPE_STRUCTURE) == true)
endfunction

function Detection takes player pl, real x1, real y1 returns nothing
    local group g
    local unit u
    local unit u2
    local integer i = 0 // spots to check
    local integer i2 = 0 // spots around the spot to check
    local integer i3 = 0 // counter of buildings that surround a spot
    local real offset
    local real offset2
    local boolean b = false
    loop
        exitwhen b == true or i == 5
            set i = i+1
            set i3 = 0
            if i == 5 then
//
            else
                if i == 1 then
                    set x1 = x1 + 0.
                    set y1 = y1 + 128.
                elseif i == 2 then
                    set x1 = x1 + 128.
                    set y1 = y1 - 128.
                elseif i == 3 then
                    set x1 = x1 - 128.
                    set y1 = y1 - 128.
                elseif i == 4 then
                    set x1 = x1 - 128.
                    set y1 = y1 + 128.
                endif
                loop
                    exitwhen i2 == 4
                        set g = CreateGroup()
                        set i2 = i2 + 1
                        if i2 == 5 then
                        //
                        else
                            if i2 == 1 then
                                set offset = 0.
                                set offset2 = 128.
                            elseif i2 == 2 then
                                set offset = 128.
                                set offset2 = 0.
                            elseif i2 == 3 then
                                    set offset = 0.
                                    set offset2 = -128.
                            elseif i2 == 4 then
                                    set offset = -128.
                                    set offset2 = 0.
                            endif
                        endif
                            call GroupEnumUnitsInRange(g, x1+offset, y1+offset2, 10., Condition(function Filter_Condition))
                              
                                    set u = FirstOfGroup(g)
                                    if u == null then
                                    else
                                        set i3 = i3 + 1
                                        if i3 == 4 then
                                            set b = true
                                        else
                                    endif
                                    endif
                        call DestroyGroup(g)
                endloop
                endif
    endloop
    if b == true then
       set u2 = CreateUnit(Player(pl, 'h002', x1, y1, 270)
// do more
    else
    endif
    set g = null
    set u = null
    set u2 = null
endfunction


Basically the purpose of this is to see when an empty spot on a grid has been blocked on its 4 sides. If it has then do something otherwise not.

My problem is that currently the only time it seems to properly work is when the last side that is covered is the spot underneath the empty spot.

To better explain view:

[] [1] []
[2] _ [3]
[] [x] []

When the last spot that gets occupied is x, the code gives the intended result, however when its 1,2, or 3 that is the last to block all sides, it does not produce the intended result.

I'm assuming something is wrong with my 2nd loop but I can't seem to figure it out.

Thanks for any assistance.
 
Last edited:
Level 24
Joined
Aug 1, 2013
Messages
4,657
Try this:
JASS:
function Filter_Condition takes nothing returns boolean
    return IsUnitType(GetFilterUnit(), UNIT_TYPE_STRUCTURE)
endfunction

function IsSpotFilled takes real x, real y returns boolean
    local boolean result = false
    local group g = CreateGroup()
    call GroupEnumUnitsInRange(g, x, y, 10., Condition(function Filter_Condition))

    set result = FirstOfGroup(g) != null

    call DestroyGroup(g)
    set g = null
    return result
endfunction

function IsSpotSurrounded takes real x, real y returns boolean
    local real x2
    local real y2
    local real grid = 128.
    local real i = 0

    loop
        exitwhen i >= 4
   
        if i == 0 then
            set x2 = x
            set y2 = y + grid
        elseif i == 1 then
            set x2 = x
            set y2 = y - grid
        elseif i == 2 then
            set x2 = x + grid
            set y2 = y
        elseif i == 3 then
            set x2 = x - grid
            set y2 = y
        endif
   
        if not IsSpotFilled(x2, y2) then
            return false
        endif
   
        set i = i + 1
    endloop

    return true
endfunction

function Detection takes player pl, real x, real y returns nothing
    local unit u
    local integer i = 0
    local real x2
    local real y2
    local real grid = 128.

    loop
        exitwhen i >= 4
   
        if i == 0 then
            set x2 = x
            set y2 = y + grid
        elseif i == 1 then
            set x2 = x
            set y2 = y - grid
        elseif i == 2 then
            set x2 = x + grid
            set y2 = y
        elseif i == 3 then
            set x2 = x - grid
            set y2 = y
        endif
   
        if IsSpotSurrounded(x2, y2) then
            set u = CreateUnit(Player(pl, 'h002', x2, y2, 270)
            // do more
            set u = null
        endif
   
        set i = i + 1
    endloop
endfunction

It is good practise to split functionalities in different functions.
One function to check if a certain slot is filled, one function to check if all 4 neighbours are filled, and one function that checks if the 4 neighbours' 4 neighbours are filled.

Also, you might want to rename your functions or give them a prefix, or add them to a library or scope using vJASS so you wont get stuck with multiple functions with the same name...
Detection() and Filter_Condition() are pretty general names.

There is one moment that if you make 2 spots complete in one move, your original concept would only detect one.
I assume it was intentional because you made it like that, but I still removed it :p
If you want to stop the loop once it has found one completed spot, you add exitwhen true just after the set u = null in the Detection() function.

And if this doesnt work, then you just have to add some debug messages.
Just show what runs and what they return.
 
Last edited:
Level 13
Joined
Mar 24, 2013
Messages
1,105
Wow, thanks for redoing the code for me. It does work now, I'm not entirely sure I followed what you changed. Although I think a part of it is that return is a break statement, which I didn't know.

I appreciate the tips on how to lay out my code, my current project is the first I've ever used JASS outside of an occasional custom script so I'm still very new.

Could you explain the 2 spots completing in one move? That doesn't/shouldn't be possible and when I execute your code it doesn't seem to do anything I wasn't expecting so maybe I'm confused?

Thanks and +rep
 
Last edited:
Level 24
Joined
Aug 1, 2013
Messages
4,657
lets say you have a field of 3 by 5:
[0][0][0]
[0][0][0]
[0][0][0]
[0][0][0]
[0][0][0]

Then you fill these spots:
[0][x][0]
[x][0][x]
[0][0][0]
[x][0][x]
[0][x][0]

Then you fill the center spot.
Now you completed two sets:
[0][x][0]
[x][0][x]
[0][x][0]
[x][0][x]
[0][x][0]

and

[0][x][0]
[x][0][x]
[0][x][0]
[x][0][x]
[0][x][0]

In your old code, it would only detect one (whichever was first), in my code, it will detect both.
 
Status
Not open for further replies.
Top