So I'm looking for a good data structure to keep track of agents in a multi-agent system. But i can't think of a fast way to implement access to each position and check at what time the agents or objects has been to this position. Furthermore these times should be able to be changed easily and be compared to see if a potential collision might occur and of course it should exclude the agent itself from the collision check.
I was thinking a hashtable like this:
position_hash[position].append((agent_id, time)) # every entry is a list
And then to change the times i would simply have a hash where i append a offset time and value, every time a collision is detected. like this:
offset_hash[agent_id].append((time_where_offset_is_applied, offset_value))
at last i would check if there is a collision by looking at the times. like this:
times = [values[1] for values in position_hash[current_position]]
agents = [values[0] for values in position_hash[current_position]]
times_with_offset = times
for agent_index, agent in enumerate(agents):
for offset_times, offset_values in offset_hash[agent]:
if offset_times <= times[agent_index]:
times_with_offset[agent_index] += offset_values
collisions = [
abs(current_time - time) <= 2 for agent, time in enumerate(times_with_offset) if agent != current_agent
]
if any(collisions):
# add new collision here
Personally i feel it looks a bit clumsy. Is there a better, faster or simpler way to achieve what was described?
Edit 2 - A simple example and more info:
- The positions and times are integers.
- The agents only occupy 1 time slot, but since they can't move simultaneously they technically occupy 2 time slots, thus the small time range.
- For this part of the implementation it needs to be offline planing
- This part of the code should be used to trace back collisions.
The Map
Uppercase is blocks and lower case is the goal
+++++++++++
+ + +
+ 0 1+a+
+ +++++++A+
+ +
+B+++++++ +
+b+ +
+ + +++++
+++++++++++
The single agent solutions
This is the single agent solutions, found by ignoring other agents. This also exists as an velocity. Keep in mind that lists inside lists are because the block is moved by the agent. First position is of the agent and second position is of the block it moved.
[[(2, 5)], [(2, 4)], [(2, 3)], [(2, 2)], [(2, 1)], [(3, 1)], [(4, 1)], [(4, 2)], [(4, 3)], [(4, 4)], [(4, 5)], [(4, 6)], [(4, 7)], [(4, 8)], [(4, 9)], [(3, 9), (2, 9)]]
[[(2, 7)], [(2, 6)], [(2, 5)], [(2, 4)], [(2, 3)], [(2, 2)], [(2, 1)], [(3, 1)], [(4, 1)], [(5, 1), (6, 1)]]
The poition_hash generated
the colors are present when the block hasn't been moved yet. it is however directly correlated to a specific agent
{(3, 9): [('red', 0), (0, 15)], (5, 1): [('green', 0), (1, 9)], (2, 5): [(0, 0), (1, 2)], (2, 4): [(0, 1), (1, 3)], (2, 3): [(0, 2), (1, 4)], (2, 2): [(0, 3), (1, 5)], (2, 1): [(0, 4), (1, 6)], (3, 1): [(0, 5), (1, 7)], (4, 1): [(0, 6), (1, 8)], (4, 2): [(0, 7)], (4, 3): [(0, 8)], (4, 4): [(0, 9)], (4, 5): [(0, 10)], (4, 6): [(0, 11)], (4, 7): [(0, 12)], (4, 8): [(0, 13)], (4, 9): [(0, 14)], (2, 9): [(0, 15)], (2, 7): [(1, 0)], (2, 6): [(1, 1)], (6, 1): [(1, 9)]}
Edit 1: Typo in code
Edit 2: Added more information