CREATE YOUR AI CUM SLUT ON CANDY.AI TRY FOR FREE
x

Ren'Py Python Container / Object / For Loop Glitch

Xavster

Well-Known Member
Game Developer
Mar 27, 2018
1,249
7,626
For my game Stellar Crossroads I am completing a covert mission mechanic and am encountering the following glitch when attempting to search a container and move objects into another container that satisfy a certain condition.
Python:
    def agent_allocate():
        for sagent in covertactive.agents:
            if sagent.status == "Selected":
                sagent.status = "CM-{:03d}".format(covert_counter)
                move_agent(sagent, covertactive, covertmission)
The code above searches the covertactive container and moves agents to the covertmission container that satisfy the "Selected" criteria. It is working inconsistently however, in that when I have agents that are adjacent to each other in the container it fails to move the second agent. From what I can tell, the for loop is skipping over the second agent and not testing them.

Say items 3 and 4 in the container satisfy the criteria, the for loop works correctly on the 3rd item, however the next loop looks at the 4th item in the revised container, which before the move function was actually the 5th. Hence the 4th item never gets tested.

Is there a way of adjusting the code above to relieve this problem?
 

Winterfire

Forum Fanatic
Respected User
Game Developer
Sep 27, 2018
5,527
8,062
For my game Stellar Crossroads I am completing a covert mission mechanic and am encountering the following glitch when attempting to search a container and move objects into another container that satisfy a certain condition.
Python:
    def agent_allocate():
        for sagent in covertactive.agents:
            if sagent.status == "Selected":
                sagent.status = "CM-{:03d}".format(covert_counter)
                move_agent(sagent, covertactive, covertmission)
The code above searches the covertactive container and moves agents to the covertmission container that satisfy the "Selected" criteria. It is working inconsistently however, in that when I have agents that are adjacent to each other in the container it fails to move the second agent. From what I can tell, the for loop is skipping over the second agent and not testing them.

Say items 3 and 4 in the container satisfy the criteria, the for loop works correctly on the 3rd item, however the next loop looks at the 4th item in the revised container, which before the move function was actually the 5th. Hence the 4th item never gets tested.

Is there a way of adjusting the code above to relieve this problem?
Try slicing

Python:
    def agent_allocate():
        for sagent in covertactive.agents[:]:
            if sagent.status == "Selected":
                sagent.status = "CM-{:03d}".format(covert_counter)
                move_agent(sagent, covertactive, covertmission)
 

Xavster

Well-Known Member
Game Developer
Mar 27, 2018
1,249
7,626
Try slicing

Python:
    def agent_allocate():
        for sagent in covertactive.agents[:]:
            if sagent.status == "Selected":
                sagent.status = "CM-{:03d}".format(covert_counter)
                move_agent(sagent, covertactive, covertmission)
Works like a charm. Knew this was the right place to ask. ;)
 

anne O'nymous

I'm not grumpy, I'm just coded that way.
Modder
Donor
Respected User
Jun 10, 2017
11,009
16,293
Try slicing
Exactly.


When one use for x in whateverList Python iterate the said "whateverlist" list in real time. Therefore, each time you add or remove an entry from/to "whateverlist", its value change, and the iteration change too.

As example, let's iterate a basic list of numbers, removing every odd numbers:
Python:
label start:

    $ abc = [ 1, 2, 3, 4, 5, 6, 7]
    $ count = 0
    python:
        for i in abc:
            renpy.say( None, "index: {} | value: {}".format( count, i ) )
            count += 1
            if i % 2:
                abc.remove( i )

    "END"
The result will be:
  • index: 0 | value: 1
  • index: 1 | value: 3
  • index: 2 | value: 5
  • index: 3 | value: 7

This happen because the iterated value is constantly updated:

  • Loop 1
    Python use the value at the index 0, that is 1.
    This is odd number, Python remove it from the list.
    The list become [ 2, 3, 4, 5, 6, 7 ]
  • Loop 2
    Python use the value at the index 1, that is now 3 because the list have changed.
    This is also a odd number, Python remove it from the list.
    The list become [ 2, 4, 5, 6, 7 ]
  • Loop 3
    Python use the value at the index 2, that is now 5 because the list have changed again.
    This is also a odd number, Python remove it from the list.
    The list become [ 2, 4, 6, 7 ]
And so on.


But when you iterate through a copy of the list, the iterated value stay constant:
Python:
label start:

    $ abc = [ 1, 2, 3, 4, 5, 6, 7]
    $ count = 0
    python:
        for i in abc[:]:
            count += 1
            renpy.say( None, "index: {} | value: {}".format( count, i ) )
            if i % 2:
                abc.remove( i )

    "END"
The result will be:
  • index: 0 | value: 1
  • index: 1 | value: 2
  • index: 2 | value: 3
  • index: 3 | value: 4
  • index: 4 | value: 5
  • index: 5 | value: 6
  • index: 6 | value: 7

This is possible because the list iterated is not the updated list, but a copy of it's value before any update.