Exit for loops

I need to exit a for loop on line 163 and 167 if the statement at line 168 if the statement is true. The way I do this now is by having this AllowLoop logic.
Is there a better way to exit a for loop?

Hey @JoeriDukker,

Verse doesn’t support breaking/continueing from for loops, so the way you’re doing things is correct. However, I can think of some ways to clean up the code you posted using other Verse characteristics.

# Move the validity check to its own function. Here I've made the function <decides>
# as that is the idomatic way of writing "IsValid" style checks in the Verse standard libraries.
IsTargetTileValid(TargetTile:int, Piece:piece)<decides><transacts>:void =
    for (OtherPiece : AllPieces):
        if (TargetTile = OtherPiece.Pos and Piece.Color = OtherPiece.Color)
            # "false?" forces a failure of IsTargetTileValid[]
            false?

# (1) Using the new IsTargetTileValid to clean things up a bit
GetPossibleSlidingMoves(Piece:chess_piece, Direction:direction_indices):[]move =
    var Moves:[]move = array{}
    StartTile := Piece.Pos

    for (DirectionIndex : DirectionIndices):
        Range := NumTilesToEdge(StartTile, DirectionIndex)
        Print("Checking direction index {DirectionIndex} with EdgeDist = {Range}")

        # 1. Loop from 1..Range instead of 0..Range. This removes the N<>0 check.
        # 2. Check IsTargetValid in the for loop. If it fails, the loop continues
        #    to the next iteration
        for:
            N := 1..Range
            TargetTile := StartTile + DirectionOffsets(DirectionIndex) * N
            # If IsTargetTileValid[] fails the loop will continue to the next iteration
            IsTargetTileValid[TargetTile, Piece]
        do:
            Print("Added move")
            set Moves += array{ move{ Start := StartTile, arget := TargetTile }}

    return Moves

If we want to go further there are two additional steps that can be taken to remove even more code. I’ll break them down below.

# (2) Using for's power to emit arrays for the inner loop
GetPossibleSlidingMoves(Piece:chess_piece, Direction:direction_indices):[]move =
    var Moves:[]move = array{}
    StartTile := Piece.Pos

    for (DirectionIndex : DirectionIndices):
        Range := NumTilesToEdge(StartTile, DirectionIndex)
        Print("Checking direction index {DirectionIndex} with EdgeDist = {Range}")

        # For loop creates a new array containing the item emitted from the "do" block
        NewMoves:[]move = for:
            N := 1..Range
            TargetTile := StartTile + DirectionOffsets(DirectionIndex) * N
            # If IsTargetTileValid[] fails the loop will continue to the next iteration
            IsTargetTileValid[TargetTile, Piece]
        do:
            # Return a new move that will be added to NewMoves automatically
            move{ Start := StartTile, Target := TargetTile }

        # Append the whole NewMoves array at once to Moves.
        set Moves += NewMoves

    return Moves
# (3) Using for's power to loop over multiple items. This turns nested for loops into one loop.
GetPossibleSlidingMoves(Piece:chess_piece, Direction:direction_indices):[]move =
    Moves := for:
        DirectionIndex : DirectionIndices
        Range := NumTilesToEdge(StartTile, DirectionIndex)
        # Now this loop will go over all the combinations of (DirectionIndex, N)
        N := 1..Range
        TargetTile := Piece.Pos + DirectionOffsets(DirectionIndex) * N
        # If IsTargetTileValid[] fails the loop will continue to the next iteration
        IsTargetTileValid[TargetTile, Piece]
    do:
        # Return a new move that will be added to NewMoves automatically
        move{ Start := StartTile, arget := TargetTile }

    return Moves
3 Likes

Thanks a ton!

Do you know how to solve this error with this type of for loop?

Take a look at the “Effect Specifiers” section of this document. It outlines the types of effects you can add to your functions. If no specifier is provided then the system precautiously uses the no_rollback effect, which is not allowed to be used in failure contexts like the clause section of an if or for.

In this case your NumTilesToEdge and DirectionOffsets functions likely require one of <transacts>, <varies>, or <computes> depending on what they’re doing. Adding one of those specifiers will indicate that they can be used in the for loop context.

1 Like

In nearly all my functions I use Print to print errors. But when I use the effect specifier that my function needs I can no longer use Print because Print has the no_rollback effect. Any idea how I can use the specifiers and also log/print errors