Advertisement
AmCholadawan

multi_agent_20180418

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