Advertisement
AmCholadawan

muti_agent_all_motions

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