Esempio n. 1
0
    def step(self):
        super().before_step()

        if self.at_base() and self.cargo:
            self.emit_event(0, "ORE_DELIVERY", self.cargo, BASE)
            self.cargo = 0

        if self.full():
            self.state = "MOVE_TO_TARGET"
            self.target = self.base.pos()

        if self.state == 'IDLE':
            # Look for explorers and follow one of the nearest ones.
            # If there are none, go to the base.
            agents = self.box_scan(self.mp.P // 2)
            self.energy -= self.mp.P
            explorers = [a for a in agents if EXPLORER in a.group_ids]
            transporters = [a for a in agents if TRANSPORTER in a.group_ids]
            if explorers:
                self.target = random.choice(explorers).pos()
                if transporters:
                    if random.random() < 1 - 1 / (len(transporters) + 1):
                        v = random.choice(transporters).vec_to(self.pos())
                        v = v.normalize(
                        ) if not v.is_zero_vec() else Vec2D.random_dir()
                        v *= 10
                        self.target = self.world.torus(self.pos() + v.round())
            else:
                self.target = self.base.pos()
            self.target = self.base.pos()  # TODO: temp
            self.state = 'MOVE_TO_TARGET'
        elif self.state == 'MOVE_TO_TARGET':
            if self.reached_target():
                self.state = 'IDLE' if not self.ores else 'COLLECT_ORES'
            else:
                if self.move_towards(self.target) or self.move_in_dir(
                        Vec2D.random_grid_dir()):
                    self.energy -= self.mp.Q
        elif self.state == 'COLLECT_ORES':
            ore_idx, ore_pos = self.ores[0]
            if ore_pos == self.pos():
                self.ores.pop(0)
                if self.try_collect_ore(ore_idx):
                    self.cargo += 1
                else:
                    self.failed_collect_attempts += 1
                    if self.failed_collect_attempts >= 2:  # two failed attempts in a row
                        self.ores = []
                if len(self.ores) == 0:
                    self.state = 'IDLE'
                self.energy -= 1
            else:
                if self.move_towards(ore_pos) or self.move_in_dir(
                        Vec2D.random_grid_dir()):
                    self.energy -= 1
        else:
            assert False, "shouldn't reach unknown state: '{}'".format(
                self.state)

        super().after_step()
Esempio n. 2
0
def main():
    l = [Vec2D(0, 0), Vec2D(10, 10), Vec2D(0, 0), Vec2D(10, 10)]
    tsm_idx = iterative_inf_norm_tsm(l)
    ll = [l[i] for i in tsm_idx]

    old_dist = calc_travel_inf_dist(l)
    new_dist = calc_travel_inf_dist(ll)
    assert old_dist == 30
    assert new_dist == 10

    print('test succeeded')
Esempio n. 3
0
def create_world(mp: MasParams):
    world = World(w=mp.G, h=mp.G, torus_enabled=True)

    n_ores = round(mp.G**2 * mp.D)
    for _ in range(n_ores):
        world.add_agent(Ore())

    positions = []
    for x in range(mp.G):
        for y in range(mp.G):
            positions.append(Vec2D(x, y))
    base_positions = random.sample(positions, mp.N)
    if mp.M == 1:  # cooperation
        company_ids = [0] * mp.N
    else:  # competitive
        company_ids = list(range(mp.N))

    for base_pos, comp_id in zip(base_positions, company_ids):
        base = Base(mp, comp_id)
        world.add_agent(base, base_pos)

        for _ in range(mp.X):
            world.add_agent(Explorer(base, mp, comp_id), pos=base_pos)
        for _ in range(mp.Y):
            world.add_agent(Transporter(base, mp, comp_id), pos=base_pos)

    return world
Esempio n. 4
0
 def initialize(self):
     # Create a target a bit off center to view the torus effect
     # self.world is set on the agent when added to a world,
     # so the world can be accessed within the agent methods
     self.start_target = Vec2D(
         math.floor(self.world.w * 0.25),
         math.floor(self.world.h * 0.25)
     )
Esempio n. 5
0
 def step(self):
     if not self.reached_target:
         self.move_towards(self.start_target)
         self.reached_target = self.pos() == self.start_target
     else:
         near_agents = self.box_scan(10, sort=False)
         if near_agents:
             self.color = Colors.RED
             if random.random() < 0.2:
                 self.move_rel(Vec2D.random_grid_dir())
             else:
                 other_agent = random.choice(near_agents)
                 self.move_away_from(other_agent.pos())
         else:
             self.color = Colors.BLUE
Esempio n. 6
0
    def initialize(self):
        self.group_collision_ids = {2, 3}
        self.color = Colors.RED
        self.destination = Vec2D(random.randint(0,world.h), random.randint(0,world.h))
        self.current_ore = []
        self.ore_to_pick_up = []
        self.ore_in_inventory = []
        self.state = "Searching"
        self.counter = 0
        self.current_energy = self.energy_capacity

        self.bases = []
        for i in range(len(world.agents)):
            if world.agents[i].group_ids == {0}:
                self.bases.append(world.agents[i])
        self.memory_capacity = self.memory_capacity - len(self.bases)
        pass
Esempio n. 7
0
    def initialize(self):
        self.group_collision_ids = {2, 3}
        self.color = Colors.GREEN
        self.destination = Vec2D(random.randint(0,world.h), random.randint(0,world.h))
        self.temp_ore = set()
        self.current_energy = self.energy_capacity
        self.state = "Exploring"
        self.counter = 0
        self.bases = []
        self.perception_radius = P
        self.communication_radius = I

        for i in range(len(world.agents)):
            if world.agents[i].group_ids == {0}:
                self.bases.append(world.agents[i])
        self.memory_capacity = self.memory_capacity - len(self.bases)

        pass
Esempio n. 8
0
def draw_sample(T):
    #world = World(200, 200, max_steps=T)
    world = World(w=mining.G, h=mining.G, torus_enabled=True, max_steps=T)
    # Add the agents to the world.
    base_logger = AgentCountLogger()
    BaseLog = base_logger.bind(mining.Base)
    for _ in range(mining.N):
        world.add_agent(BaseLog(), pos = Vec2D(random.randint(0,world.h), random.randint(0,world.h)))

    # Dispurse robots equally amongst bases initially
    explorer_logger = AgentCountLogger()
    ExplorerLog = explorer_logger.bind(mining.Explorer)
    for _ in range(mining.X):
        for j in range(mining.N):
            world.add_agent(ExplorerLog(), pos = world.agents[j].pos())

    transporter_logger = AgentCountLogger()
    TransporterLog = transporter_logger.bind(mining.Transporter)
    for _ in range(mining.Y):
        for j in range(mining.N):
            world.add_agent(TransporterLog(), pos = world.agents[j].pos())

    # Add ore on the map (as agents)
    ore_total = world.w * world.h * mining.D # The density of ores is multiplied with the mapsize to make the correct amount of ore
    ore_logger = AgentCountLogger()
    OreLog = ore_logger.bind(mining.Ore)
    for _ in range(int(ore_total)):
        world.add_agent(OreLog())

    explorer_counts = []
    transporter_counts = []
    base_counts = []
    ore_counts = []
    while not world.ended:
        explorer_counts.append(explorer_logger.count)
        transporter_counts.append(transporter_logger.count)
        base_counts.append(base_logger.count)
        ore_counts.append(ore_total - ore_logger.count)
        world.step()
        #vis = Visualizer(world, target_speed=25)
        #vis.start()


    return [explorer_counts, transporter_counts, ore_counts] # [explorer_counts, transporter_counts, base_counts]
Esempio n. 9
0
    def step(self):
#####################################################################################

        if self.dist(self.bases[self.find_nearest_base()].pos()) + 10 > self.current_energy:
            #print("Explorer " + str(self.idx) + " almost out of energy. Returning to base")
            self.state = "Returning"

        if self.state == "Exploring":
            
            if self.counter < 15 :
                self.move_towards(self.destination)
                self.group_collision_ids = {2, 3}
                self.consume_energy(Q)
                self.counter = self.counter + 1
            else:
                self.temp_ore = self.box_scan(rng = self.perception_radius, group_id = 1) #Only performs scans when moving
                while len(self.temp_ore) > self.memory_capacity:
                    self.temp_ore.pop()
                self.consume_energy(self.perception_radius) #Consuming energy due to perception radius
                if self.temp_ore != None:
                    self.emit_event(self.communication_radius, "Pickup request", self.temp_ore)
                    self.consume_energy(1) # Consume energy due to communication
                # Reset the counter and make a new destination
                self.counter = 0
                self.destination = Vec2D(random.randint(0,world.h), random.randint(0,world.h))
#####################################################################################
        elif self.state == "Returning":

            self.destination = world.agents[self.find_nearest_base()].pos()
            self.move_towards(self.destination)
            self.consume_energy(Q)
            if self.pos() == self.destination:
                self.group_collision_ids = set()
                #print("Explorer reached base. Recharging energy")
                self.current_energy = self.energy_capacity

                self.counter = 0
                self.state = "Exploring"        
        
        if self.current_energy <= 0:
            print("Agent " + str(self.idx) + " died")
            world.remove_agent(self.idx)

        pass
Esempio n. 10
0
def main():
    world = World(w=G, h=G, torus_enabled=True, max_steps=T) # create world, torus or not
    # Add the agents to the world.
    for _ in range(N):
        world.add_agent(Base(), pos = Vec2D(random.randint(0,world.h), random.randint(0,world.h)))

    # Dispurse robots equally amongst bases initially
    for _ in range(X):
        for j in range(N):
            world.add_agent(Explorer(), pos = world.agents[j].pos())

    for _ in range(Y):
        for j in range(N):
            world.add_agent(Transporter(), pos = world.agents[j].pos())

    # Add ore on the map (as agents)
    ore_total = world.w * world.h * D # The density of ores is multiplied with the mapsize to make the correct amount of ore
    for _ in range(int(ore_total)):
        world.add_agent(Ore())

    # The world proceeds by calling 'world.step()'
    while not world.ended:
        world.step()
Esempio n. 11
0
    def initialize(self):
        self.group_collision_ids = {2, 3}
        self.color = Colors.GREEN
        self.destination = Vec2D(random.randint(0,self.world.h), random.randint(0,self.world.h))
        self.temp_ore = []
        self.discovered_ore = []
        self.ore_to_forget = []
        self.current_energy = self.energy_capacity
        self.state = "Exploring"
        self.counter = 0
        self.bases = []
        self.perception_radius = P
        self.communication_radius = I
        self.current_friend = None
        self.exploration_radius = random.randint(15, 30)


        for i in range(len(self.world.agents)):
            if self.world.agents[i].group_ids == {0}:
                self.bases.append(self.world.agents[i])
        self.memory_capacity = self.memory_capacity - len(self.bases)

        pass
Esempio n. 12
0
 def step(self):
     self.move_rel(Vec2D.random_grid_dir())
     self.emit_event(brush_radius, "PAINT", self.pos())
Esempio n. 13
0
        if event_type == "PAINT":
            emit_pos = data
            dir = -self.vec_to(emit_pos)
            dist = dir.magnitude()
            dir_angle = (dir.angle() + (self.world.time * 0.1)) % (math.pi * 2)
            hue = dir_angle / (2 * math.pi)

            if dist < brush_radius:
                self.color = colorsys.hsv_to_rgb(hue, 1, 1)
            if dist < brush_radius * 0.5:
                self.color = Colors.WHITE


for x in range(size):
    for y in range(size):
        world.add_agent(Canvas(), Vec2D(x, y))


class Brush(Agent):
    color = Colors.WHITE
    start_target: Vec2D = None
    reached_target = False

    def step(self):
        self.move_rel(Vec2D.random_grid_dir())
        self.emit_event(brush_radius, "PAINT", self.pos())


world.add_agent(Brush(), Vec2D(size // 2, size // 2))

vis = Visualizer(world, scale=3, target_speed=100)
Esempio n. 14
0
    def step(self):
        if not self.world.ended: 
    #####################################################################################
            if self.dist(self.bases[self.find_nearest_base()].pos()) + 15 > self.current_energy:
                self.state = "Returning"

            if self.state == "Exploring":
                if self.counter < self.exploration_radius :
                    self.move_towards(self.destination)
                    self.group_collision_ids = {2, 3}
                    self.consume_energy(Q)

                else:
                    self.temp_ore = self.box_scan(rng = self.perception_radius, group_id = 1) #Only performs scans when moving
                    self.consume_energy(self.perception_radius) #Consuming energy due to perception radius
                    for i in range(len(self.temp_ore)):         # Add ore into memory until cap.
                        if len(self.discovered_ore) <= self.memory_capacity and self.temp_ore[i] not in self.discovered_ore:
                            self.discovered_ore.append(self.temp_ore[i])
                    if self.discovered_ore != None:
                        self.emit_event(self.communication_radius, "Pickup request", self.discovered_ore + [self.idx])
                        self.consume_energy(1) # Consume 1 energy unit due to communication
                    if len(self.discovered_ore) == self.memory_capacity:
                        self.state = "Requesting"                
                    
                    # Reset the counter and make a new destination
                    self.counter = 0
                    self.destination = Vec2D(random.randint(0,self.world.h), random.randint(0,self.world.h))
    #####################################################################################
            elif self.state == "Requesting":
                # Counter has just been set to zero and we already have a new destionation, 
                # but we stay (using that counter) until a Transporter has releived us of some memory-space
                if self.counter % 5 == 0: # Tries 10 times every fifth step to make pickup-request
                    self.emit_event(self.communication_radius, "Pickup request", self.discovered_ore)
                    self.consume_energy(1) # Consume 1 energy unit due to communication
                if self.counter > 50 : # Give up and go exploring again... will in reality only move once and try again
                    self.counter = 0
                    self.state = "Exploring"
                    self.discovered_ore = []
    #####################################################################################
            elif self.state == "Choosing":
                if self.discovered_ore != []:
                    for i in range(len(self.ore_to_forget)):
                        if self.ore_to_forget[i] in self.discovered_ore:
                            self.discovered_ore.remove(self.ore_to_forget[i])
                    self.emit_event(self.communication_radius, "Choose transporter", [self.current_friend, self.idx])
                self.current_friend = None
                self.state = "Exploring" # Now the explorers should not get stuck....
                
    #####################################################################################
            elif self.state == "Returning":
                self.destination = self.world.agents[self.find_nearest_base()].pos()
                self.move_towards(self.destination)
                self.consume_energy(Q)
                if self.pos() == self.destination: # Maybe change this into dist(pos, base)< 1.5 (lidt snyd)
                    self.group_collision_ids = set()
                    self.current_energy = self.energy_capacity
                    self.exploration_radius = random.randint(15, 30)
                    self.counter = 0
                    self.destination = Vec2D(random.randint(0,self.world.h), random.randint(0,self.world.h))
                    self.discovered_ore = []
                    self.current_friend = None
                    self.state = "Exploring"        
            
            if self.current_energy <= 0:
                print("Agent " + str(self.idx) + " died")
                self.world.remove_agent(self.idx)
            
            self.counter = self.counter + 1
            pass
Esempio n. 15
0
    def step(self):
        if not self.world.ended:
            if self.dist(self.bases[self.find_nearest_base()].pos()) + 15 > self.current_energy:
                self.destination = self.bases[self.find_nearest_base()].pos()
                self.state = "Returning"

    #####################################################################################            
            if self.state == "Searching":
                self.group_collision_ids = {2, 3}
                if self.counter < 20 :
                    self.move_towards(self.destination)
                    self.consume_energy(Q)
                else:
                    self.counter = 0
                    self.destination = Vec2D(random.randint(0,self.world.h), random.randint(0,self.world.h))
    #####################################################################################
            elif self.state == "Pickup" :
                if len(self.ore_in_inventory) >= self.inventory_capacity: # Inventory full
                    self.destination = self.bases[self.find_nearest_base()].pos()
                    self.state = "Returning"
                elif len(self.ore_to_pick_up) < 1:
                    self.state = "Searching"
                else:
                    # Picking a new target
                    self.current_ore = self.ore_to_pick_up[0] #random.randint(0, len(self.ore_to_pick_up)-1)
                    if self.current_ore.idx in self.world.active_agents: #if self.current_ore.picked == False:
                        self.destination = self.current_ore.pos()
                        self.move_towards(self.destination)
                        self.consume_energy(Q)
                        self.state = "Moving"
                    else: 
                        self.ore_to_pick_up.remove(self.current_ore)
                        self.state = "Pickup"
    #####################################################################################
            elif self.state == "Moving":
                self.move_towards(self.destination)
                self.consume_energy(Q)
                if self.pos() == self.destination:
                    #deactive ore and remove from memory
                    self.ore_to_pick_up.remove(self.current_ore)
                    if self.current_ore.idx in self.world.active_agents: #if self.current_ore.picked == False:
                        self.current_ore.pickup(self) # Tell the ore that it has been picked up
                        self.ore_in_inventory.append(self.current_ore)
                        self.consume_energy(1) #Picking an ore costs 1 energy
                    self.state = "Pickup"
    #####################################################################################
            elif self.state == "Acknowledging":
                # self.temp_ore now has as many ores as I can handle. Acknowledge back with my and friend's ID
                self.emit_event(self.communication_radius, "Pickup acknowledgement", self.temp_ore + [self.current_friend, self.idx])
                self.consume_energy(1)
                self.state = "Pickup" 
                
    #####################################################################################
            elif self.state == "Returning":
                self.move_towards(self.destination)
                self.consume_energy(Q)
                if self.pos() == self.destination :
                    self.group_collision_ids = set()
                    self.bases[self.find_nearest_base()].deposit(self.ore_in_inventory) # Depositing ore into base
                    self.ore_in_inventory = []# Removing ore from inventory'
                    self.current_energy = self.energy_capacity #Recharging
                    #if self.ore_to_pick_up != []:
                    #    self.destination = self.ore_to_pick_up[0].pos()
                    #else:
                    # This is not very smart... 
                    self.destination = Vec2D(random.randint(0,self.world.h), random.randint(0,self.world.h))
                    self.state = "Pickup"
    #####################################################################################
            
            self.counter = self.counter + 1

            if self.current_energy <= 0:
                print("Agent " + str(self.idx) + " died")
                self.world.remove_agent(self.idx)
            pass
Esempio n. 16
0
    def step(self):
#####################################################################################
        if self.dist(world.agents[0].pos()) + 10 > self.current_energy:
            #print("Transporter " + str(self.idx) + " almost out of energy. Returning to base")
            self.state = "Returning"
        if self.state == "Searching":
            self.group_collision_ids = {2, 3}
            if self.counter < 15 :
                self.move_towards(self.destination)
                self.consume_energy(Q)
            else:
                self.counter = 0
                self.destination = Vec2D(random.randint(0,world.h), random.randint(0,world.h))
#####################################################################################
        elif self.state == "Pickup" :
            if len(self.ore_in_inventory) > self.inventory_capacity:
                #print("Inventory full on " + str(self.idx) + ". Returning to base")
                self.destination = self.bases[self.pick_base()].pos()
                self.state = "Returning"
            elif len(self.ore_to_pick_up) < 2:
                #print("Ran out of ore to find. Searching for an Explorer")
                self.state = "Searching"
            else:
                # Picking a new target
                self.current_ore = self.ore_to_pick_up[0] #random.randint(0, len(self.ore_to_pick_up)-1)
                if self.current_ore.picked == False:
                    self.destination = Vec2D(self.current_ore.pos().x, self.current_ore.pos().y)
                    self.move_towards(self.destination)
                    self.consume_energy(Q)
                    self.state = "Moving"
                else: 
                    self.ore_to_pick_up.remove(self.current_ore)
                    self.state = "Pickup"
#####################################################################################
        elif self.state == "Moving":
            self.move_towards(self.destination)
            self.consume_energy(Q)
            if self.pos() == self.destination:
                #deactive ore and remove from memory
                self.ore_to_pick_up.remove(self.current_ore)
                if self.current_ore.picked == False:
                    #print("Found valid ore. Picking ore from world.")
                    self.current_ore.pickup(self) # Tell the ore that it has been picked up
                    self.ore_in_inventory.append(self.current_ore)
                    self.consume_energy(1) #Picking an ore costs 1 energy
                self.state = "Pickup"
#####################################################################################
        elif self.state == "Returning":
            
            self.move_towards(self.destination)
            self.consume_energy(Q)
            if self.pos() == self.destination :
                self.bases[self.find_nearest_base()].deposit(self.ore_in_inventory) # Depositing ore into base
                self.ore_in_inventory = []# Removing ore from inventory'
                self.current_energy = self.energy_capacity #Recharging
                self.state = "Searching"
        
        #print("Agent number " + str(self.idx) + " has " + str(len(self.ore_to_pick_up)) + " to pick up")

        self.counter = self.counter + 1

        if self.current_energy <= 0:
            print("Agent " + str(self.idx) + " died")
            world.remove_agent(self.idx)

        pass
Esempio n. 17
0
 def step(self):
     self.move_rel(Vec2D.random_grid_dir())
Esempio n. 18
0
                for i in range(len(data)):
                    if data[i] not in self.ore_to_pick_up:# Make sure there are no duplicates
                        self.ore_to_pick_up.append(data[i]) 
                self.state = "Pickup" 
        if event_type == "Base full":
            print("Base full, going to returning state" + str(len(data)))
            self.destination = self.bases[self.pick_base()].pos()
            self.state = "Returning"      
        pass

    def cleanup(self):
        pass

# Add the agents to the world.
for i in range(N):
    world.add_agent(Base(), pos = Vec2D(random.randint(0,world.h), random.randint(0,world.h)))


# Dispurse robots equally amongst bases initially
for i in range(X):
    for j in range(N):
        world.add_agent(Explorer(), pos = world.agents[j].pos())

for i in range(Y):
    for j in range(N):
        world.add_agent(Transporter(), pos = world.agents[j].pos())

# Add ore on the map (as agents)
ore_total = world.w * world.h * D # The density of ores is multiplied with the mapsize to make the correct amount of ore
for i in range(int(ore_total)):
    world.add_agent(Ore())
Esempio n. 19
0
    def step(self):
        super().before_step()

        if self.state == "MOVE_TO_TARGET":
            self.color = Colors.GREEN
            if self.reached_target():
                if self.at_base():
                    self.dir = Vec2D.random_dir()
                if self.ore_data:
                    transporters = (self.box_scan(self.mp.P // 2, TRANSPORTER + str(self.company_id)))[:self.mp.S]
                    self.consume_energy(self.mp.P)
                    self.ore_data = (len(transporters), self.ore_data[1])
                    self.state = "EMIT_EVENT_ORE_POS"
                else:
                    self.state = "SCAN"
            else:
                if not self.move_towards(self.target):
                    self.move_in_dir(Vec2D.random_grid_dir())
                    self.consume_energy(self.mp.Q)

        elif self.state == "SCAN":
            self.color = Colors.GREY25
            agents = self.box_scan(self.mp.P // 2)
            self.consume_energy(self.mp.P)
            ores = [a for a in agents if ORE in a.group_ids]
            explorers = [a for a in agents if EXPLORER in a.group_ids]
            transporters = [a for a in agents if TRANSPORTER in a.group_ids]

            if ores:
                rel_ore_pos = [self.vec_to(o.pos()) for o in ores]
                rel_ore_cog = sum(rel_ore_pos, Vec2D()) / len(ores)
                if rel_ore_cog.magnitude() > self.mp.P / 4:
                    # TODO: set max iterations
                    self.color = Colors.MAGENTA
                    self.target = self.world.torus(self.pos() + rel_ore_cog.round())
                    self.state = "MOVE_TO_TARGET"
                else:
                    rel_ore_pos = [self.vec_to(o.pos()) for o in ores]
                    tsm_idx = tsm.iterative_inf_norm_tsm(rel_ore_pos, n=1000)
                    ores = [ores[i] for i in tsm_idx]
                    ore_data = [(o.idx, o.pos()) for o in ores]
                    self.ore_data = (len(transporters), ore_data)
                    if transporters:
                        self.state = "EMIT_EVENT_ORE_POS"
                    else:
                        self.target = self.base.pos()
                        self.state = "MOVE_TO_TARGET"
            elif explorers:
                other_expl = random.choice(explorers)
                dir = other_expl.vec_to(self.pos())
                dir = dir / dir.magnitude() if not dir.is_zero_vec() else Vec2D.random_dir()
                self.target = self.world.torus(other_expl.pos() + (dir * 20).round())
                self.state = "MOVE_TO_TARGET"
            else:
                self.set_new_random_rel_target()
                self.state = "MOVE_TO_TARGET"

        elif self.state == "EMIT_EVENT_ORE_POS":
            self.color = Colors.WHITE
            self.emit_event(self.mp.I // 2, "ORE_POSITIONS", self.ore_data, TRANSPORTER + str(self.company_id))
            self.consume_energy(1)
            self.ore_data = None
            self.set_new_random_rel_target()
            self.state = "MOVE_TO_TARGET"

        super().after_step()
Esempio n. 20
0
    group_ids = {1}
    group_collision_ids = {
        0, 1
    }  # Not able to enter wall tiles or other Mover tiles

    def step(self):
        self.move_rel(Vec2D.random_grid_dir())


# Create walls
x1, x2 = round(size * 0.3), round(size * 0.7)
y1, y2 = round(size * 0.6), round(size * 0.8)

for x in (x1, x2):
    for y in range(y1 + 1):
        world.add_agent(Wall(), Vec2D(x, y))
    for y in range(y2, size):
        world.add_agent(Wall(), Vec2D(x, y))

for y in (y1, y2):
    for x in range(x1 + 1, x2):
        world.add_agent(Wall(), Vec2D(x, y))

# Add Mover agents
for _ in range(200):
    world.add_agent(Mover(), Vec2D(size // 2, size // 4))

# Start and visualize simulation
vis = Visualizer(world, scale=3, target_speed=200)
vis.start()