Advertisement
AmCholadawan

Multi_agent_densitymap_version

Feb 15th, 2018
87
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 50.49 KB | None | 0 0
  1. from collections import namedtuple
  2. from collections import OrderedDict
  3. from enum import Enum
  4. from matplotlib import pyplot as plt
  5. import os
  6. import csv
  7. import numpy as np
  8. import copy
  9. import random
  10. import time
  11. from datetime import datetime
  12. import struct
  13. import pickle
  14. import sys
  15.  
  16. import levyrandom
  17.  
  18. # test merge
  19.  
  20.  
  21. class slicee:
  22.     """
  23.      Creates an array of start and stop value pairs (with optional step
  24.      values)
  25.  
  26.       Examples
  27.      --------
  28.      >>> slicee()[0, 1:2, ::5, ...]
  29.      # '(0, slice(1, 2, None), slice(None, None, 5), Ellipsis)'
  30.  
  31.      References
  32.      ----------
  33.      .. [#] Python's slice notation. StackOverflow.
  34.         http://stackoverflow.com/questions/509211/explain-pythons-slice-notation
  35.  
  36.  
  37.      """
  38.     def __getitem__(self, item):
  39.         return item
  40.  
  41. dateStr = time.strftime('%Y-%m-%d')
  42. #timeStr = time.strftime('%Y-%m-%d_%H_%M_%S')
  43. timeStr = datetime.utcnow().strftime('%Y-%m-%d%H%M%S%f')[:-3]
  44. #timeStr1 = datetime.utcnow()
  45. #timeStr = timeStr1.strftime('%Y-%m-%d%H%M%S%f')[:-3]
  46.  
  47. # set model parameters
  48. # give your data set directory a name
  49. dataSetName = "Finitefood" #+ dateStr
  50. #++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  51. n_cells = 10000 #400                         # must be square number
  52.  
  53. if len(sys.argv) > 2:
  54.     n_bots =  int(sys.argv[2]) #169
  55. else:
  56.     n_bots = 1
  57.  
  58. print(type(n_bots))
  59.  
  60. #max_food_per_cell = 100
  61. if len(sys.argv) > 1:
  62.     max_food_per_cell = int(sys.argv[3]) #1
  63. else:
  64.     max_food_per_cell = 100
  65.  
  66.  
  67. food_cell_value = "max_food_per_cell"   # "random", "max_food_per_cell"
  68. plot_output = True                    #  plots and saves output data
  69. show_plot = True                      #  displays data during simulation
  70. #++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  71. trophallaxis = True
  72. FiniteFood = True
  73. #++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  74. scavenge = True
  75. food_map_style = "density_map"          # "existing_map", "new_map", "central_map", "density_map"
  76. bot_map_style = "central_map"           # "existing_map", "new_map", "random_map", "central_map"
  77. maxTimesteps = 1
  78.  
  79. food_tick = 3
  80.  
  81. if food_map_style == "density_map":     # specify teh density and the number of blocks
  82.     food_map_density = 10               # % of density in each block
  83.     blocks = 1                          # number of block in n_cells
  84.        
  85. if food_map_style == "central_map":     # set dimensions of food patches:
  86.     if len(sys.argv) > 1:
  87.         n_food_cells = int(sys.argv[1]) #1
  88.     else:
  89.         n_food_cells = 100
  90.        
  91.  
  92. if food_map_style == "new_map":         # set dimensions of food patches:
  93.     if len(sys.argv) > 1:
  94.         food_offset = int(sys.argv[1]) #1
  95.     else:
  96.         food_offset = 5
  97.        
  98.     bot_length = n_bots ** (1/2)
  99.     half_bot_length = bot_length/2
  100.     n_cells_length = n_cells ** (1/2)
  101.     mid_n_cells = n_cells_length/2
  102.     bot_edge_plus = mid_n_cells + half_bot_length
  103.     bot_edge_neg = mid_n_cells - half_bot_length
  104.     food_in_edge_plus = bot_edge_plus + food_offset
  105.     food_in_edge_neg = bot_edge_neg - food_offset
  106.     food_out_edge_plus = food_in_edge_plus + food_tick
  107.     food_out_edge_neg = food_in_edge_neg - food_tick        
  108.        
  109.     food_y_range = slicee()[food_out_edge_neg:food_in_edge_plus,
  110.                             food_in_edge_plus:food_out_edge_plus,
  111.                             food_in_edge_neg:food_out_edge_plus,
  112.                             food_out_edge_neg:food_in_edge_neg,]
  113.     food_x_range = slicee()[food_out_edge_neg:food_in_edge_neg,
  114.                             food_out_edge_neg:food_in_edge_plus,
  115.                             food_in_edge_plus:food_out_edge_plus,
  116.                             food_in_edge_neg:food_out_edge_plus,]  
  117.    
  118.     # food_y_range = slicee()[1:2, 4:6,]
  119.     # food_x_range = slicee()[1:2, 4:6,]
  120. #    food_y_range = slicee()[3:7, ]
  121. #    food_x_range = slicee()[3:7, ]
  122.  
  123. if bot_map_style == "new_map":  # set dimensions of bot groups:
  124.     bot_y_range = slicee()[3:7, ]
  125.     bot_x_range = slicee()[3:7, ]
  126.  
  127. if bot_map_style == "random":
  128.     set_number_agents_on_food = True
  129.     n_agents_on_food = 2
  130.  
  131. if bot_map_style == "existing_map":  # input names of previous data
  132.     bot_map_dir = "Data.07-02-2016_00_25_05_JST"
  133.     bot_map_name = "Data.07-02-2016_00_25_05_JST"
  134.  
  135. if food_map_style == "existing_map": # input names of previous data
  136.     food_map_dir = "Data.07-02-2016_00_25_05_JST"
  137.     food_map_name = "Data.07-02-2016_00_25_05_JST"
  138.  
  139.  
  140. BOT_DEFAULTS = OrderedDict([
  141.     ("base_metabolism", 0),
  142.     ("EinPerFeed", 10),
  143.     ("eff_E_conversion", 1),
  144.     ("t_steps_to_charge", 5),
  145.     ("Estored_init", 50),
  146.     ("Estored_max", 100),
  147.     ("Eth_battFull", 0),
  148.     ("Ecost_perStep", 1),
  149.     #("Ecost_perFeed", 1),
  150.     ("senseRange", 1),
  151.     ("scavenge", scavenge),
  152.     ("trophallaxis", trophallaxis),
  153.     ("trophMode", "cautious"),  # "equalise", "cautious", "selfless"
  154. ])
  155.  
  156. """dict: Default values for bot construction."""
  157.  
  158. SENSING_TARGETS = {
  159.     "neighbour_on_food": 2,
  160.     "neighbour_not_on_food": 1,
  161.     "neighbouring_recruits" : 1,
  162.     "neighbouring_bot" : 1,
  163.     "neighbouring_space": 0,
  164. }
  165. """dict: Potential targets that can be sensed."""
  166.  
  167. # random seed is random choice.
  168. # replace with set values for repeated output
  169. seed_np = np.random.randint(0, 2**32 - 1)
  170. seed_random = np.random.randint(0, 2**32 - 1)
  171. np.random.seed(seed_np)
  172. random.seed(seed_random)
  173.  
  174. # the path to where you want to save the data
  175. dirname = os.path.abspath(os.path.join(
  176.     os.path.dirname( __file__ ),
  177.     '../../..',
  178.     "simulation_results"
  179.     + "/" + "self_energy_robot"
  180.     + "/" + "test11"
  181.     + "/" + "density_map"
  182.     ))
  183.  
  184. path =  dirname + "/" + dataSetName
  185.  
  186. # give each run in the data set a unique name
  187. dataName = "Bots" + str(n_bots) + "FoodDensity" + str(food_map_density) + "Maxfood" + str(max_food_per_cell) + "_" + timeStr   #Maxfood = initial max_food_per_cells
  188. #print("current data", dataName)
  189.  
  190. # directory to store plot data
  191. os.makedirs(path
  192.             + "/" + dataName
  193.             + "/" + "plot_data")
  194.  
  195. # os.makedirs(path + "/"
  196. #             + dataName
  197. #             + "/figures")
  198.  
  199. dataTimestep = path \
  200.                + "/" + dataName  \
  201.                + "/" + dataName + '_dataTimestep.csv'
  202.  
  203. dataSummary = path \
  204.               + "/" + dataName  \
  205.               + "/" + dataName + '_dataSummary.csv'
  206.  
  207. data_per_timestep = ["count",
  208.                      "total_food",
  209.                      "food_patches",
  210.                      "bots_with_Estored",
  211.                      "area_covered",
  212.                      "total_steps_taken",
  213.                      "max_energy_stored",
  214.                      "trophallaxis",
  215.                      ]
  216. count = 1
  217. trophallaxis_value = 0
  218. start_time = time.time()
  219.  
  220. Location = namedtuple("Location", ("x", "y"))
  221.  
  222. class Food(object):
  223.     """
  224.   Maps the distribution of food over the grid space.
  225.  
  226.   Parameters
  227.   ----------
  228.   food_map_style :
  229.       The name of the method used to construct the food map.
  230.   n_cells : int
  231.      The number of cells with individual values that the food map is
  232.      discretised into.
  233.   max_food_per_cell : int
  234.      The maximum value of a food cell.
  235.  
  236.   Attributes
  237.   ----------
  238.   n_cells : int
  239.      The number of cells with individual values that the food map is
  240.      discretised into.
  241.   map_size : int
  242.       The length of each side of the food map in grid cells.
  243.   max_food_per_cell : int
  244.      The maximum value of a food cell.
  245.   food_map : array
  246.      The distribution of food across the grid space, food cell discretisation.
  247.  
  248.   """
  249.     def __init__(self):
  250.  
  251.         self.food_map_style = food_map_style
  252.         self.n_cells = n_cells
  253.         self.map_size = int(np.sqrt(self.n_cells))
  254.         self.max_food_per_cell = max_food_per_cell
  255.         self.food_map = np.zeros(self.n_cells)
  256.  
  257.         if food_map_style == "existing_map":
  258.  
  259.             self.food_map = np.load(food_map_dir
  260.                                     + "/" + food_map_name
  261.                                     + "/" + food_map_name
  262.                                     + "_food.npy")
  263.             map_name = food_map_name
  264.  
  265.         elif food_map_style == "new_map":
  266.             self._new_map()
  267.             map_name = dataName
  268.  
  269.         elif food_map_style == "central_map":
  270.             self._central_map()
  271.             map_name = dataName
  272.            
  273.         elif food_map_style == "density_map":
  274.             self._density_map(food_map_density, blocks)
  275.             map_name = dataName
  276.  
  277.         food_map_name = path \
  278.                         + "/" + dataName \
  279.                         + "/" + map_name
  280.  
  281.         np.save(food_map_name + "_food", self.food_map)
  282.         self.total_food_initial = np.sum(self.food_map)
  283.         self.total_food_cells_initial = len(np.argwhere(self.food_map))
  284.  
  285.     def _new_map(self):
  286.         self.food_map = np.reshape(self.food_map,
  287.                                    (self.map_size,self.map_size))
  288.  
  289.         for y, x in zip(food_y_range, food_x_range):
  290.             self.food_map[y, x] = 1
  291.  
  292.         self.populate_food_cells()
  293.  
  294.     def _central_map(self):
  295.         self.food_map = np.reshape(self.food_map,
  296.                                    (self.map_size, self.map_size))
  297.  
  298.         _midpoint = int(self.map_size / 2)
  299.         _sideLength = int(np.sqrt(n_food_cells))
  300.         _lower = int(_midpoint - (_sideLength / 2))
  301.         _upper = int(_lower + _sideLength)
  302.         _range = np.arange(_lower, _upper, 1)
  303.  
  304.         for y in _range:
  305.             for x in _range:
  306.                 self.food_map[y, x] = 1
  307.  
  308.         self.populate_food_cells()
  309.    
  310.     def _density_map(self, food_map_density, blocks):
  311.         self.food_map = np.reshape(self.food_map,
  312.                                    (self.map_size, self.map_size))
  313.        
  314.         self.cells_per_block = n_cells / blocks
  315.         self.blocks_per_side = np.sqrt(blocks)
  316.         self.block_size = self.map_size / self.blocks_per_side
  317.         self.n_food_cells = self.cells_per_block * food_map_density / 100
  318.        
  319.         for col in range(self.blocks_per_side):
  320.             for row in range(self.blocks_per_side):
  321.                 self.food_cells = np.random.choice(self.cells_per_block, self.n_food_cells, replace=False)
  322.                 for cell in self.food_cells:
  323.                     self.food_map[(col * self.block_size) + (cell % self.block_size),
  324.                                   (row * self.block_size) + (cell // self.block_size)] = 1
  325.                          
  326.         self.populate_food_cells()
  327.  
  328.     def populate_food_cells(self):
  329.         # food on each cell
  330.         y, x = np.nonzero(self.food_map)
  331.         for X, Y in zip(x, y):
  332.  
  333.             if food_cell_value == "max_food_per_cell":
  334.                 self.food_map[X, Y] = self.max_food_per_cell
  335.  
  336.             if food_cell_value == "random":
  337.                 # set limits
  338.                 food_cell_values = range(BOT_DEFAULTS['Ein_perFeed'],
  339.                                          self.max_food_per_cell + 1,
  340.                                          BOT_DEFAULTS['Ein_perFeed'])
  341.                 self.food_map[X, Y] = random.choice(food_cell_values)
  342.  
  343.     def __repr__(self):
  344.         return "Food({}, {}, {})".format(
  345.             self.n_cells,
  346.             self.map_size,
  347.             self.max_food_per_cell,)
  348.  
  349.     def __str__(self):
  350.         return str(self.food_map)
  351.  
  352. class Bot(object):
  353.     """
  354.   Robot agents that travel around the grid space, eating the food.
  355.  
  356.   Parameters
  357.   ----------
  358.   base_metabolism : int
  359.       The base energy consumption per simulation step of each bot
  360.   Eremoved_perFeed : int
  361.       The amount of energy removed from the cell on the food map on which a
  362.       bot is located every time athe bot feeds.
  363.   Estored_init : float
  364.       The amount of stored energy the bots are initialised with.
  365.   Ecost_perStep : int
  366.       The energy consumed by the bot for each step of size = one grid space.
  367.   Eth_explore : int
  368.       The stored energy threshold that prompts bots to change their task from
  369.       storing energy to exploring.
  370.   Eth_store : int
  371.       The stored energy threshold that prompts bots to change their task from
  372.       exploring to storing energy and aggregating bots around the
  373.       source of energy.
  374.   Eth_troph : int
  375.       The stored energy threshold at which the bot begins sharing energy with
  376.       others.
  377.   Eth_battFull : int
  378.       The stored energy threshold at which a bot stops receiving energy during
  379.       trophallaxis.
  380.   Estored_max : int.
  381.       The value of stored energy above which feeding does not increase the
  382.   senseRange, : int
  383.       The thickness of the border around the bot location within which
  384.       cells are considered in sensing operations.
  385.   troph : logical
  386.       Boolean value for whether bots feed each other or not.
  387.   trophMode : string
  388.       The name of the method the bot uses when feeding bots.
  389.   eff_E_conversion : int
  390.       The efficency (maximum = 1) with which energy removed from the food
  391.       map is converted to stored energy.
  392.   t_steps_to_charge : int
  393.       The number of time steps the bot takes for the converted energy to be
  394.       stored.
  395.  
  396.   Attributes
  397.   ----------
  398.   base_metabolism : int
  399.       The base energy consumption per simulation step of each bot
  400.   Eremoved_perFeed : int
  401.       The amount of energy removed from the cell on the food map on which a
  402.       bot is located every time athe bot feeds.
  403.   Estored_init : float
  404.       The amount of stored energy the bots are initialised with.
  405.   Ecost_perStep : int
  406.       The energy consumed by the bot for each step of size = one grid space.
  407.   Eth_explore : int
  408.       The stored energy threshold that prompts bots to change their task from
  409.       storing energy to exploring.
  410.   Eth_store : int
  411.       The stored energy threshold that prompts bots to change their task from
  412.       exploring to storing energy and aggregating bots around the
  413.       source of energy.
  414.   Eth_troph : int
  415.       The stored energy threshold at which the bot begins sharing energy with
  416.       others.
  417.   Eth_battFull : int
  418.       The stored energy threshold at which a bot stops receiving energy during
  419.       trophallaxis.
  420.   Estored_max : int.
  421.       The value of stored energy above which feeding does not increase the
  422.   senseRange, : int
  423.       The thickness of the border around the bot location within which
  424.       cells are considered in sensing operations.
  425.   troph : logical
  426.       Boolean value for whether bots feed each other or not.
  427.   trophMode : string
  428.       The name of the method the bot uses when feeding bots.
  429.   eff_E_conversion : int
  430.       The efficency (maximum = 1) with which energy removed from the food
  431.       map is converted to stored energy.
  432.   t_steps_to_charge : int
  433.       The number of time steps the bot takes for the converted energy to be
  434.       stored.
  435.   E_stored : float
  436.       The cumulative energy from feeding less the energy consumed.
  437.   location : tuple
  438.       The x, y coordinates of the bot location on the bot map.
  439.   new_location_generator : string
  440.       The name of the method the bot uses to choose a new location on the bot
  441.       map to attempt to move to.
  442.   new_location_generators : dictionary
  443.       The possible new location generators used by the bot.
  444.   target_location : tuple
  445.       The x, y coordinates of the location on the bot map that the bot will
  446.       attempt to move to.
  447.  
  448.  
  449.  
  450.  
  451.   bots : list
  452.       A list of all the bots that exist.
  453.   sense_kernel : array
  454.       A kernel of values used in bot operations that "sense" the cells
  455.       surrounding the bot, with the footprint of the sensed cells equal to the
  456.       dimensions of the kernel.
  457.  
  458.   """
  459.     bots = []
  460.  
  461.     sense_kernel = np.zeros((2 * BOT_DEFAULTS["senseRange"]+ 1) ** 2)
  462.     sense_kernel[(len(sense_kernel) // 2)] = 1
  463.     kernel_size = np.sqrt(len(sense_kernel))
  464.     sense_kernel = np.reshape(sense_kernel, (kernel_size, kernel_size))
  465.  
  466.     def __init__(self, world, *,
  467.                  base_metabolism,
  468.                  EinPerFeed,
  469.                  eff_E_conversion,
  470.                  t_steps_to_charge,
  471.                  Estored_init,
  472.                  Estored_max,
  473.                  Eth_battFull,
  474.                  Ecost_perStep,
  475.                  #Ecost_perFeed,
  476.                  senseRange,
  477.                  trophallaxis,
  478.                  scavenge,
  479.                  trophMode):
  480.  
  481.         self.base_metabolism = base_metabolism
  482.         self.EinPerFeed = EinPerFeed
  483.         self.Estored_init = Estored_init
  484.         self.Ecost_perStep = Ecost_perStep
  485.         self.Eth_battFull = Eth_battFull
  486.         self.Estored_max = Estored_max
  487.         self.senseRange = senseRange
  488.         self.troph = trophallaxis
  489.         self.scavenge = scavenge
  490.         self.trophMode = trophMode
  491.         self.eff_E_conversion = eff_E_conversion
  492.         self.t_steps_to_charge = t_steps_to_charge
  493.         self.Estored = Estored_init
  494.         self.location = None
  495.         self.new_location_generator = "levy"
  496.         self.target_location = None
  497.         self.bots.append(self)
  498.  
  499.         self.new_location_generators = {
  500.             "random": self.new_location_random,
  501.             "levy": self.new_location_levy,
  502.         }
  503.  
  504.         #self.id = None
  505.         self.levylastdirection = ['0', '0']
  506.         self.levycumulativedir = [0, 0]
  507.  
  508.     def sense(self, map, sensing_target):
  509.         """
  510.       Checks if bot has any neighbouring bots/ spaces/ recruits
  511.       Parameters
  512.       ----------
  513.       map : array
  514.           The map whose contents are being sensed.
  515.       sensing_target : string
  516.           The item to search for.
  517.  
  518.       Returns
  519.       -------
  520.       list[Location]
  521.           The location of all neighbours of the target type.
  522.  
  523.       """
  524.         # top left hand corner of kernel = i, j
  525.         i = self.location.y - BOT_DEFAULTS["senseRange"]
  526.         j = self.location.x - BOT_DEFAULTS["senseRange"]
  527.         k = np.shape(Bot.sense_kernel)[0]
  528.  
  529.         neighbours = np.argwhere(map[i:i + k, j:j + k]
  530.                                  - Bot.sense_kernel ==
  531.                                  SENSING_TARGETS[sensing_target])
  532.  
  533.         return [Location(x + j, y + i) for y, x in neighbours]
  534.  
  535.     def evaluate_neighbours(self, world):
  536.         """
  537.  
  538.       Parameters
  539.       ----------
  540.       world : object
  541.           The world in which the bots live
  542.  
  543.       Returns
  544.       -------
  545.  
  546.       """
  547.         location = self.location
  548.         #print(self.location)
  549.  
  550.         neighbours = self.sense(np.ma.make_mask(world.bot_map) * 1,
  551.                                 "neighbouring_bot")
  552.  
  553.         # print("neighbours", neighbours)
  554.         #
  555.         # print(world.food_map)
  556.         #
  557.         # bot_on_food = bool((np.ma.make_mask(world.food_map) * 1))
  558.         #                    [location[::-1]])
  559.         #
  560.         # print(bot_on_food)
  561.         #
  562.         # print("on food", bot_on_food)
  563.  
  564.         if neighbours == []:
  565.             pass
  566.  
  567.         else:
  568.             return neighbours  # neighbours_food
  569.             # CATAGORISES NEIGHOURS BY FOOD VALUE OF CURRENT LOCATION
  570.             # neighbours = {}
  571.             #
  572.             # bot_not_on_food_map = np.ma.make_mask(world.bot_map) * 1 - \
  573.             #                   np.ma.make_mask(world.food_map) * 1
  574.             #
  575.             # bot_on_food_map = np.ma.make_mask(world.bot_map) * 1 + \
  576.             #               np.ma.make_mask(world.food_map) * 1
  577.             #
  578.             # if bot_on_food:
  579.             #     neighbours["bot1_neighbour0"] = \
  580.             #         self.sense(bot_not_on_food_map, "neighbour_not_on_food")
  581.             #
  582.             #     neighbours["bot1_neighbour1"] = \
  583.             #         self.sense(bot_on_food_map, "neighbour_on_food")
  584.             #
  585.             # else:  # if food cell empty
  586.             #
  587.             #     neighbours["bot0_neighbour0"] = \
  588.             #         self.sense(bot_not_on_food_map,"neighbour_not_on_food")
  589.             #
  590.             #     neighbours["bot0_neighbour1"] = \
  591.             #         self.sense(bot_on_food_map, "neighbour_on_food")
  592.  
  593.  
  594.  
  595.     def new_location_random(self, location, world):
  596.         """
  597.       Determines the next space the bot will attempt to move to.
  598.  
  599.       Parameters
  600.       ----------
  601.       initial_location: named tuple
  602.           The x,y coordinates of position the bot will attempt to move from.
  603.  
  604.       Returns
  605.       -------
  606.       new_location : name tuple
  607.           The x,y coordinates of next position the bot will attempt to move to.
  608.       """
  609.  
  610.         new_location = Location(
  611.             np.clip(location.x + random.randint(-1, 1),
  612.                     BOT_DEFAULTS["senseRange"],
  613.                     world.bot_map_size - 1
  614.                     - BOT_DEFAULTS["senseRange"]),
  615.             np.clip(location.y + random.randint(-1, 1),
  616.                     BOT_DEFAULTS["senseRange"],
  617.                     world.bot_map_size - 1
  618.                     - BOT_DEFAULTS["senseRange"]))
  619.  
  620.         return new_location
  621.  
  622.     """Levy related functions"""
  623.     def switch_levy_direction(self, direction):
  624.         if direction == '+1':
  625.             new_direction = '-1'
  626.         elif direction == '-1':
  627.             new_direction = '+1'
  628.  
  629.         return(new_direction)
  630.  
  631.     def generate_levy_values(self, mode, levycumthreshold):
  632.         if mode == '+':
  633.             axis = random.randint(0, 1)
  634.             # 0: move along x
  635.             # 1: move along y
  636.             if axis == 0:
  637.                 new_direction_x = levyrandom.direction(self.levylastdirection[0])
  638.                 new_direction_y = '0'
  639.             elif axis == 1:
  640.                 new_direction_x = '0'
  641.                 new_direction_y = levyrandom.direction(self.levylastdirection[1])
  642.  
  643.         elif mode == 'x':
  644.             new_direction_x = levyrandom.direction(self.levylastdirection[0])
  645.             new_direction_y = levyrandom.direction(self.levylastdirection[1])
  646.  
  647.         elif mode == '*':
  648.             axis = random.randint(0, 3)
  649.             # 0: move along x
  650.             # 1: move along y
  651.             # 2,3: move along a diagonal
  652.             if axis == 0:
  653.                 new_direction_x = levyrandom.direction(self.levylastdirection[0])
  654.                 new_direction_y = '0'
  655.             elif axis == 1:
  656.                 new_direction_x = '0'
  657.                 new_direction_y = levyrandom.direction(self.levylastdirection[1])
  658.             elif axis > 1:
  659.                 new_direction_x = levyrandom.direction(self.levylastdirection[0])
  660.                 new_direction_y = levyrandom.direction(self.levylastdirection[1])
  661.  
  662.         self.levycumulativedir[0] += int(new_direction_x)
  663.         self.levycumulativedir[1] += int(new_direction_y)
  664.  
  665.         if abs(self.levycumulativedir[0]) > levycumthreshold:
  666.             self.levycumulativedir[0] = 0
  667.             new_direction_x = self.switch_levy_direction(new_direction_x)
  668.  
  669.         if abs(self.levycumulativedir[1]) > levycumthreshold:
  670.             self.levycumulativedir[1] = 0
  671.             new_direction_y = self.switch_levy_direction(new_direction_y)
  672.  
  673.         self.levylastdirection = [new_direction_x, new_direction_y]
  674.  
  675.         return(self.levylastdirection)
  676.  
  677.     def new_location_levy(self, location, world):
  678.         """
  679.       Determines the next space the bot will attempt to move to.
  680.  
  681.       Parameters
  682.       ----------
  683.       initial_location: named tuple
  684.           The x,y coordinates of position the bot will attempt to move from.
  685.  
  686.       Returns
  687.       -------
  688.       new_location : name tuple
  689.           The x,y coordinates of next position the bot will attempt to move to.
  690.       """
  691.  
  692.         """
  693.       mode allowed values:
  694.       '+' generates levy values to move only horizontally and vertically, one direction at time
  695.       'x' generates levy values to move diagonally, both directions at once
  696.       '*' generates levy values to move randomly in all 8 possible directions
  697.       """
  698.         mode = '*'
  699.         max_steps_on_same_direction = 20
  700.  
  701.         new_direction = self.generate_levy_values(mode, max_steps_on_same_direction)
  702.  
  703.         new_location = Location(
  704.             np.clip(location.x + int(new_direction[0]),
  705.                     BOT_DEFAULTS["senseRange"],
  706.                     world.bot_map_size - 1
  707.                     - BOT_DEFAULTS["senseRange"]),
  708.             np.clip(location.y + int(new_direction[1]),
  709.                     BOT_DEFAULTS["senseRange"],
  710.                     world.bot_map_size - 1
  711.                     - BOT_DEFAULTS["senseRange"]))
  712.  
  713.         return new_location
  714.     """/Levy related functions"""
  715.  
  716.     def move(self, world, location):
  717.         """
  718.       Moves the bot and updates the stroed energy accordingly.
  719.  
  720.       Parameters
  721.       ----------
  722.       new_location : Location
  723.           The location to move to.
  724.       """
  725.  
  726.         # stop charging
  727.         world.charge_map[location] = 0
  728.  
  729.         # select a target neighbouring lement address to move to
  730.         new_location = self.new_location_generators[
  731.             str(self.new_location_generator)](
  732.             location,
  733.             world)
  734.  
  735.         world.bot_map[location[::-1]].update_maps(world,
  736.                                                   new_location,
  737.                                                   location)
  738.  
  739.         world.Acovered_map += np.copy(np.ma.make_mask(world.bot_map) * 1)
  740.  
  741.         #world.Acovered_map += np.ma.make_mask(world.bot_map) * 1
  742.  
  743.  
  744.     def update_maps(self, world, new_location, initial_location):
  745.  
  746.         maps_to_update = [world.move_map,
  747.                           world.Estored_map,
  748.                           world.bot_map]
  749.  
  750.         for _map in maps_to_update:
  751.             if isinstance(_map[initial_location[::-1]], Bot):
  752.                 new_value = _map[initial_location[::-1]]
  753.  
  754.             else:
  755.                 new_value = np.clip((_map[initial_location[::-1]]
  756.                                      - BOT_DEFAULTS["Ecost_perStep"]),
  757.                                      0, float("inf"))
  758.  
  759.             # DOES NOT MOVE
  760.             if world.bot_map[new_location[::-1]]:
  761.                 _map[initial_location[::-1]] = new_value
  762.  
  763.             # MOVES
  764.             elif world.bot_map[new_location[::-1]] == None:
  765.                 _map[new_location[::-1]] = new_value
  766.  
  767.                 # delete initial location
  768.                 if isinstance(_map[initial_location[::-1]], Bot):
  769.                     _map[initial_location[::-1]] = None
  770.                 else:
  771.                     _map[initial_location[::-1]] = 0
  772.  
  773.     def trophallaxis(self, world, neighbours):
  774.         #print("TROPHALAXIS")
  775.         # TODO: create a trophallaxis map of robots engagaed in trophallaxis so
  776.         # that only one exchnage happens per robot per timestep
  777.         global trophallaxis_value
  778.         if world.charge_map[self.location[::-1]] != 0:
  779.             # random.shuffle(neighbours)
  780.             # for neighbour in neighbours:
  781.             neighbour = random.choice(neighbours)
  782.             Eself = world.Estored_map[self.location[::-1]]
  783.             Eneighbour = world.Estored_map[neighbour[::-1]]
  784.             Eaverage = float((Eself + Eneighbour)/2)
  785.             trophallaxis_value += 1
  786.             print(trophallaxis_value, "sharinggggggggggggggggggggggggggggg")
  787.             world.Estored_map[self.location[::-1]] = Eaverage
  788.             world.Estored_map[neighbour[::-1]] = Eaverage
  789.             # E = float(Eself/ 2)
  790.             # world.Estored_map[self.location[::-1]] -= E
  791.             # world.Estored_map[neighbour[::-1]] += E
  792.         else:
  793.             pass
  794.  
  795.     def __repr__(self):
  796.         return "Bot({})".format(self.location)
  797.  
  798.     def __str__(self): # real signature unknown
  799.         """ Return str(self). """
  800.         return "x{}_y{}".format(self.location[0],self.location[1])
  801.  
  802. class World(object):
  803.     """
  804.   Maps the distribution of food over the grid space.
  805.  
  806.   Parameters
  807.   ----------
  808.   n_bots : int
  809.       The number of bots
  810.   _food : Food
  811.       The food distribution across the grid space.
  812.  
  813.   Attributes
  814.   ----------
  815.   n_bots : int
  816.       The number of bots
  817.   _food : object
  818.       The food distribution across the grid space.
  819.   n_cells :
  820.       The number of food cells
  821.   map_size : int
  822.       The length of each side of the food map.
  823.   food_map : np.ndarray
  824.       The distribution of food across the grid space.
  825.   bot_map : np.ndarray
  826.       The distribution of bots across the grid space.
  827.   bot_map_size : int
  828.       The length of each side of the bot map in grid units.
  829.   _bots_on_food : int
  830.       The number of bots located on a cell containing food
  831.   Estored_map : np.ndarray
  832.       The map of cumulative energy stored by each bot.
  833.   Acovered_map : np.ndarray
  834.       A map showing the number of times a grid cell has been entered by a bot.
  835.   trajectory_coords : Dictionary
  836.      Coordinates of start and end point that define robots motion vector
  837.  
  838.   """
  839.  
  840.     def __init__(self, food):
  841.         self.n_bots = n_bots
  842.         self._food = food
  843.         self.n_cells = n_cells
  844.         self.map_size = self._food.map_size
  845.         self.food_map, self.food_map_size = self._pad_map(
  846.             self._food.food_map, BOT_DEFAULTS['senseRange'])
  847.  
  848.         if show_plot == True:
  849.             plt.matshow(self.food_map)
  850.             plt.show()
  851.  
  852.         self.bot_map = None
  853.         self.bot_map_size = None
  854.         self._populate_bot_map()
  855.         self._bots_on_food = None
  856.  
  857.         self.Estored_map = np.ma.make_mask(self.bot_map) \
  858.                                      * BOT_DEFAULTS["Estored_init"]
  859.  
  860.         self.Acovered_map = np.copy(np.ma.make_mask(self.bot_map) * 1)
  861.  
  862.         self.move_map = np.zeros_like(self.food_map)
  863.  
  864.         self.charge_map = np.zeros_like(self.food_map)
  865.  
  866.         # self.charge_map = np.multiply(np.ma.make_mask(self.bot_map) * 1,
  867.         #                                    np.ma.make_mask(self.food_map) * 1)
  868.  
  869.         self.trajectory_coords = {"x_preMove" : [],
  870.                                   "y_preMove" : [],
  871.                                   "y_postMove": [],
  872.                                   "x_postMove": [],
  873.                                  }
  874.  
  875.     def _pad_map(self, map_to_pad, _border_width):
  876.         """
  877.       Creates a border of width = _border_width around the map as dictated by
  878.       the sense range of the bots. This is to prevent errors generated by
  879.       functions that use elements of a window around each bot, the size of
  880.       which is defined  by the robot sense range.
  881.  
  882.       Parameters
  883.       ----------
  884.       map_to_pad : array
  885.           The map to pad.
  886.  
  887.       _border_width :
  888.           The border width in grid units
  889.       """
  890.         _full_map_size = int(self.map_size + 2*_border_width)
  891.  
  892.         if map_to_pad.dtype == object:
  893.             _full_map = np.empty(
  894.                 (_full_map_size) ** 2, dtype=object).reshape(_full_map_size,
  895.                  _full_map_size)
  896.  
  897.         else:
  898.             _full_map = np.zeros(
  899.                 (_full_map_size) ** 2).reshape(_full_map_size,_full_map_size)
  900.  
  901.         _full_map[_border_width:(
  902.                 _border_width + self.map_size),
  903.                 _border_width:(_border_width + self.map_size)] = map_to_pad
  904.  
  905.         return _full_map, _full_map_size
  906.  
  907.     def _populate_bot_map(self):
  908.  
  909.  
  910.         """
  911.       Distributes n_bots start locations randomly over the grid space
  912.  
  913.       """
  914.         # TODO: if random seed gives you same starting map, this can be removed
  915.         if bot_map_style == "existing_map":
  916.             self.bot_map = np.load(path
  917.                                    + "/" + bot_map_dir
  918.                                    + "/" + bot_map_name + "bots.npy")
  919.             self.bot_map_size = np.shape(self.bot_map)[0]
  920.             bot_map_name = path \
  921.                            + "/" + dataName \
  922.                            + "/" + bot_map_name
  923.  
  924.         else:
  925.  
  926.             if bot_map_style == "new_map":
  927.                 self._new_map()
  928.  
  929.             if bot_map_style == "central_map":
  930.                 self._central_map()
  931.  
  932.             if bot_map_style == "random_map":
  933.                 self._random_map()
  934.                 if set_number_agents_on_food == True:
  935.                     while len(self._bots_on_food) != n_agents_on_food:
  936.                         self._random_map()
  937.  
  938.             # give each bot a location identity
  939.             y, x = np.where(self.bot_map)
  940.             for Y, X in zip(y, x):
  941.                 self.bot_map[Y, X].location = Location(X, Y)
  942.  
  943.             bot_map_name = (path
  944.                             + "/" + dataName
  945.                             + "/" + dataName)
  946.  
  947.         np.save(bot_map_name + "_bots", self.bot_map)
  948.  
  949.  
  950.  
  951.         if show_plot == True:
  952.             plt.matshow(np.ma.make_mask(self.bot_map)*1)
  953.             plt.show()
  954.  
  955.     def _random_map(self):
  956.  
  957.         self.bot_map = np.empty(self.n_cells, dtype=object)
  958.  
  959.         for i in range(self.n_bots):
  960.             self.bot_map[i] = Bot(self, **BOT_DEFAULTS)
  961.  
  962.         np.random.shuffle(self.bot_map)
  963.         self.bot_map = np.reshape(self.bot_map, (self.map_size, self.map_size))
  964.  
  965.         self.bot_map, self.bot_map_size = self._pad_map(
  966.             self.bot_map, BOT_DEFAULTS['senseRange'])
  967.  
  968.         self._bots_on_food = np.where(
  969.             (np.ma.make_mask(self.bot_map) * 1 > 0) &
  970.             (self.food_map > 0))
  971.  
  972.         #print(len(self._bots_on_food))
  973.  
  974.     def _new_map(self):
  975.  
  976.         self.bot_map = np.empty(self.n_cells, dtype=object)
  977.  
  978.         self.bot_map = np.reshape(self.bot_map, (self.map_size, self.map_size))
  979.  
  980.         for y, x in zip(bot_y_range, bot_x_range):
  981.             self.bot_map[y,x] = Bot(self, **BOT_DEFAULTS)
  982.  
  983.         self.bot_map, self.bot_map_size = self._pad_map(
  984.             self.bot_map, BOT_DEFAULTS['senseRange'])
  985.  
  986.     def _central_map(self):
  987.         #print("central")
  988.  
  989.         self.bot_map = np.empty(self.n_cells, dtype=object)
  990.  
  991.         self.bot_map = np.reshape(self.bot_map, (self.map_size, self.map_size))
  992.  
  993.         _midpoint = int(self.map_size/2)
  994.         _sideLength = int(np.sqrt(self.n_bots))
  995.         _lower = int(_midpoint-(_sideLength/2))
  996.         _upper = int(_lower + _sideLength)
  997.         _range = np.arange(_lower, _upper,1)
  998.  
  999.         for y in _range:
  1000.             for x in _range:
  1001.                 self.bot_map[y,x] = Bot(self, **BOT_DEFAULTS)
  1002.  
  1003.         self.bot_map, self.bot_map_size = self._pad_map(
  1004.             self.bot_map, BOT_DEFAULTS['senseRange'])
  1005.  
  1006.     def save_data_per_timestep(self):
  1007.  
  1008.         # log data to data per cycle
  1009.         with open(dataTimestep, 'a') as c:
  1010.             writer = csv.writer(c)
  1011.             writer.writerow([
  1012.  
  1013.                 # count
  1014.                 count,
  1015.  
  1016.                 # total food
  1017.                 np.sum(self.food_map),
  1018.  
  1019.                 # number of food patches
  1020.                 len(np.where(self.food_map)[0]),
  1021.  
  1022.                 # _bots_with_Estored
  1023.                 len(np.where(self.Estored_map)[0]),
  1024.  
  1025.                 # total area covered
  1026.                 len(np.where(self.Acovered_map)[0]),
  1027.  
  1028.                 # total steps taken
  1029.                 np.sum(self.Acovered_map),
  1030.  
  1031.                 # maximum on board eergy
  1032.                 np.amax(self.Estored_map),
  1033.  
  1034.                 # trophallaxis
  1035.                 trophallaxis_value,
  1036.  
  1037.             ])
  1038.  
  1039.     def save_data_init(self, food_map):
  1040.  
  1041.         """
  1042.       Creates a dictionary of the attributes of the World object and the
  1043.       default properties of the bots. Saves these and other global data and
  1044.       parameters of the World object to a new csv file.
  1045.       Defines heaidings of parameters to be recorded at each timestep to a new
  1046.       csv file and calculates and saves initial values.
  1047.  
  1048.       Parameters
  1049.       ----------
  1050.       food_map : array
  1051.           An attribute to remove from the dictionary.
  1052.       """
  1053.  
  1054.         attributes = food_map.__dict__
  1055.         del attributes["food_map"]
  1056.         attributes.update(BOT_DEFAULTS)
  1057.  
  1058.         # write data to data summary
  1059.         with open(dataSummary, 'w') as s:
  1060.             writer = csv.writer(s)
  1061.             for key, value in attributes.items():
  1062.                 writer.writerow([key, value])
  1063.             writer.writerow(["n_food_cells_initial",
  1064.                              len(np.where(self.food_map)[0])])
  1065.             writer.writerow(["n_bots", self.n_bots])
  1066.             writer.writerow(["FiniteFood", FiniteFood])
  1067.             writer.writerow(["food_map_style", food_map_style])
  1068.             writer.writerow(["bot_map_style", bot_map_style])
  1069.             writer.writerow(["maxTimesteps", maxTimesteps])
  1070.             writer.writerow(["seed np:", seed_np])
  1071.             writer.writerow(["seed random:", seed_random])
  1072.  
  1073.         # setup data per timestep file
  1074.         with open(dataTimestep, 'w') as c:
  1075.             writer = csv.writer(c)
  1076.             writer.writerow(data_per_timestep)
  1077.  
  1078.         self.save_data_per_timestep()
  1079.  
  1080.     def save_data_food_finished(self):
  1081.  
  1082.         """
  1083.       Creates a dictionary of the attributes of the World object and the
  1084.       default properties of the bots. Saves these and other global data and
  1085.       parameters of the World object to a new csv file.
  1086.       Defines heaidings of parameters to be recorded at each timestep to a new
  1087.       csv file and calculates and saves initial values.
  1088.  
  1089.       Parameters
  1090.  
  1091.       ----------
  1092.       food_map : array
  1093.           An attribute to remove from the dictionary.
  1094.  
  1095.       """
  1096.  
  1097.         lst = ['time_food_finished', "bots_with_Estored_food_finished" ]
  1098.         with open(dataSummary, 'rt') as f:
  1099.             reader = csv.reader(f, delimiter=',')
  1100.             for row in reader:
  1101.                 print(row)
  1102.                 for l in lst:
  1103.                     if row[0] == l:
  1104.                         print(lst)
  1105.                         lst.remove(l)
  1106.         if lst != []:
  1107.             print(lst)
  1108.             with open(dataSummary, 'a') as s:
  1109.                 writer = csv.writer(s)
  1110.                 writer.writerow(["time_food_finished", count])
  1111.                 writer.writerow(["bots_with_Estored_food_finished",
  1112.                                  len(np.where(self.Estored_map)[0])])
  1113.  
  1114.     def save_data_final(self):
  1115.  
  1116.         """
  1117.       Creates a dictionary of the attributes of the World object and the
  1118.       default properties of the bots. Saves these and other global data and
  1119.       parameters of the World object to a new csv file.
  1120.       Defines heaidings of parameters to be recorded at each timestep to a new
  1121.       csv file and calculates and saves initial values.
  1122.  
  1123.       Parameters
  1124.  
  1125.       ----------
  1126.       food_map : array
  1127.           An attribute to remove from the dictionary.
  1128.  
  1129.       """
  1130.         with open(dataSummary, 'a') as s:
  1131.             writer = csv.writer(s)
  1132.             writer.writerow(["count", count])
  1133.             writer.writerow(["total_food_final", np.sum(self.food_map)])
  1134.             writer.writerow(["n_food_cells_final",
  1135.                              len(np.where(self.food_map)[0])])
  1136.             writer.writerow(["bots_with_Estored_final",
  1137.                              len(np.where(self.Estored_map)[0])])
  1138.             writer.writerow(["total_area_covered",
  1139.                              len(np.where(self.Acovered_map)[0])])
  1140.             writer.writerow(["total_steps_taken",
  1141.                              np.sum(self.Acovered_map)])
  1142.  
  1143.             lst = ['time_food_finished', "bots_with_Estored_food_finished"]
  1144.             with open(dataSummary, 'rt') as f:
  1145.                 reader = csv.reader(f, delimiter=',')
  1146.                 for row in reader:
  1147.                     print(row)
  1148.                     for l in lst:
  1149.                         if row[0] == l:
  1150.                             print(lst)
  1151.                             lst.remove(l)
  1152.             if lst != []:
  1153.                 print(lst)
  1154.                 with open(dataSummary, 'a') as s:
  1155.                     writer = csv.writer(s)
  1156.                         # writer.writerow(["time_food_finished"],0)
  1157.                         # writer.writerow(["bots_with_Estored_food_finished"],0)
  1158.                     writer.writerow(["time_food_finished"])
  1159.                     writer.writerow(["bots_with_Estored_food_finished"])
  1160.  
  1161.         AcoveredFinal = np.where(self.Acovered_map)
  1162.  
  1163.         np.save(path \
  1164.                       + "/" + dataName \
  1165.                       + "/" + dataName + '_AcoveredFinal',
  1166.                 np.where(self.Acovered_map))
  1167.  
  1168.         #print("done")
  1169.  
  1170.     def plot(self):
  1171.  
  1172.         global count
  1173.  
  1174.         plot_dir = path \
  1175.                    + "/" + dataName \
  1176.                    + "/" + "plot_data"\
  1177.                    + "/"
  1178.  
  1179.         plot_layer_names = ["_food", "_Estored", "_bots", "_bots_loc" ]
  1180.         plot_layers = [self.food_map,
  1181.                        self.Estored_map,
  1182.                        self.bot_map,
  1183.                        (np.ma.make_mask(self.bot_map)*1)]
  1184.  
  1185.         for name, layer in zip(plot_layer_names, plot_layers):
  1186.             y, x = np.where(layer)
  1187.             nonzero = zip(y, x)
  1188.  
  1189.             with open(plot_dir
  1190.                               + name
  1191.                               + str(count).zfill(4)
  1192.                               + '.txt', 'w+') as outf:
  1193.  
  1194.                 for r, k in nonzero:
  1195.                     if name == "_bots":
  1196.                         outf.write(
  1197.                             '{:d}{:d}{!s:s}\n'.format(
  1198.                                 r, k, layer[r, k]))
  1199.  
  1200.                     else:
  1201.                         outf.write(
  1202.                             '{:d} {:d} {:g}\n'.format(
  1203.                                 r, k, layer[r, k]))
  1204.  
  1205. #        for i in self.trajectory_coords:
  1206. #            with open(plot_dir
  1207. #                              + "_trajectory_coords"
  1208. #                              + str(count).zfill(4)
  1209. #                              + '.csv', 'w') as f:
  1210. #
  1211. #                writer = csv.writer(f)
  1212. #                for row in self.trajectory_coords.items():
  1213. #                    writer.writerow(row)
  1214.  
  1215.     def feed(self):
  1216.         """
  1217.       Decreases food map by 1 unit in every grid cell newly occupied by a bot
  1218.       Updates the bot charging map with new occupants
  1219.       Updates the stored energy map of all charging bots with the energy from
  1220.       feeding divided by the number of time steps taken to charge.
  1221.  
  1222.       """
  1223.  
  1224.         Ein = BOT_DEFAULTS["EinPerFeed"]
  1225.         eff = BOT_DEFAULTS["eff_E_conversion"]
  1226.         t_steps = BOT_DEFAULTS["t_steps_to_charge"]
  1227.  
  1228.         chargePerTimetep = float(Ein * eff / t_steps)
  1229.  
  1230.         new_bots_on_food = np.where((np.ma.make_mask(self.bot_map)*1>0)
  1231.                                    & (self.food_map > 0)
  1232.                                    & (self.charge_map == 0))
  1233.  
  1234.         if FiniteFood == True:
  1235.             self.food_map[new_bots_on_food] -= BOT_DEFAULTS["EinPerFeed"]
  1236.             np.clip(self.food_map, 0, float("inf"), self.food_map)
  1237.  
  1238.         if BOT_DEFAULTS["scavenge"] == True:
  1239.             self.charge(new_bots_on_food, chargePerTimetep)
  1240.  
  1241.     def charge(self, new_bots_on_food, chargePerTimetep):
  1242.         """
  1243.       Updates the stored energy map of all charging bots with the energy from
  1244.       feeding divided by the number of time steps taken to charge.
  1245.  
  1246.       """
  1247.         # self.charge_map[np.where(self.charge_map)] += chargePerTimetep
  1248.         #
  1249.         # self.charge_map[new_bots_on_food] += chargePerTimetep
  1250.  
  1251.         self.charge_map[np.where(self.charge_map)] += 1
  1252.  
  1253.         self.charge_map[new_bots_on_food] += 1
  1254.  
  1255.         self.move_map = np.multiply(
  1256.             self.move_map,
  1257.             np.invert(np.ma.make_mask(self.charge_map)) * 1)
  1258.  
  1259.         t_steps = BOT_DEFAULTS["t_steps_to_charge"]
  1260.  
  1261.         self.Estored_map = np.clip(np.where(self.charge_map,
  1262.                                             self.Estored_map + chargePerTimetep,
  1263.                                             self.Estored_map),
  1264.                                    0,
  1265.                                    BOT_DEFAULTS["Estored_max"],
  1266.                                    self.Estored_map)
  1267.         ### ****PRINT
  1268.         # print("charged")
  1269.         # print(self.charge_map)
  1270.         # print("charged")
  1271.         # print(self.charge_map[self.charge_map >= t_steps])
  1272.         # print("")
  1273.         # print("move")
  1274.         # print(self.move_map)
  1275.         # print("")
  1276.         # print("stored")
  1277.         # print(self.Estored_map)
  1278.         # print("")
  1279.  
  1280.         self.charge_map[self.charge_map >= t_steps] = 0
  1281.  
  1282.     def base_metabolism(self):
  1283.  
  1284.         """
  1285.  
  1286.       """
  1287.         np.clip(
  1288.             self.Estored_map - BOT_DEFAULTS["base_metabolism"],
  1289.             0, float("inf"), self.Estored_map)
  1290.  
  1291.     def functioning_bots(self):
  1292.  
  1293.         functioning_bots = []
  1294.  
  1295.         incapacitated_bots = self.incapacitated_bots()
  1296.         _bots = np.copy(self.bot_map)
  1297.         _bots[incapacitated_bots] = None
  1298.         _functioning_bots = np.argwhere(_bots)
  1299.         for _functioning_bot in _functioning_bots:
  1300.             bot = self.bot_map[_functioning_bot[0],
  1301.                                _functioning_bot[1]]
  1302.             functioning_bots.append(bot)
  1303.  
  1304.         return functioning_bots
  1305.  
  1306.  
  1307.     def incapacitated_bots(self):
  1308.         incapacitated_bots = np.where((self.bot_map != None)
  1309.                                       and self.Estored_map == 0)
  1310.         return incapacitated_bots
  1311.  
  1312.     def store_trajectory(self, preORpost, *initialPosition):
  1313.         if preORpost == "pre":
  1314.             y, x = np.nonzero(self.move_map)
  1315.             y=list(y)
  1316.             x=list(x)
  1317.  
  1318.             self.trajectory_coords["x_" + preORpost + "Move"].extend(x)
  1319.             self.trajectory_coords["y_" + preORpost + "Move"].extend(y)
  1320.  
  1321.         else:
  1322.             y, x = np.where(self.bot_map == initialPosition)
  1323.  
  1324.             self.trajectory_coords["x_" + preORpost + "Move"].append(x[0])
  1325.             self.trajectory_coords["y_" + preORpost + "Move"].append(y[0])
  1326.  
  1327.         return y,x
  1328.  
  1329.     def energy_transfer(self):
  1330.  
  1331.         # energy in
  1332.         self.feed()
  1333.  
  1334.         # energy out
  1335.         self.base_metabolism()
  1336.  
  1337.         functioning_bots = self.functioning_bots()
  1338.  
  1339.         if functioning_bots != []:
  1340.  
  1341.             random.shuffle(functioning_bots)
  1342.  
  1343.             for bot in functioning_bots:
  1344.  
  1345.                 neighbours = bot.sense(
  1346.                     np.ma.make_mask(self.bot_map) * 1,
  1347.  
  1348.                     "neighbouring_bot")
  1349.  
  1350.                 neighbours = bot.evaluate_neighbours(self)
  1351.  
  1352.                 if bool(neighbours) == False:
  1353.                     pass
  1354.  
  1355.                 else:
  1356.                     if BOT_DEFAULTS["trophallaxis"] == True:
  1357.                         bot.trophallaxis(self, neighbours)
  1358.  
  1359.  
  1360.     def movement(self):
  1361.         # self.move_map = np.where(
  1362.         #     self.Estored_map >= BOT_DEFAULTS["Eth_battFull"],
  1363.         #     self.Estored_map,
  1364.         #     self.move_map)
  1365.  
  1366.         # self.move_map = np.where(self.charge_map >= t_steps,
  1367.         #                          self.Estored_map,
  1368.         #                          self.move_map)
  1369.  
  1370.         # print("charge mode")
  1371.         # print(self.charge_map)
  1372.         # print("charge mode")
  1373.         # print(np.invert(self.charge_map))
  1374.  
  1375.  
  1376.         self.move_map = np.where(
  1377.             (self.Estored_map >= BOT_DEFAULTS["Eth_battFull"]) &
  1378.             (self.charge_map == 0),
  1379.             self.Estored_map,
  1380.             0)
  1381.  
  1382.         # print("move")
  1383.         # print(self.move_map)
  1384.         # print("")
  1385.  
  1386.         # print(self.move_map)
  1387.         # print("")
  1388.         # print(self.charge_map)
  1389.         # print("")
  1390.         # print(self.food_map)
  1391.         # print("")
  1392.  
  1393.         # print("MoveMap")
  1394.         # print(self.move_map[45:55 , 45:55] )
  1395.         # print("EstoredMap")
  1396.         # print(self.Estored_map[45:55 , 45:55] )
  1397.         # print("ChargeMap")
  1398.         # print(self.charge_map[45:55 , 45:55])
  1399.             #     self.Estored_map >= BOT_DEFAULTS["Eth_battFull"],
  1400.             #     self.Estored_map,
  1401.             #     self.move_map)
  1402.  
  1403.         #self.move_map = np.where(np.ma.make_map)
  1404.  
  1405.         if self.move_map.any():
  1406.  
  1407.             # print("move_map")
  1408.             # print(self.move_map)
  1409.  
  1410.             # log the initial position of each bot
  1411.             pre_move_y, pre_move_x = self.store_trajectory("pre")
  1412.             moving_bots = self.bot_map[pre_move_y, pre_move_x]
  1413.  
  1414.             # shuffle the bots
  1415.             # print(pre_move_y)
  1416.             # print(pre_move_x)
  1417.             # print("")
  1418.             bots_to_shuffle = list(zip(pre_move_y, pre_move_x))
  1419.             random.shuffle(bots_to_shuffle)
  1420.             pre_move_y, pre_move_x = zip(*bots_to_shuffle)
  1421.  
  1422.             # print(pre_move_y)
  1423.             # print(pre_move_x)
  1424.             # print("bots")
  1425.             # print(np.ma.make_mask(self.bot_map) * 1)
  1426.             # print("")
  1427.            
  1428.             # move all the bots
  1429.             for Y, X in zip(pre_move_y, pre_move_x):
  1430.                 # print(Y,X)
  1431.                 self.bot_map[Y, X].move(self, Location(X, Y))
  1432.                 # print(np.ma.make_mask(self.bot_map)*1)
  1433.  
  1434.             # log the final position of each bot
  1435.             for initPosition in moving_bots:
  1436.                 post_move_y, post_move_x = \
  1437.                     self.store_trajectory("post", initPosition)
  1438.  
  1439.                 # update each Bot instance location attribute to current position.
  1440.                 self.bot_map[post_move_y[0],
  1441.                               post_move_x[0]].location \
  1442.                     = Location(post_move_x[0], post_move_y[0])
  1443.  
  1444.  
  1445. def main():
  1446.  
  1447.     global count
  1448.     global trophallaxis_value
  1449.  
  1450.  
  1451.  
  1452.     # distributes food
  1453.     food_map = Food()
  1454.  
  1455.     # populate world with agents
  1456.     world = World(food_map)
  1457.     #print("food_map", world.food_map)
  1458.  
  1459.     world.save_data_init(food_map)
  1460.     if plot_output:
  1461.         world.plot()
  1462.  
  1463.     # loop until all bots incapacitated by hunger OR all food removed
  1464.     # while (np.any(world.Estored_map) and np.any(world.food_map)):
  1465.     while (np.any(world.Estored_map)
  1466.            #and np.any(world.food_map)
  1467.            and count <= maxTimesteps):
  1468.  
  1469.         # print(world.bot_map[45:55, 45:55])
  1470.         # print(np.ma.make_mask(world.bot_map[45:55, 45:55]) * 1)
  1471.  
  1472.  
  1473.         count += 1
  1474.         print("count", count, "=", trophallaxis_value)
  1475.         trophallaxis_value = 0
  1476.         world.energy_transfer()
  1477.         world.movement()
  1478.         world.save_data_per_timestep()
  1479.         if plot_output:
  1480.             world.plot()
  1481.         if np.any(world.food_map) == False:
  1482.             print("all food eaten")
  1483.             world.save_data_food_finished()
  1484.  
  1485.  
  1486.     if count >= maxTimesteps:
  1487.         print("exceeded maximum timesteps")
  1488.     else:
  1489.         print("all bots dead")
  1490.  
  1491.     world.save_data_final()
  1492.  
  1493. if __name__ == '__main__':
  1494.     try:
  1495.         main()
  1496.     finally:
  1497.         print("end")
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement