Inside the A-Life Challenge

Now that I’ve had a few weeks to figure things out and implement a working barebones GUI, let’s talk about the program structure and my approach to building a GUI in Python.

The concept for the backbone of the program is very simple: we have two screens, a starting parameters screen and a simulation screen. The starting parameters screen allows the user to customize basic attributes of the organisms. The animation is all handled in the simulation screen and individual organisms are instantiated and their information is tracked using an Organism class. All these features are modularized with separate .py files for each screen, the Organism class, settings, and additionally for the simulation steps.

So what exactly do I mean by the “simulation steps”? First, I should point out that in order to have a realistic and fair simulation of multiple organisms, it’s important that all of the organisms are able to act synchronously. Otherwise, whichever organism goes first will always have an advantage and our simulation will quickly depart from realism.

However, it turns out that Python is a bit cumbersome when it comes to multithreading. There is a way to fork child processes, but nothing so robust as, for example, OpenMP for C++. That’s not too much of a problem, since on a regular PC with only a handful of cores to work with, there is no way we could get true synchronicity with the organisms in our simulation anyway. Using child processes or OpenMP, we would be at the mercy of the kernel’s task scheduler and whatever random order it decided to put the threads in (threads in this case representing an individual organism). So, I had a better idea – simulate synchronicity through turns with steps, similar to a boardgame. Once I had this idea, I started to envision the simulation in its entirety as a boardgame, with organisms having statistics such as health, damage, speed, etc. Personally, this made the project a lot more interesting for me too!

We broke our turns down to four steps: 1) set destination, 2) move, 3) battle, and 4) conclusion. All organisms must complete a step before the next step starts, and no organisms are removed from the simulation until they have dealt/received damage. The turns repeat forever until the user decides to stop the simulation. With this approach, we are able to simulate synchronicity in such a way that multithreading is not necessary.

Let’s cover the turn steps in more detail.

1. Set Destination

Each organism has a means of tracking other organisms through vision. Using this ability, predators and prey determine a new destination at the beginning of each turn based on basic behaviors, i.e. prey run away from predators and predators run towards prey. We may implement more sophisticated behaviors here, such as flocking for prey.

One issue with the simulation is that in order to make the animation appear to be smooth, the organisms must make very small movements each turn. The result is that turns happen frequently – many times per second – and attention span becomes an issue with the organisms if they are constantly choosing a new destination. So, we have implemented a rudimentary attention span that keeps the organisms going to the same destination most of the time.

2. Move

Movement is accomplished by erasing and redrawing the organisms in very small increments as they make their way to their individual destinations.

This step is conceptually simple, but it was probably the trickiest in terms of animation using Python turtle, which is the basis for the visual component of the simulation. Turtle is a pretty basic graphics library for Python that I believe was originally intended for education purposes. It is pretty good for drawing lines and shapes, and for having a set number of animated ‘turtles’ – turtles in this case representing a moving object with a customizable shape. In our case, the shapes are just dots with a diameter of 10 pixels, colored red for predators and green for prey.

Even after many hours of researching and trying various ways to animate our simulation, there seems to be no way to avoid the animation slowing down significantly as the number of turtles increases. My best fix so far for this problem is to adjust a variable I call slow_factor, which causes the turtles to be redrawn at farther and farther distances (in effect, speeding them up) the lower it goes. Eventually I will implement a linear (possibly exponential) equation that best allows animation speed to remain constant as the number of organisms increase. We may have to introduce an organism cap to avoid anything too crazy happening, though.

3. Battle

Battle is the exchange of damage between organisms that are close enough to another organism of the opposite type to attack/defend. Damage is deducted from health totals, but nothing else happens to the organisms in this step in order to assure that all organisms are allowed to deal and receive damage.

4. Conclusion

Finally, the conclusion step is a catch all that is intended to encompass all the activity that is required to update the status of the board. These activities include removing dead organisms from the board, reproducing new organisms, and updating statistics.

Since organisms are stored in a list, each activity will be carried out in succession for each organism in order to reduce time complexity.

Overall, we’ve managed to maintain a time complexity of O(n2) in the program, with the destination being the most costly step in the turn – since each organism searches through the list once to find nearby organisms. Unfortunately, that’s enough to make animation a little tricky as I mentioned in the Move step, but a little challenge helps keep it interesting!

Hopefully you have a good idea about the basic structure of the project now. Next time, I plan to expound a little on the tkinter windows and how they’re structured, as well as give you updates on how things are coming along. Until then!

Print Friendly, PDF & Email

Posted

in

by

Tags:

Comments

Leave a Reply

Your email address will not be published. Required fields are marked *