In a previous post I constructed a simple agent-based simulation model, containing groups of agents that can be located on a battlefield grid. The model was coded in Python, using matplotlib for visualization.

The agents were modelled as a class, as shown below:

# class, defining agents as abstract data types class agent: # init-method, the constructor method for agents def __init__(self,x,y,group): self.life = 100 # agent's life score self.x = x self.y = y self.group = group

A 2-dimensional array for modelling the battlefield grid was created with a list comprehension in Python:

# creating empty 100 x 100 list using list comprehension in python battlefield = [[None for i in range(0,100)] for i in range(0,100)]

A helper function for creating a group of agents with defined group size was implemented as displayed below:

# -- define a function for creating agents and assigning them to grid def agentCreator(size,group,groupList,field,n,m): # loop through entire group, i.e. in this case 1000 units for j in range(0,size): # select random available location while True: # random x coordinate x = random.choice(range(0,n)) # random y coordinate y = random.choice(range(0,m)) # check if spot is available; if not then re-iterate if field[x][y] == None: field[x][y] = agent(x=x,y=y,group=group) # append agent object reference to group list groupList.append(field[x][y]) # exit while loop; spot on field is taken break

Using these model components I created an initial battlefield population and plotted agent locations using matplotlib. This is done in the code below:

# list with available x and y locations locations = battlefield.copy() # using .copy prevents copying by reference # create empty list for containing agent references in future, type A & B agents_A = [] agents_B = [] # assigning random spots to agents of group A and B; import random agentCreator(size = 1000, group = "A", groupList = agents_A, field = battlefield, n = 100, m = 100) agentCreator(size = 1000, group = "B", groupList = agents_B, field = battlefield, n = 100, m = 100) #.imshow() needs a matrix with float elements; population = [[0.0 for i in range(0,100)] for i in range(0,100)] # if agent is of type A, put a 1.0, if of type B, pyt a 2.0 for i in range(1,100): for j in range(1,100): if battlefield[i][j] == None: # empty pass # leave 0.0 in population cell elif battlefield[i][j].group == "A": # group A agents population[i][j] = 1.0 # 1.0 means "A" else: # group B agents population[i][j] = 2.0 # 2.0 means "B" # import pyplot and colors from matplotlib from matplotlib import pyplot, colors # using colors from matplotlib, define a color map colormap = colors.ListedColormap(["lightgrey","green","blue"]) # define figure size using pyplot pyplot.figure(figsize = (12,12)) # using pyplot add a title pyplot.title("battlefield before simulation run (green = A, blue = B)", fontsize = 24) # using pyplot add x and y labels pyplot.xlabel("x coordinates", fontsize = 20) pyplot.ylabel("y coordinates", fontsize = 20) # adjust x and y axis ticks, using pyplot pyplot.xticks(fontsize = 16) pyplot.yticks(fontsize = 16) # use .imshow() method from pyplot to visualize agent locations pyplot.imshow(X = population, cmap = colormap)

<matplotlib.image.AxesImage at 0x22495922ac8>

We can now conduct a simple simulation run which in later posts will turn into an experiment. For this we implement two attack strategies:

##### Group A has the strategy of always hitting the same agent in each round

##### Group B has a random and independent strategy for attacking enemies. This means that each agent of type B will attack a randomly selected enemy within that agent’s reach.

The simulation is now conducted under the following conditions:

##### 1) Each round is one iteration

##### 2) In each round, each agent can attack one agent within his reach

##### 3) The reach of an agent is defined at the start of the simulation and defaults to 10

##### 4) If an agent dies he will no longer be located on the battle field

##### 5) An agent dies when his life score equals or goes below zero

##### 6) Each agent has a randomly distributed attack damage, ranging from 10 to 60

##### 7) In each round all agents get to launch an attack

With these rules in place I will now iterate through 50 rounds of fighting. At the end I will print a plot of the remaining agents on the battlefield. The implementation follows below:

for counter in range(0,50): # in this case I am conducting 50 iterations # iterating through all cells on the battlefield for i in range(0,len(battlefield)): for j in range(0,len(battlefield)): #print("top tier iteration, i: "+str(i)+", j: "+str(j)) # check if there is an agent in the respective cell if battlefield[i][j] != None: # depending on the type: execute respective attack strategy if battlefield[i][j].group == "A": found_i = None found_j = None # look in neigbouring cells in same order for each iteration for k in range(i-10,i+11): for l in range(j-10,j+11): # check for negative index values; if so - break! if k < 0 or l < 0: break # check for index values above 99, if so break! if k > 99 or l > 99: break if battlefield[k][l]: if battlefield[k][l].group == "B": # then this is an enemy if found_i == None: found_i = k found_j = l # deal damage to identified enemy if found_i: battlefield[found_i][found_j].life = battlefield[found_i][found_j].life - random.randint(10,60) else: # first check if there even is an enemy in one of the surrounding cells enemy_found = False for k in range(i-10,i+11): for l in range(j-10,j+11): # check for negative index, if so break to next iteration if k < 0 or l < 0: break # check for index values above 99, if so break if k > 99 or l > 99: break if battlefield[k][l] != None: if battlefield[k][l].group == "A": enemy_found = True # select a random row and a random column found_i = None found_j = None while enemy_found and found_i == None: k = random.randint(i-10,i+10) l = random.randint(j-10,j+10) # check for negative index, if so continue to next iteration if k < 0 or l < 0: continue # check for index value > 99, if so continue if k > 99 or l > 99: continue if k != i: if battlefield[k][l]: if battlefield[k][l].group == "A": found_i = k found_j = l else: if l != j: if battlefield[k][l]: if battlefield[k][l].group == "A": found_i = k found_j = l # deal damage to identified enemy if found_i: battlefield[found_i][found_j].life = battlefield[found_i][found_j].life - random.randint(10,60) # identifying agents with life score of score or below - and removing them from the grid for i in range(0,len(battlefield)): for j in range(0,len(battlefield)): if battlefield[i][j]: if battlefield[i][j].life <= 0: battlefield[i][j] = None # producing a plot of all battlefield locations, 10 iterations after population = [[0.0 for i in range(0,100)] for i in range(0,100)] # if agent is of type A, put a 1.0, if of type B, pyt a 2.0 for i in range(1,100): for j in range(1,100): if battlefield[i][j] == None: # empty pass # leave 0.0 in population cell elif battlefield[i][j].group == "A": # group A agents population[i][j] = 1.0 # 1.0 means "A" else: # group B agents population[i][j] = 2.0 # 2.0 means "B" # import pyplot and colors from matplotlib from matplotlib import pyplot, colors # using colors from matplotlib, define a color map colormap = colors.ListedColormap(["lightgrey","green","blue"]) # define figure size using pyplot pyplot.figure(figsize = (12,12)) # using pyplot add a title pyplot.title("battlefield after 50 iterations (green = A, blue = B)", fontsize = 24) # using pyplot add x and y labels pyplot.xlabel("x coordinates", fontsize = 20) pyplot.ylabel("y coordinates", fontsize = 20) # adjust x and y axis ticks, using pyplot pyplot.xticks(fontsize = 16) pyplot.yticks(fontsize = 16) # use .imshow() method from pyplot to visualize agent locations pyplot.imshow(X = population, cmap = colormap)

<matplotlib.image.AxesImage at 0x22495be1848>

In some following posts I will clean the code and pack its functionality into re-usable functions. I will then conduct a more comprehensive simulation study in which various parameters are varied to investigate their impact on battle outcome.

In this example I used Python lists as my agent containers of choice. However, similar models can be constructed using e.g. Python arrays or NumPy arrays.

## Leave a Reply