Python list question

Hi all

I have a script that is dealing with a list of ships that are racing. The number of racers can be selected at the start of the race.

Now the fun begins!

During the race each ships lap is recorded- and so as each ship passes the start/ finish line a string will print the result. The main problem I am trying to get around is that ships can be destroyed, so the way in which this information is recorded needs to be flexible.

This is the code:


try:
        ship[0] is not None
        
        ship_in_race = bge.logic.getCurrentController().sensors["Collision"].hitObject
        
        if collision.positive and ship_in_race == ship[0] and ship[0]["lap"] > 0:
            
           ow["ship_1_lap_time"] = ship_in_race["race_time"]
            
           print(str("First place:") + str(" ") + str(ship_in_race) + str(" ") + str("lap time:") + str(" ") + ow["ship_1_lap_time"])
           
    except IndexError: 
    
        print("ship was not selected at race start or has been destroyed") 

As you can see, the script creates a reference to any ship that activates the collision sensor, and checks to see if that object in the list exists. There are eight properties that are used by the controlling object to store up to eight lap times.

If the racer does not exist, it generates an exception (in the case of a ship that is destroyed or is not selected) and one of the eight lap time properties is not written to.

Now my question: is there a way to get around using a try / except style approach to this? In essence is there a way of stopping an ‘out of index’ error without ignoring it like I am doing here?

If I do choose to keep the try /except approach, would it cause any problems later along the line?

I hope this makes sense!

Cheers

Paul

By what I saw you really don’t need to use lists, which are for things which need to be checked into a given order; use a python dict, dicts are for when you do not need to check things into a given order, as you’re just storing the racer state and laps; dicts are easier to use also.

I would store available racers into that dict, if the car isn’t selected, it shouldn’t even be part of the dict(your game should load only what it needs); if the car is destroyed, you could just replace the object pointer in the dict by a None, ‘destroyed’ or whatever you think would be explanative for that state, and if it should forgot about cars which are destroyed(including laps), you should delete the dictionary entry regarding that racer when that happens.

Dicts are like:

racers = {}

racers['racer_1'] = [car_obj, [put laps here]] 

I would use a for loop to check for each racer in that dict if it hit that collision point you talked about.

I think also you could write for the print instead:

print(str("First place: “) + str(ship_in_race) + str(” lap time: ") + ow[“ship_1_lap_time”])

You could check gameobject.invalid to see if the game object has been removed.

Better yet, don’t get in the situation in the first place. Every time you delete a game object, make sure you also remove any references to it elsewhere in your code.

And in my opinion, try / except is totally acceptable for use although it does make debugging a bit harder.

i tried to clean a list by using try / except,

this is the best result:


    L=list(ow["L"])
    for i in L:
        try:
            print(i.position)
        except:
            ow["L"].remove(i)

using the attribute .invalid:
start>>

ow[“L”]=[i for i in ow[“L”] if not i.invalid]

>>end

:wink:

i think, but I may be wrong,

that the try / except is used to avoid jumping the successive lines in case of error (which would cause more errors)

In fact, if you have an error at line 15,
line 16 - 17 - 18, etc. are not performed

instead with the try / except are performed anyway

try…except is quite a good message to deal with expected error processing. It is a well known method. E.g. in Java this is called Exceptions.

The advantage is the processing can return multiple different error conditions rather than mixing it with “good case results”.

It is strongly advised to keep the caught statement as small as possible.

This is because after an error the succeeding code will not be executed as Marco mentioned. This can produce to a broken program state (e.g. half of the variables are set with new values, others remain with old values).
Additional multiple statements can produce the same error. With one try…except it is impossible to tell which one was the error cause.

All caught errors should be expected. The error handling should be specified. Error handling can produce errors too.

Thanks for the replies everyone!

Its an interesting problem as I am thinking of trying to get the chunk of code above to be generated per ship, but it seems a lot of hassle when I can just have eight pre-coded chunks. I was considering globalDict but I would still need to order the ships as they cross the line…shame as it would be easier to do (in theory).

As an amendment, I have moved the ow[“ship_1_lap_time”] into a Python created variable within the code block as a start (so unless the try /except is true the property is not generated…or I hope thats whats happening…:confused:). This is the code below:


try:
        ship[0] is not None
        
        ow["ship_1_lap_time"] = 0.0 # code generated property / variable
        
        ship_in_race = bge.logic.getCurrentController().sensors["Collision"].hitObject
        
        if collision.positive and ship_in_race == ship[0] and ship[0]["lap"] > 0:
            
           ow["ship_1_lap_time"] = ship_in_race["race_time"]
            
           print(str("First place: ") + str(ship_in_race)  + str(" lap time: ") + str(round(ow["ship_1_lap_time"],2)))

I suppose I could make a function that does this… maybe some homework foe me to do!

that is the problem of try/except

i learn it right now,

so, to make a good debug need to write try / except for once line!!

something like:


    if sens.status==1:
        try:
            a = variableWRONG #line read(error inside)
            print("a-try")    #line NOT read! (i had thinked different)
        except:
            print("a-except") #line read
            
        try:
            b = 1             #line read (without error)
            print("b-try")    #line read
        except:
            print("b-except") #line NOT read

you have tried to using obj.invalid ?

this should work to check if a obj is death

Thanks Marco! Will try obj.invalid later and see what happens!

i think is the best solution

i hope to not adding confusion…
regard the try…except , and the “jumping line”:
suppose which “target” can be a reference wrong for some reason.
try/except can avoid other error


in this case "time" is assigned corrrectly(with or without reference wrong by "target")
#################
try:
    own.worldPosition = target.worldPosition 
except:
    pass

own["time"]+=1
#################



without try/except, if "target" is a reference wrong also "time" is not assigned (so ,can due other error)
#################
own.worldPosition = target.worldPosition 
own["time"]+=1
#################

Out of interest, what would the syntax be?

If I put:


if ship[0].invalid:

   None

I get out of index errors.

“ship” is a list right?

you can clean all list in this way:

oldList = ship
newList = [i for i in oldList if not i.invalid] #create a new list without obj invalid
ship = newList #replace the list (clean)

which is the same of:
ship = [i for i in ship if not i.invalid]

at this point ship[0] should be correct (if the list is not empty)

or


if ship[0].invalid:
    del ship[0]

if you not have a huge list (1000 ships) i counsill the first

EDIT: out of index(with index[0]) … the list is empty

Cool, thanks again, Marco!

Also, congratulations in 2 posts time…its your 1000th post!

yeah I’m old! ;D

What is it they say, life begins at 1000?

40 max! :smiley:

solved?

hint: with dictionary and list, try to use the consolle interactive in blender

thats is much too fast than make test in bge

you not need to import anything or use object

hust write:

L=[4,5,1] #press key return

L#return (instead of >> print(L) )

>>>[4,5,1]

L[0]

>>>4

len(L)

>>>3

Thanks for the follow up, Marco, as I was dealing with this (I re-wrote my original code slightly to make it more/ slightly logical) my daughter has started teething…so I’ve had to deal with that!

Eventually I will have to write from scratch as I have been trying to add more functionality to the timer- things like lap times, total race time, time difference between racers etc. I’ll have to send you what I’ve done so far (more flying cubes!!) so you can take a look.

I read something above about using dictionary and lists? If you have the need for the easiness of dictionaries and the ordering power of lists, there is the python OrderedDict module.