diff --git a/README.md b/README.md
index 32ea606..7ac7797 100644
--- a/README.md
+++ b/README.md
@@ -1,2 +1,10 @@
# ants
A reimplementation of Schweitzer et al. 1996 as well as additional improvemnts for the Course Agent Based Modelling for Social Systems FS2023 ETH Zürich
+
+
+For the course [Agent Based Modelling for Social Systems FS2023](https://www.vorlesungen.ethz.ch/Vorlesungsverzeichnis/lerneinheit.view?lerneinheitId=167292&semkez=2023S&ansicht=LEHRVERANSTALTUNGEN&lang=de) we were tasked to implement a model of our own (in groups).
+For this, we decided to implement an enhanced version of [Active random walkers simulate trunk trail formation by ants (Schweitzer et al. 1996)](https://www.sciencedirect.com/science/article/pii/S030326479601670X?casa_token=fv82ToWDN3cAAAAA:wB5hHIlxnYBBvyuHb98YUFpXqWqGt50xDRnmAZ_UaMS5khR9IiH8K6m1b5gdqkAe1ACXx_lEy2U) using Python and Mesa.
+
+
+For now, wanted features can be found in our [shortlist](shortlist.md).
+For everything else start at [main py](main.py)
diff --git a/agent.py b/agent.py
new file mode 100644
index 0000000..e1f1148
--- /dev/null
+++ b/agent.py
@@ -0,0 +1,59 @@
+"""
+agent.py - Part of ants project
+
+This model implements the actual agents on the grid (a.k.a. the ants)
+
+License: AGPL 3 (see end of file)
+(C) Alexander Bocken, Viviane Fahrni, Grace Kragho
+"""
+import numpy as np
+from mesa.agent import Agent
+from mesa.space import Coordinate
+
+
+class RandomWalkerAnt(Agent):
+ def __init__(self, unique_id, model, do_follow_chemical_A=True,
+ energy_0=1, chemical_drop_rate_0=1, sensitvity_0=1, alpha=0.5)-> None:
+ super().__init__(unique_id=unique_id, model=model)
+
+ self._next_pos : None | Coordinate = None
+
+ self.prev_pos = None
+ self.do_follow_chemical_A : bool = True # False -> follow_chemical_B = True
+ self.energy : float = energy_0
+ self.sensitvity : float = sensitvity_0
+ self.chemical_drop_rate : float = chemical_drop_rate_0 #TODO: check whether needs to be separated into A and B
+ self.alpha = alpha
+
+ def step(self):
+ pass
+
+ def advance(self) -> None:
+ self.pos = self._next_pos
+
+ @property
+ def front_neighbors(self):
+ if self.prev_pos is not None:
+ x, y = self.pos
+ x_prev, y_prev = self.prev_pos
+ dx, dy = x - x_prev, y - y_prev
+ front = [
+ (x, y + dy),
+ (x + dx, y),
+ (x + dx, y + dy),
+ ]
+ return front #TODO: verify (do we need to sperate into even/odd?)
+ else:
+ # TODO: return all neighbors or raise Exception?
+ pass
+
+
+
+
+"""
+This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, version 3.
+
+This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
+
+You should have received a copy of the GNU Affero General Public License along with this program. If not, see
+"""
diff --git a/main.py b/main.py
new file mode 100755
index 0000000..b92000e
--- /dev/null
+++ b/main.py
@@ -0,0 +1,49 @@
+#!/bin/python
+"""
+main.py - Part of ants project
+execute via `python main.py` in terminal or only UNIX: `./main.py`
+
+License: AGPL 3 (see end of file)
+(C) Alexander Bocken, Viviane Fahrni, Grace Kragho
+"""
+from model import ActiveWalkerModel
+from agent import RandomWalkerAnt
+import numpy as np
+import matplotlib.pyplot as plt
+from mesa.space import Coordinate
+
+def main():
+ width = 21
+ height = width
+ num_initial_roamers = 5
+ num_max_agents = 100
+ nest_position : Coordinate = (width //2, height //2)
+ max_steps = 100
+
+ model = ActiveWalkerModel(width=width, height=height,
+ num_initial_roamers=num_initial_roamers,
+ nest_position=nest_position,
+ num_max_agents=num_max_agents,
+ max_steps=max_steps)
+
+ # just initial testing of MultiHexGrid
+ for agent in model.grid.get_neighbors(pos=nest_position, include_center=True):
+ if agent.unique_id == 2:
+ agent.do_follow_chemical_A = False
+ agent.prev_pos = (9,10)
+ print(agent.front_neighbors)
+ print(agent.pos, agent.unique_id, agent.do_follow_chemical_A)
+
+
+if __name__ == "__main__":
+ main()
+
+
+
+"""
+This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, version 3.
+
+This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
+
+You should have received a copy of the GNU Affero General Public License along with this program. If not, see
+"""
diff --git a/model.py b/model.py
new file mode 100644
index 0000000..9dcf2d0
--- /dev/null
+++ b/model.py
@@ -0,0 +1,65 @@
+"""
+model.py - Part of ants project
+
+This file implements the mesa model on which our ActiveRandomWalkerAnts
+will act
+
+License: AGPL 3 (see end of file)
+(C) Alexander Bocken, Viviane Fahrni, Grace Kragho
+"""
+
+import numpy as np
+from mesa.model import Model
+from mesa.space import Coordinate, HexGrid, Iterable
+from multihex import MultiHexGrid
+from mesa.time import SimultaneousActivation
+from mesa.datacollection import DataCollector
+from agent import RandomWalkerAnt
+
+class ActiveWalkerModel(Model):
+ def __init__(self, width : int, height : int , num_max_agents : int,
+ num_initial_roamers : int,
+ nest_position : Coordinate,
+ max_steps:int=1000) -> None:
+ super().__init__()
+ self.schedule = SimultaneousActivation(self)
+ self.grid = MultiHexGrid(width=width, height=height, torus=True) # TODO: replace with MultiHexGrid
+ self._unique_id_counter : int = -1 # only touch via get_unique_id() or get_unique_ids(num_ids)
+
+ self.max_steps = max_steps
+ self.nest_position : Coordinate = nest_position
+ self.num_max_agents = num_max_agents
+
+ for agent_id in self.get_unique_ids(num_initial_roamers):
+ agent = RandomWalkerAnt(unique_id=agent_id, model=self, do_follow_chemical_A=True)
+ self.schedule.add(agent)
+ self.grid.place_agent(agent, pos=nest_position)
+
+ self.datacollector = DataCollector(
+ model_reporters={},
+ agent_reporters={}
+ )
+ self.datacollector.collect(self) # keep at end of __init___
+
+ def step(self):
+ self.schedule.step()
+ self.datacollector.collect(self)
+
+ if self.schedule.steps >= self.max_steps:
+ self.running = False
+
+ def get_unique_id(self) -> int:
+ self._unique_id_counter += 1
+ return self._unique_id_counter
+
+ def get_unique_ids(self, num_ids : int):
+ for _ in range(num_ids):
+ yield self.get_unique_id()
+
+"""
+This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, version 3.
+
+This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
+
+You should have received a copy of the GNU Affero General Public License along with this program. If not, see
+"""
diff --git a/multihex.py b/multihex.py
new file mode 100644
index 0000000..325278d
--- /dev/null
+++ b/multihex.py
@@ -0,0 +1,101 @@
+"""
+multihex.py - Part of ants project
+
+This file impements a Mesa HexGrid while allowing for multiple agents to be
+at the same location. The base for this code comes from the MultiGrid class
+in mesa/space.py
+
+License: AGPL 3 (see end of file)
+(C) Alexander Bocken, Viviane Fahrni, Grace Kragho
+"""
+
+from mesa.space import HexGrid
+from mesa.agent import Agent
+import numpy as np
+from mesa.space import Coordinate, accept_tuple_argument
+import itertools
+from typing import (
+ Any,
+ Callable,
+ Iterable,
+ Iterator,
+ List,
+ Sequence,
+ Tuple,
+ TypeVar,
+ Union,
+ cast,
+ overload,
+)
+
+MultiGridContent = list[Agent]
+
+class MultiHexGrid(HexGrid):
+ """Hexagonal grid where each cell can contain more than one agent.
+ Mostly based of mesa's HexGrid
+ Functions according to odd-q rules.
+ See http://www.redblobgames.com/grids/hexagons/#coordinates for more.
+
+ Properties:
+ width, height: The grid's width and height.
+ torus: Boolean which determines whether to treat the grid as a torus.
+
+ Methods:
+ get_neighbors: Returns the objects surrounding a given cell.
+ get_neighborhood: Returns the cells surrounding a given cell.
+ iter_neighbors: Iterates over position neighbors.
+ iter_neighborhood: Returns an iterator over cell coordinates that are
+ in the neighborhood of a certain point.
+ """
+ grid: list[list[MultiGridContent]]
+
+ @staticmethod
+ def default_val() -> MultiGridContent:
+ """Default value for new cell elements."""
+ return []
+
+ def place_agent(self, agent: Agent, pos: Coordinate) -> None:
+ """Place the agent at the specified location, and set its pos variable."""
+ x, y = pos
+ if agent.pos is None or agent not in self._grid[x][y]:
+ self._grid[x][y].append(agent)
+ agent.pos = pos
+ if self._empties_built:
+ self._empties.discard(pos)
+
+ def remove_agent(self, agent: Agent) -> None:
+ """Remove the agent from the given location and set its pos attribute to None."""
+ pos = agent.pos
+ x, y = pos
+ self._grid[x][y].remove(agent)
+ if self._empties_built and self.is_cell_empty(pos):
+ self._empties.add(pos)
+ agent.pos = None
+
+ @accept_tuple_argument
+ def iter_cell_list_contents(
+ self, cell_list: Iterable[Coordinate]
+ ) -> Iterator[Agent]:
+ """Returns an iterator of the agents contained in the cells identified
+ in `cell_list`; cells with empty content are excluded.
+
+ Args:
+ cell_list: Array-like of (x, y) tuples, or single tuple.
+
+ Returns:
+ An iterator of the agents contained in the cells identified in `cell_list`.
+ """
+ return itertools.chain.from_iterable(
+ self._grid[x][y]
+ for x, y in itertools.filterfalse(self.is_cell_empty, cell_list)
+ )
+
+
+
+"""
+This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, version 3.
+
+This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
+
+You should have received a copy of the GNU Affero General Public License along with this program. If not, see
+"""
diff --git a/shortlist.md b/shortlist.md
new file mode 100644
index 0000000..ca563a8
--- /dev/null
+++ b/shortlist.md
@@ -0,0 +1,45 @@
+# SHORTLIST
+
+- nonlinear response to concentration of pheromones (with upper and lower threshold)
+ -> needs a separation of sensitivity and internal energy
+
+## More chaos
+- what happens if you disrupt the trail with an obstacle?
+- limited node capacity
+
+
+# Model setup
+
+## Agents
+- previous_position
+- position
+- sensitivity
+- internal energy
+- pheromone drop rate (A/B)
+- what chemical we´re looking for
+- optional: how much food we have with us (and decrement to prevent dying if energy is low)
+- alpha
+
+### step function
+- probablistic forward step based on concentrations and sensitvity
+ - follow highest concentration probabilistically and be random otherwise
+- drop pheromones
+- have we found food -> change behaviour and decrease food amount + reset stuff
+- are we at the nest (having found food)? -> recruit new ants + reset stuff
+- decrement sensitivity
+- decrement energy (optional: only without food)
+ - do i need to die
+
+## Model
+
+### hexagonal grid
+ - pheromone a/b concentration
+ - nest location
+ - food location/concentration
+ - for later: node capacity
+- N total ants
+- a few other constants which need to be set
+
+### step
+ advance ants (call ants step function)
+ decrease pheromone concentration on grid