Advertisement
AmCholadawan

multi_agent_levywalk_densitymap

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