When I was much younger I used to read Scientific American. In those days, it had a regular column by AK Dewdney called “Computer Recreations”. Eventually, several of his columns were compiled into a book called “The Armchair Universe” of which I had a copy, but I suspect my parents donated it to the Church Fête bookstall. Anyway, my brother independently discovered the same book, so I bought a replacement copy off Amazon (it’s out of print, so my copy is second hand).
I thought recreating the computer recreations from the book would make a good idea for a series of blog posts, so here’s the first one: Sharks and Fishes(es).
The mythical planet of WaTor is a torus; it’s shaped like a doughnut. By a happy coincidence, this means you can simulate it with a rectangular grid where going North off the top brings you onto the bottom, going East of the right edge brings you onto the left edge and vice versa in both cases.
WaTor is entirely covered in water and has two species of animal in it: fish and sharks. The fish wander around at random and breed occasionally. The sharks, being carnivorous, wander arounds in search of fish to eat and also breed occasionally. Sharks will starve if they go too long without eating. Both fish and sharks breed asexually.
Time on WaTor is measured in chronons.
The World of Wator is a simulation designed to illustrate predator-prey relationships. The populations of fish and sharks rise and fall in cycles. The fish population rises. The shark population rises in response because there is loads of food. Eventually, the fish population crashes because they are all being eaten by sharks and that causes the shark population to crash because there is not enough food.
My implementation of WaTor differs significantly from that of AK Dewdney. For a start, I can have much larger grids. Dewdney’s implementation had a grid of about 30 units square. One of his colleagues implemented Wator on a VAX 11 with an 80 x 23 grid. This seemed to be the limit of what was achievable in those days. I’ve tried grids up to 200 x 200 and these work fine without any real optimisations for speed – no graphics acceleration or anything. As it turns out, the size of the grid really matters. The larger the grid, the more stable the populations seem to be. I tend to think this might be due to localisation. Population crashes in one part of the world are balanced by explosions elsewhere.
The other major difference is the way in which I represent the world. AK Dewdney used arrays of integers to represent each parameter that needed tracking. For fish there is one parameter – its age. This tells you when it is time for a fish to breed. For a shark there are two parameters – age and time it last ate. So there were two arrays needed for the sharks. Additionally, there were two more arrays that recorded whether each animal had moved or not this chronon. In my implementation, there is a class called
Animal and two subclasses
Shark that model the two species. The parameters of breeding age and starvation time are instance properties of the fish and sharks. Technically, this is not necessary since they have the same value for all instances, but I envisage a future enhancement in which these parameters might vary on an individual basis.
WaTor itself is a two dimensional array of
Optional<Animal>. Each element of the array is either a
nil. WaTor is modelled by the
The algorithm is much as defined by AK Dewdney except using my data structures.
- Fish move and breed. We make a list of all the fish and shuffle it (shuffling is an expensive operation and may change). Then each fish is moved to a random empty adjacent cell. If it is time to breed, a clone is created on the cell just vacated.
- Sharks move and breed. We make a list of all the sharks and shuffle it. Each shark will be moved to an adjacent cell containing a fish, if there is one. The fish is deemed to have been eaten. If there are no fish nearby, the shark will move to a random empty cell. If the shark has moved and it’s time to breed, a clone is created on the cell just vacated.
I need to record statistics so that we can show pretty graphs of the population changes.
It would be nice to allow variability of breeding age and starvation age as an evolution demonstration but there needs to be a downside to decreasing the former or increasing the latter. My current thoughts are to introduce some concept of energy, so a fish has a certain amount of energy that increases slowly over time and it must be split when it breeds. Similarly each shark gets the energy of the fish it eats and it dies when it runs out and when it breeds it splits the energy between it and its offspring.
You can find the code in my Bit Bucket repository. The version of the program used in the screen recording above is tagged at
version_1and is located at