Advertisement
AmCholadawan

multi_agent_island_map_v2

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