cellular_automata.wa_tor¶
Wa-Tor algorithm (1984)
@ https://en.wikipedia.org/wiki/Wa-Tor @ https://beltoforion.de/en/wator/ @ https://beltoforion.de/en/wator/images/wator_medium.webm
This solution aims to completely remove any systematic approach to the Wa-Tor planet, and utilise fully random methods.
The constants are a working set that allows the Wa-Tor planet to result in one of the three possible results.
Attributes¶
Classes¶
Represents an entity (either prey or predator). |
|
Represents the main Wa-Tor algorithm. |
Functions¶
|
Visually displays the Wa-Tor planet using |
Module Contents¶
- class cellular_automata.wa_tor.Entity(prey: bool, coords: tuple[int, int])¶
Represents an entity (either prey or predator).
>>> e = Entity(True, coords=(0, 0)) >>> e.prey True >>> e.coords (0, 0) >>> e.alive True
- __repr__() str ¶
>>> Entity(prey=True, coords=(1, 1)) Entity(prey=True, coords=(1, 1), remaining_reproduction_time=5) >>> Entity(prey=False, coords=(2, 1)) Entity(prey=False, coords=(2, 1), remaining_reproduction_time=20, energy_value=15)
- reset_reproduction_time() None ¶
>>> e = Entity(True, coords=(0, 0)) >>> e.reset_reproduction_time() >>> e.remaining_reproduction_time == PREY_REPRODUCTION_TIME True >>> e = Entity(False, coords=(0, 0)) >>> e.reset_reproduction_time() >>> e.remaining_reproduction_time == PREDATOR_REPRODUCTION_TIME True
- alive = True¶
- coords¶
- energy_value¶
- prey¶
- remaining_reproduction_time¶
- class cellular_automata.wa_tor.WaTor(width: int, height: int)¶
Represents the main Wa-Tor algorithm.
- Attr time_passed:
A function that is called every time time passes (a chronon) in order to visually display the new Wa-Tor planet. The time_passed function can block using time.sleep to slow the algorithm progression.
>>> wt = WaTor(10, 15) >>> wt.width 10 >>> wt.height 15 >>> len(wt.planet) 15 >>> len(wt.planet[0]) 10 >>> len(wt.get_entities()) == PREDATOR_INITIAL_COUNT + PREY_INITIAL_COUNT True
- add_entity(prey: bool) None ¶
Adds an entity, making sure the entity does not override another entity
>>> wt = WaTor(WIDTH, HEIGHT) >>> wt.set_planet([[None, None], [None, None]]) >>> wt.add_entity(True) >>> len(wt.get_entities()) 1 >>> wt.add_entity(False) >>> len(wt.get_entities()) 2
- balance_predators_and_prey() None ¶
Balances predators and preys so that prey can not dominate the predators, blocking up space for them to reproduce.
>>> wt = WaTor(WIDTH, HEIGHT) >>> for i in range(2000): ... row, col = i // HEIGHT, i % WIDTH ... wt.planet[row][col] = Entity(True, coords=(row, col)) >>> entities = len(wt.get_entities()) >>> wt.balance_predators_and_prey() >>> len(wt.get_entities()) == entities False
- get_entities() list[Entity] ¶
Returns a list of all the entities within the planet.
>>> wt = WaTor(WIDTH, HEIGHT) >>> len(wt.get_entities()) == PREDATOR_INITIAL_COUNT + PREY_INITIAL_COUNT True
- get_surrounding_prey(entity: Entity) list[Entity] ¶
Returns all the prey entities around (N, S, E, W) a predator entity.
Subtly different to the try_to_move_to_unoccupied square.
>>> wt = WaTor(WIDTH, HEIGHT) >>> wt.set_planet([ ... [None, Entity(True, (0, 1)), None], ... [None, Entity(False, (1, 1)), None], ... [None, Entity(True, (2, 1)), None]]) >>> wt.get_surrounding_prey( ... Entity(False, (1, 1))) [Entity(prey=True, coords=(0, 1), remaining_reproduction_time=5), Entity(prey=True, coords=(2, 1), remaining_reproduction_time=5)] >>> wt.set_planet([[Entity(False, (0, 0))]]) >>> wt.get_surrounding_prey(Entity(False, (0, 0))) [] >>> wt.set_planet([ ... [Entity(True, (0, 0)), Entity(False, (1, 0)), Entity(False, (2, 0))], ... [None, Entity(False, (1, 1)), Entity(True, (2, 1))], ... [None, None, None]]) >>> wt.get_surrounding_prey(Entity(False, (1, 0))) [Entity(prey=True, coords=(0, 0), remaining_reproduction_time=5)]
- move_and_reproduce(entity: Entity, direction_orders: list[Literal['N', 'E', 'S', 'W']]) None ¶
Attempts to move to an unoccupied neighbouring square in either of the four directions (North, South, East, West). If the move was successful and the remaining_reproduction time is equal to 0, then a new prey or predator can also be created in the previous square.
- Parameters:
direction_orders – Ordered list (like priority queue) depicting order to attempt to move. Removes any systematic approach of checking neighbouring squares.
>>> planet = [ ... [None, None, None], ... [None, Entity(True, coords=(1, 1)), None], ... [None, None, None] ... ] >>> wt = WaTor(WIDTH, HEIGHT) >>> wt.set_planet(planet) >>> wt.move_and_reproduce(Entity(True, coords=(1, 1)), direction_orders=["N"]) >>> wt.planet [[None, Entity(prey=True, coords=(0, 1), remaining_reproduction_time=4), None], [None, None, None], [None, None, None]] >>> wt.planet[0][0] = Entity(True, coords=(0, 0)) >>> wt.move_and_reproduce(Entity(True, coords=(0, 1)), ... direction_orders=["N", "W", "E", "S"]) >>> wt.planet [[Entity(prey=True, coords=(0, 0), remaining_reproduction_time=5), None, Entity(prey=True, coords=(0, 2), remaining_reproduction_time=4)], [None, None, None], [None, None, None]] >>> wt.planet[0][1] = wt.planet[0][2] >>> wt.planet[0][2] = None >>> wt.move_and_reproduce(Entity(True, coords=(0, 1)), ... direction_orders=["N", "W", "S", "E"]) >>> wt.planet [[Entity(prey=True, coords=(0, 0), remaining_reproduction_time=5), None, None], [None, Entity(prey=True, coords=(1, 1), remaining_reproduction_time=4), None], [None, None, None]]
>>> wt = WaTor(WIDTH, HEIGHT) >>> reproducable_entity = Entity(False, coords=(0, 1)) >>> reproducable_entity.remaining_reproduction_time = 0 >>> wt.planet = [[None, reproducable_entity]] >>> wt.move_and_reproduce(reproducable_entity, ... direction_orders=["N", "W", "S", "E"]) >>> wt.planet [[Entity(prey=False, coords=(0, 0), remaining_reproduction_time=20, energy_value=15), Entity(prey=False, coords=(0, 1), remaining_reproduction_time=20, energy_value=15)]]
- perform_predator_actions(entity: Entity, occupied_by_prey_coords: tuple[int, int] | None, direction_orders: list[Literal['N', 'E', 'S', 'W']]) None ¶
Performs the actions for a predator entity
- Parameters:
occupied_by_prey_coords – Move to this location if there is prey there
- For predators the rules are:
At each chronon, a predator moves randomly to an adjacent square occupied
by a prey. If there is none, the predator moves to a random adjacent unoccupied square. If there are no free squares, no movement takes place.
At each chronon, each predator is deprived of a unit of energy.
Upon reaching zero energy, a predator dies.
If a predator moves to a square occupied by a prey,
it eats the prey and earns a certain amount of energy.
5. Once a predator has survived a certain number of chronons it may reproduce in exactly the same way as the prey.
>>> wt = WaTor(WIDTH, HEIGHT) >>> wt.set_planet([[Entity(True, coords=(0, 0)), Entity(False, coords=(0, 1))]]) >>> wt.perform_predator_actions(Entity(False, coords=(0, 1)), (0, 0), []) >>> wt.planet [[Entity(prey=False, coords=(0, 0), remaining_reproduction_time=20, energy_value=19), None]]
- perform_prey_actions(entity: Entity, direction_orders: list[Literal['N', 'E', 'S', 'W']]) None ¶
Performs the actions for a prey entity
- For prey the rules are:
At each chronon, a prey moves randomly to one of the adjacent unoccupied
squares. If there are no free squares, no movement takes place.
Once a prey has survived a certain number of chronons it may reproduce.
This is done as it moves to a neighbouring square, leaving behind a new prey in its old position. Its reproduction time is also reset to zero.
>>> wt = WaTor(WIDTH, HEIGHT) >>> reproducable_entity = Entity(True, coords=(0, 1)) >>> reproducable_entity.remaining_reproduction_time = 0 >>> wt.planet = [[None, reproducable_entity]] >>> wt.perform_prey_actions(reproducable_entity, ... direction_orders=["N", "W", "S", "E"]) >>> wt.planet [[Entity(prey=True, coords=(0, 0), remaining_reproduction_time=5), Entity(prey=True, coords=(0, 1), remaining_reproduction_time=5)]]
- run(*, iteration_count: int) None ¶
Emulate time passing by looping iteration_count times
>>> wt = WaTor(WIDTH, HEIGHT) >>> wt.run(iteration_count=PREDATOR_INITIAL_ENERGY_VALUE - 1) >>> len(list(filter(lambda entity: entity.prey is False, ... wt.get_entities()))) >= PREDATOR_INITIAL_COUNT True
- set_planet(planet: list[list[Entity | None]]) None ¶
Ease of access for testing
>>> wt = WaTor(WIDTH, HEIGHT) >>> planet = [ ... [None, None, None], ... [None, Entity(True, coords=(1, 1)), None] ... ] >>> wt.set_planet(planet) >>> wt.planet == planet True >>> wt.width 3 >>> wt.height 2
- height¶
- width¶
- cellular_automata.wa_tor.visualise(wt: WaTor, iter_number: int, *, colour: bool = True) None ¶
Visually displays the Wa-Tor planet using an ascii code in terminal to clear and re-print the Wa-Tor planet at intervals.
Uses ascii colour codes to colourfully display the predators and prey.
(0x60f197) Prey = # (0xfffff) Predator = x
>>> wt = WaTor(30, 30) >>> wt.set_planet([ ... [Entity(True, coords=(0, 0)), Entity(False, coords=(0, 1)), None], ... [Entity(False, coords=(1, 0)), None, Entity(False, coords=(1, 2))], ... [None, Entity(True, coords=(2, 1)), None] ... ]) >>> visualise(wt, 0, colour=False) # x . x . x . # . Iteration: 0 | Prey count: 2 | Predator count: 3 |
- cellular_automata.wa_tor.DELETE_UNBALANCED_ENTITIES = 50¶
- cellular_automata.wa_tor.HEIGHT = 50¶
- cellular_automata.wa_tor.MAX_ENTITIES = 500¶
- cellular_automata.wa_tor.PREDATOR_FOOD_VALUE = 5¶
- cellular_automata.wa_tor.PREDATOR_INITIAL_COUNT = 50¶
- cellular_automata.wa_tor.PREDATOR_INITIAL_ENERGY_VALUE = 15¶
- cellular_automata.wa_tor.PREDATOR_REPRODUCTION_TIME = 20¶
- cellular_automata.wa_tor.PREY_INITIAL_COUNT = 30¶
- cellular_automata.wa_tor.PREY_REPRODUCTION_TIME = 5¶
- cellular_automata.wa_tor.WIDTH = 50¶
- cellular_automata.wa_tor.wt¶