1

My very first post, sorry if I made any mistakes!

I'm messing around the pygame library, and I'm extremely new to python in general. I have created 3 enemies classes and they work as intended, however, this is how I make them move (I call the move function stored inside the class).

I wonder if there is a more clean way to do things. I have many other enemies to code and this seems very repetitive to type, so it's a sign I'm doing something wrong.

I tried creating a "control list" where I list every enemy list there is and I try to access them through their index but it isn't working. I also tried to concatenate but I'm getting an error saying I can't concatenate list names, another error was that my list names turned into strings (yes, I tried using quotation marks). I'm sure this will be a simple fix, but I spent 3 days and I wrap my head around it. If it's possible to do so

The sample of my code so far - it is located in the main run loop of my game.

    for giant in lst_enemy_giants:
        giant.move()
    else:
        pass

    for spider in lst_enemy_spiders:
        spider.move()
    else:
        pass

    for goblin in lst_enemy_goblin:
        giant.move()
    else:
        pass

# The pattern the I want
    for ENEMY in lst_enemy_ENEMY:
        ENEMY.move()

# where ENEMY is any enemy list that can be stored somewhere
Rabbid76
  • 202,892
  • 27
  • 131
  • 174

1 Answers1

3

Just chain the iterators together.

from itertools import chain

for enemy in chain(lst_enemy_giants, lst_enemy_spiders, lst_enemy_goblin):
    enemy.move()

This is a slightly nicer way of writing a nested loop like

for enemy_list in [lst_enemy_giants, lst_enemy_spiders, lst_enemy_goblin]:
    for enemy in enemy_list:
        enemy.move()

Unrelated, but I recommend keeping a single dict like

enemies = {'giants': [...], 'spiders': [...], 'goblins': [...]}

rather than three separate variables referencing separate lists. You can still use, for example, enemies['giants'] anywhere you would have used lst_enemy_giants, but now you can write

for enemy in chain(*enemies.values()):
    enemy.move()
chepner
  • 497,756
  • 71
  • 530
  • 681
  • Interesting. Of course, all of the enemy objects need a `move()` method, which is an Interface principle. I wonder if Type Hints can help enforce this in modern Python3. – h0r53 Oct 28 '21 at 17:00
  • Yes, using `typing.Protocol`. That's beyond the scope of this question, which is addressing a situation where it is already assumed that each enemy object has a `move` method. – chepner Oct 28 '21 at 17:02
  • Oh the second method worked wonderfully! I made so much sense too. I didn't know that I could actually do that. Thank you so much! – Chaotic Dwarf Oct 28 '21 at 17:02
  • @chepner would you mind providing an example with `typing.Protocol`? I am very interested in how you might make this technique type-safe. – h0r53 Oct 28 '21 at 17:03
  • 1
    @h0r53 See https://stackoverflow.com/questions/29022766/what-to-use-in-replacement-of-an-interface-protocol-in-python/50255847#50255847. – chepner Oct 28 '21 at 17:04