Advertisement
AmCholadawan

multiagent_vlevy2

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