0
\$\begingroup\$

Is there a way in Godot's GDScript to quickly/easily break out of nested loops?

For example:

# Check if the entire grid is filled.
filled = true
for x in grid:
    for y in grid[x]:
        if grid[x][y] == null:
            filled = false
            break # Break out of both loops?

PHP's break has an optional numeric argument that allows breaking out of nested loops: https://www.php.net/manual/en/control-structures.break.php
And Python has a for...else construct that can be used for this purpose: https://stackoverflow.com/a/3150107/4168619

Is there anything similar in GDScript?

\$\endgroup\$

2 Answers 2

6
\$\begingroup\$

Option1 Use an extra bool flag to break

extends Node2D

func _ready():
    var grid = [
        [1,2,3],
        [4,5,6],
        [7,null,9],
    ]
    var filled = true
    for row in grid:
        var isBreak = false
        for data in row:
            if data == null:
                filled = false
                isBreak = true
                break
        if isBreak:
            break
    print(filled)

Option2 Use return

extends Node2D

func isFilled(array):
    for row in array:
        for data in row:
            if data == null:
                return false
    return true

func _ready():
    var grid = [
        [1,2,3],
        [4,5,6],
        [7,null,9],
    ]
    var filled = isFilled(grid)
    print(filled)

Option3 flatten the array and use a single loop

(use append or append_array or +):

extends Node2D

func flatten1(array):
    var result =[]
    for row in array:
        for data in row:
            result.append(data)
    return result

func flatten2(array):
    var result =[]
    for row in array:
        result.append_array(row)
    return result
    
func flatten3(array):
    var result =[]
    for row in array:
        result+=row
    return result
    
func _ready():
    var grid = [
        [1,2,3],
        [4,5,6],
        [7,null,9],
    ]
    var filled = true
    for element in flatten1(grid):
        if element==null:
            filled = false
            break
    print(filled)

(use reduce):

extends Node2D

func _ready():
    var grid = [
        [1,2,3],
        [4,5,6],
        [7,null,9],
    ]
    var filled = true
    for element in grid.reduce(func(acc, x): return x+acc):
        if element==null:
            filled = false
            break
    print(filled)

Option4 Just check if the entire grid is filled

(use reduce and has)

extends Node2D

func _ready():
    var grid = [
        [1,2,3],
        [4,5,6],
        [7,null,9],
    ]
    var filled = !grid.reduce(func(acc, x): return x+acc).has(null)
    print(filled)

Related link: Godot Engine 4.0 documentation:Array

\$\endgroup\$
2
\$\begingroup\$

Some languages, such as C#, doesn't have such feature, but there are workarounds.

I'd prefer to put the code in a seperate function, and then use return; or return [value]; the moment you got the value you wanted.

Going through each loop with a boolean check (like if (filled == false) break;) is also possible in larger nested loops.

\$\endgroup\$
2
  • 2
    \$\begingroup\$ C# has such a feature, it's just not considered good coding style in many cases: goto will break out of any number of nested loops. As long as you only ever use forward gotos, (jumping to a label strictly later in the same function), you avoid the worst problems with them. But it's still usually a code smell and a sign that there's a better way to structure the algorithm so that you don't need it, like your return suggestion. \$\endgroup\$
    – DMGregory
    May 22, 2023 at 11:36
  • \$\begingroup\$ I've been strictly teached to never use goto in any scenario, for the reasons you mentioned. So even suggesting goto as an option would've been a bad habit for me. But yeah, technically it is an option. \$\endgroup\$
    – Steven
    May 22, 2023 at 13:58

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .