Home > Net >  I can't find a method to prevent my program slowing down as it loads more sprites python
I can't find a method to prevent my program slowing down as it loads more sprites python

Time:11-18

I have created a simple simulation to show evolution. It works through a simuple window that contains many squares representing single-celled organisms. The screen looks like this:

enter image description here

The single-celled organisms (dubbed amoebae for conciseness) move around randomly. If they collide with another amoebae they produce an offspring. However, to prevent them reproducing infinitely I introduced an age measure. Amoebae must attain a certain age before they reproduce and once they do their age is reset to 1.

Now for the evolution part. As you can see, the amoebae are different colours. This represents the 'gene' that is passed down to offspring through reproduction (there is a chance of mutation controlled by a constant called maturingSpeed, which I set very high to increase the speed of evolution). It's called maturingSpeed and it controls the speed at which the amoebae age, which means that amoebae that have a higher maturingSpeed with reproduce faster and pass on their gene. In this way, they should gradually evolve through natural selection so all of the amoebae have a very high maturingSpeed. A high maturingSpeed translates to a brighter colour on the screen.

There is one other thing I should mention, which is the life countdown on each amoeba. It starts out at 10000 and ticks down by one each time the amoeba is updated. This is to gradually kill off the old amoebae, also increasing the rate of evolution and making it more lifelike.

My problem is that before the amoebae all evolve to get a high maturingSpeed (the highest I've had is around 65%), they become too numerous and the simulation starts slowing down as it struggles to load them all. I need a method to make the amoebae die off faster as more of them are produced. I have tried to cull them if they are above a certain number, or increase their countdown rate based on the number of amoebae however all of these methods cause them to eventually stop reproducing and die off for some reason. I have deleted these sections from my code now because they didn't work but I could add them again if needed.

My source code:

import pygame
import random
import time
import itertools

from pygame.locals import (
    QUIT
)

pygame.init()
SCREEN_WIDTH = 500
SCREEN_HEIGHT = 500
screen = pygame.display.set_mode([500, 500])
amoebas = pygame.sprite.Group()
all_sprites = pygame.sprite.Group()
idList = []
mutationConstant = 254

class Amoeba(pygame.sprite.Sprite):
    
    id_iter = itertools.count()
    
    def __init__(self, maturingSpeed, x, y):
        super(Amoeba, self).__init__()
        self.id = 'amoeba'   str(next(Amoeba.id_iter))
        idList.append(self.id)
        self.surf = pygame.Surface((10,10))
        if maturingSpeed <= 0:
            maturingSpeed = 1
        elif maturingSpeed >= 255:
            maturingSpeed = 254
        print(maturingSpeed)
        self.surf.fill((maturingSpeed, 0, 0))
        self.rect = self.surf.get_rect(
            center=(
                x,
                y,
            )
        )
        self.speed = 2
        self.age = 1
        self.maturingSpeed = int(maturingSpeed)
        self.life = 9999

        
    def update(self):
        if self.rect.left <= 0:
            direction = 1
        elif self.rect.right >= SCREEN_WIDTH:
            direction = 2
        elif self.rect.top <= 0:
            direction = 3
        elif self.rect.bottom >= SCREEN_HEIGHT:
            direction = 4
        else:
            direction = random.randint(1, 4)
            
        if direction == 1:
            self.rect.move_ip(self.speed, 0)
        elif direction == 2:
            self.rect.move_ip(-self.speed, 0)
        elif direction == 3:
            self.rect.move_ip(0, self.speed)
        elif direction == 4:
            self.rect.move_ip(0, -self.speed)

        self.life = self.life - 1
        if self.life <= 0:
            self.kill()

            
        modMaturingSpeed = self.maturingSpeed / 1240
        self.age = self.age   (1 * modMaturingSpeed)
            
    @classmethod
    def collide(cls):
        global collisionSuccess
        collisionSuccess = False
        
        global posList
        posList = [[amoeba.rect.left, amoeba.rect.bottom] for amoeba in amoebas]
        length = len(posList)

        for i in range(length):
          for amoeba in amoebas:
              if amoeba.id == str(idList[i]):
                  ageOne = getattr(amoeba, 'age')
                  
                  for h in range(i 1, length):
                      for amoeba in amoebas:
                          if amoeba.id == str(idList[h]):
                              ageTwo = getattr(amoeba, 'age')

                              OneX = int(posList[i][0])
                              OneY = int(posList[i][1])
                              TwoX = int(posList[h][0])
                              TwoY = int(posList[h][1])

                              if ageOne >= 100 and ageTwo >= 100:
                                  if (OneX < TwoX   10 and OneX   10 > TwoX
                                      and OneY < TwoY   10 and 10   OneY > TwoY):
                                      
                                      for amoeba in amoebas:
                                          if amoeba.id == str(idList[i]):
                                              setattr(amoeba, 'age', 1)
                                              pOMSinitial = int(getattr(amoeba, 'maturingSpeed'))
                                                  
                                      for amoeba in amoebas:
                                            if amoeba.id == str(idList[h]):
                                                setattr(amoeba, 'age', 1)
                                                pTMSinitial = int(getattr(amoeba, 'maturingSpeed'))
                                        
                                      locationX = OneX   random.randint(-10, 10)
                                      locationY = OneY   random.randint(-10, 10)
                                      if pOMSinitial >= pTMSinitial:
                                            pOMSfinal = pOMSinitial   mutationConstant
                                            pTMSfinal = pTMSinitial - mutationConstant
                                            newMaturingSpeed = random.randint(pTMSfinal, pOMSfinal)
                                      else:
                                            pOMSfinal = pOMSinitial - mutationConstant
                                            pTMSfinal = pTMSinitial   mutationConstant
                                            newMaturingSpeed = random.randint(pOMSfinal, pTMSfinal)

                                      collisionSuccess = True
                                      return cls(newMaturingSpeed, locationX, locationY)

screen.fill((255, 255, 255))

for i in range(15):
        amoebaname = Amoeba(random.randint(100, 150), random.randint(0, SCREEN_WIDTH), random.randint(0, SCREEN_HEIGHT))
        amoebas.add(amoebaname)
        all_sprites.add(amoebaname)

p = 0

while True:
    ageArray = [amoeba.age for amoeba in amoebas]
    
    if p == 1000:
        print(amoebas)
        five = 0
        four = 0
        three = 0
        two = 0
        one = 0
        
        for amoeba in amoebas:
            if amoeba.maturingSpeed >= 200:
                five = five   1
            elif amoeba.maturingSpeed >=150:
                four = four   1
            elif amoeba.maturingSpeed >= 100:
                three = three   1
            elif amoeba.maturingSpeed >= 50:
                two = two   1
            else:
                one = one   1
                
        total = one   two   three   four   five
        DivFive = five / total
        DivFour = four / total
        DivThree = three / total
        DivTwo = two / total
        DivOne = one / total

        print(DivFive, DivFour, DivThree, DivTwo, DivOne)
        
        p = 0
    else:
        p = p   1


    time.sleep(0.0000001)
    screen.fill((255, 255, 255))
    
    for event in pygame.event.get():
        if event.type == QUIT:
            break
        
    amoebas.update()
    amoebaname = Amoeba.collide()
    if collisionSuccess == True:
        amoebas.add(amoebaname)
        all_sprites.add(amoebaname)

    for entity in all_sprites:
        screen.blit(entity.surf, entity.rect)
        
    pygame.display.flip()
    

pygame.quit()

CodePudding user response:

Too many nested loops and unneeded data structures. I did some cleanup and it's faster now. And it seems that the mutation constant was far to high. I changed the value from 254 to 25.

import pygame
import random
import time
import itertools

from pygame.locals import (
    QUIT
)

SCREEN_WIDTH = 500
SCREEN_HEIGHT = 500
MUTATION_CONSTANT = 25

pygame.init()
screen = pygame.display.set_mode([SCREEN_WIDTH, SCREEN_HEIGHT])
amoebas = pygame.sprite.Group()


class Amoeba(pygame.sprite.Sprite):
    id_iter = itertools.count()

    def __init__(self, maturing_speed, x, y):
        super().__init__()
        self.id = 'amoeba'   str(next(Amoeba.id_iter))
        self.surf = pygame.Surface((10, 10))
        self.maturing_speed = min(max(maturing_speed, 1), 254)
        self.surf.fill((self.maturing_speed, 0, 0))
        self.rect = self.surf.get_rect(center=(x, y,))
        self.speed = 2
        self.age = 1
        self.life = 9999

    def update(self):
        if self.rect.left <= 0:
            direction = 1
        elif self.rect.right >= SCREEN_WIDTH:
            direction = 2
        elif self.rect.top <= 0:
            direction = 3
        elif self.rect.bottom >= SCREEN_HEIGHT:
            direction = 4
        else:
            direction = random.randint(1, 4)

        if direction == 1:
            self.rect.move_ip(self.speed, 0)
        elif direction == 2:
            self.rect.move_ip(-self.speed, 0)
        elif direction == 3:
            self.rect.move_ip(0, self.speed)
        elif direction == 4:
            self.rect.move_ip(0, -self.speed)

        self.life = self.life - 1
        if self.life <= 0:
            self.kill()

        self.age = self.age   (1 * self.maturing_speed / 1240)

    @classmethod
    def collide(cls):
        for amoeba_1, amoeba_2 in itertools.combinations(amoebas, 2):
            if amoeba_1.age >= 100 and amoeba_2.age >= 100 and (
                pygame.sprite.collide_rect(amoeba_1, amoeba_2)
            ):
                amoeba_1.age = 1
                amoeba_2.age = 1

                location_x = amoeba_1.rect.left   random.randint(-10, 10)
                location_y = amoeba_1.rect.bottom   random.randint(-10, 10)

                speed_low = min(amoeba_1.maturing_speed, amoeba_2.maturing_speed) - MUTATION_CONSTANT
                speed_high = max(amoeba_1.maturing_speed, amoeba_2.maturing_speed)   MUTATION_CONSTANT
                new_maturing_speed = random.randint(speed_low, speed_high)
                
                return cls(new_maturing_speed, location_x, location_y)
        return None


def main():
    screen.fill((255, 255, 255))

    for i in range(25):
        amoeba = Amoeba(random.randint(100, 150), random.randint(0, SCREEN_WIDTH), random.randint(0, SCREEN_HEIGHT))
        amoebas.add(amoeba)

    step_counter = 0
    while True:
        step_counter  = 1
        if step_counter % 100 == 0:
            print(step_counter, amoebas)
            five = 0
            four = 0
            three = 0
            two = 0
            one = 0

            for amoeba in amoebas:
                if amoeba.maturing_speed >= 200:
                    five = five   1
                elif amoeba.maturing_speed >= 150:
                    four = four   1
                elif amoeba.maturing_speed >= 100:
                    three = three   1
                elif amoeba.maturing_speed >= 50:
                    two = two   1
                else:
                    one = one   1

            total = one   two   three   four   five
            print(f'{five/total:.4f} {four/total:.4f} {three/total:.4f} {two/total:.4f} {one/total:.4f}')

        time.sleep(0.0000001)
        screen.fill((255, 255, 255))

        for event in pygame.event.get():
            if event.type == QUIT:
                break

        amoebas.update()
        amoeba = Amoeba.collide()
        if amoeba:
            amoebas.add(amoeba)

        for amoeba in amoebas:
            screen.blit(amoeba.surf, amoeba.rect)

        pygame.display.flip()

    pygame.quit()


if __name__ == '__main__':
    main()
  • Related