# File vwmanager.py
#
# Author: Gerd Doeben-Henisch
# First: Aug 7,2019
# Last: Aug 19, 2019
#
# Some functions to support the creation and the management od 2D-viertual worlds with the layout of a 2D-grid
##############################
# IMPORTS
import random as rnd # Enabling random numbers
import copy as cp # Enabling true copies of objects
# Print a matrix line by line
def printMX(obj):
for i in range(len(obj)): # Print matrix line by line
print(obj[i],'\n') # '\n' commands a new line
def printMXs(obj,say):
if say == 1:
for i in range(len(obj)): # Print matrix line by line
print(obj[i],'\n') # '\n' commands a new line
else:
pass
# Generate a matrix as a list with every element a list; all length = n
def nmlist(n):
mx = [['_' for y in range(n)] for x in range(n)] # Generate 2D matrix from ground
printMX(mx)
return mx
# Number of objects based on percentage of objects
def numberObj(p,n):
maxObj=n*n
numberObj=int(p*(maxObj/100)) # Restricting to integers as result
#print('Number of objects :\n',numberObj)
return numberObj
# Insert n-many objects ['O'] at selected position in the matrix
# Generate randomly n-many coordinates
# Attach at these positions by insertion the objects
# Attention !!! The sum of all objects should be not greater than 100%
# Otherwise the generation runs into a deadlock :-)
def placeObj(no,n,mx,obj):
for i in range(no):
y=rnd.randrange(n)
x=rnd.randrange(n)
mx[y][x]=obj
print('New Matrix :\n')
printMX(mx)
return mx
def placeObjs(no,n,mx,obj,say):
for i in range(no):
y=rnd.randrange(n)
x=rnd.randrange(n)
mx[y][x]=obj
if say == 1:
print('New Matrix :\n')
printMX(mx)
return mx
# Generate and show list of actual objects with 'name' in the grid
# Get objects of type c out of the matrix mx
# Attach a copy of the general values from objL to certain objects
# Generate individual IDs for certain objects
def makeobjL(c,objL,mx,n):
ol=[]
ol=[[y,x,f] for y in range(n) for x in range(n) for f in mx[y][x] if f==c]
if c != 'O': # Obstacles do not need additional information
[ol[i].append(cp.copy(objL[c])) for i in range(len(ol))] # Food and actors attach general information from objL
# and get an individual ID
for i in range(len(ol)):
ol[i][3][0]=i
else:
pass
return ol
# Generating a random direction Dir for every actor
# Parse through the objekt list for actors olA
# Take the element with the direction Dir = olA[i][3][4]
# Generate a random number r in [0,8]
# Store this random number at Dir
# Return olA
def randDir(olA):
for i in range(len(olA)): #Cycle through all actor objects
Dir=rnd.randrange(9) # Possible directions are in [0,8]
olA[i][3][4]=Dir # Set new direction Dir
return olA
# Compute new intended positions according to wanted direction Dir
# For this make a true copy of old olA as olAA
# See below possible directions:
'''
|8|1|2|
|7|0|3|
|6|5|4|
'''
# Transform the old coordinates into new ones
def transformYX(yold,xold,Dir):
if Dir == 0:
ynew = yold
xnew = xold
elif Dir == 1:
ynew = yold-1
xnew = xold
elif Dir == 2:
ynew = yold-1
xnew = xold+1
elif Dir == 3:
ynew = yold
xnew = xold+1
elif Dir == 4:
ynew = yold+1
xnew = xold+1
elif Dir == 5:
ynew = yold+1
xnew = xold
elif Dir == 6:
ynew = yold+1
xnew = xold-1
elif Dir == 7:
ynew = yold
xnew = xold-1
elif Dir == 8:
ynew = yold-1
xnew = xold-1
else:
ynew = yold
xnew = xold
print('ERROR IN NEW POSITION!\n')
return ynew, xnew
# Transform the reverse: from direction Dir back to start
# In case of olAA (or olA) one gets the y,x values for some index i as follows:
# y = olAA[i][0]
# x = olA[Ai][1]
def transReversYX(Dir,y,x):
if Dir == 0:
yold = y
xold = x
elif Dir == 1:
yold = y+1
xold = x
elif Dir == 2:
yold = y+1
xold = x-1
elif Dir == 3:
yold = y
xold = x-1
elif Dir == 4:
yold = y-1
xold = x-1
elif Dir == 5:
yold = y-1
xold = x
elif Dir == 6:
yold = y-1
xold = x+1
elif Dir == 7:
yold = y
xold = x+1
elif Dir == 8:
yold = y+1
xold = x+1
else:
yold = y
xold = x
print('ERROR IN POSITION!\n')
return yold, xold
###########################################################
# REDUCING THE NEW POSITIONS TO ALLOWED ONES
###########################################################
# Making a working real copy of olA as olAA
# for the upcoming sequence of operations which compute the new positions
# and then subsequently check the new positions accross several criteria
# which disallow the new position.
# The general idea is to generate a 'allow list' parallel to the olAA list
# which can later be used to decide which OLD positions from olA have to be kept
# because the new move is not possible and which NEW positions from olAA should
# be realized for olA.
# In the following generation of the new positions some first filtering already
# is active: new positions (ynew, xnew) from (yold, xold) will be filtered out
# with regard to the boundaries Min <= x <= Max. The 'surviving new position'
# is the old position.
def newPos0(olA,n):
Min = 0 # Minimal index value in n x n ,matrix
Max = n-1 # Maximal index value in n x n matrix
olAA = cp.deepcopy(olA) # Make true and complete copy of olA
for i in range(len(olAA)): # Cycle through all actor objects
yold = olAA[i][0] # Get old y value
xold = olAA[i][1] # Get old x value
Dir = olAA[i][3][4] # Get new direction
print('\n OLD= y,x,Dir ', yold,xold,Dir)
p = transformYX(yold,xold,Dir)
ynew = p[0]
xnew = p[1]
if ynew < Min or ynew > Max:
ynew = yold
xnew = xold
olAA[i][3][4]=-1 # Set Dir back to zero
if xnew < Min or xnew > Max:
xnew = xold
ynew = yold
olAA[i][3][4]=-1 # Set Dir back to zero
olAA[i][0] = ynew
olAA[i][1] = xnew
print('\n NEW = y,x', ynew,xnew)
return olAA
def newPos0s(olA,n,say):
Min = 0 # Minimal index value in n x n ,matrix
Max = n-1 # Maximal index value in n x n matrix
olAA = cp.deepcopy(olA) # Make true and complete copy of olA
for i in range(len(olAA)): # Cycle through all actor objects
yold = olAA[i][0] # Get old y value
xold = olAA[i][1] # Get old x value
Dir = olAA[i][3][4] # Get new direction
if say == 1:
print('\n OLD= y,x,Dir ', yold,xold,Dir)
p = transformYX(yold,xold,Dir)
ynew = p[0]
xnew = p[1]
if ynew < Min or ynew > Max:
ynew = yold
xnew = xold
olAA[i][3][4]=-1 # Set Dir back to zero
if xnew < Min or xnew > Max:
xnew = xold
ynew = yold
olAA[i][3][4]=-1 # Set Dir back to zero
olAA[i][0] = ynew
olAA[i][1] = xnew
if say == 1:
print('\n NEW = y,x', ynew,xnew)
return olAA
# Operation:
# Make a virtual copy mxx of mx by mx0 with olO, olF and olA.
# Then check for every actor from olAA whether it hits with the planned new position vw.transReversYX(an 'O'.
# If so then append to the disallow list a '1'.
def reduceAO(mx0,olO, olF, olAA,olA):
disallowL = []
mxx = show2D(mx0, olO, olF, olA) # Reproduce old 2D grid
print('Old world with mxx \n')
printMX(mxx)
for i in range(len(olAA)): # Check olAA list
y=olAA[i][0]
x=olAA[i][1]
print('World at i ',i,' in mxx = ',mxx[y][x],'\n')
if mxx[y][x] == 'O': # if collision with obstacle
disallowL.append(i)
olAA[i][3][4]=-1 # Set Dir back to zero
print('disallowL after ',i)
printMX(disallowL)
else:
pass
return disallowL
def reduceAOs(mx0,olO, olF, olAA,olA,say):
disallowL = []
mxx = show2D(mx0, olO, olF, olA) # Reproduce old 2D grid
if say == 1:
print('Old world with mxx \n')
printMX(mxx)
for i in range(len(olAA)): # Check olAA list
y=olAA[i][0]
x=olAA[i][1]
if say == 1:
print('World at i ',i,' in mxx = ',mxx[y][x],'\n')
if mxx[y][x] == 'O': # if collision with obstacle
disallowL.append(i)
olAA[i][3][4]=-1 # Set Dir back to zero
if say == 1:
print('disallowL after ',i)
printMX(disallowL)
else:
pass
return disallowL
# Replace in olAA the disallowed positions
def updateOLA(olA,olAA,disallowL):
print('disallowL before usage in update \n')
printMX(disallowL)
print('olAA before update\n')
printMX(olAA)
for i in range(len(disallowL)):
olAA[disallowL[i]] = olA[disallowL[i]]
olAA[disallowL[i]][3][4]=-1 # Set Dir back to zero
print('Updated olAA with disallowed \n')
printMX(olAA)
return olAA
def updateOLAs(olA,olAA,disallowL,say):
if say == 1:
print('disallowL before usage in update \n')
printMX(disallowL)
print('olAA before update\n')
printMX(olAA)
for i in range(len(disallowL)):
olAA[disallowL[i]] = olA[disallowL[i]]
olAA[disallowL[i]][3][4]=-1 # Set Dir back to zero
if say == 1:
print('Updated olAA with disallowed \n')
printMX(olAA)
return olAA
# Check of similar elements in a list
# Here the list is the real copy of olA as olAA
# If a similarity between two elements e,e' will be detected then
# store the indices of these elements [i,j] in the list equalL
# The lenght of the list has to be greater than 1!
def selfL(L):
equalL=[] # Empty list of indices
print('Length of L: ',len(L))
if len(L)<2:
pass
else:
i=0
while i <= len(L)-2:
j=i+1
while j < len(L):
print('i,j =',i,j)
print(L[i][:2],L[j][:2])
if L[i][:2] == L[j][:2]:
print('Is equal!')
equalL.append([i,j])
else:
pass
j+=1
i+=1
return equalL
def selfLs(L,say):
equalL=[] # Empty list of indices
if say == 1:
print('Length of L: ',len(L))
if len(L)<2:
pass
else:
i=0
while i <= len(L)-2:
j=i+1
while j < len(L):
if say == 1:
print('i,j =',i,j)
print(L[i][:2],L[j][:2])
if L[i][:2] == L[j][:2]:
if say == 1:
print('Is equal!')
equalL.append([i,j])
else:
pass
j+=1
i+=1
return equalL
# Restore the old positions in olAA by olA and equalL
def restoreAA(equalL, olA, olAA):
for i in range(len(equalL)):
r=equalL[i][0]
s=equalL[i][1]
olAA[r][:2] = olA[r][:2]
olAA[r][3][4]=-1 # Set Dir back to zero
olAA[s][:2] = olA[s][:2]
olAA[s][3][4]=-1 # Set Dir back to zero
print('olAA after restoration of similar elements')
printMX(olAA)
return olAA
def restoreAAs(equalL, olA, olAA,say):
for i in range(len(equalL)):
r=equalL[i][0]
s=equalL[i][1]
olAA[r][:2] = olA[r][:2]
olAA[r][3][4]=-1 # Set Dir back to zero
olAA[s][:2] = olA[s][:2]
olAA[s][3][4]=-1 # Set Dir back to zero
if say == 1:
print('olAA after restoration of similar elements')
printMX(olAA)
return olAA
# Check for accessibility of cells generated by a direction D={2,4,6,8}
# All actors pointing to new positions which are free of obstacles 'O'
# and which are depending from the directions D={2,4,6,8} are only reachable if the two
# neighbor cells generated by the directions D-1 and D+1 are free of obstacles too. Therefore
# one has to check whether this is the case.
# As previously a disallowL list will be generated and then a reduceAO() and updateOLA()
# will be applied.
def checkCornerYX(olAA,mx):
disallowL = []
for i in range(len(olAA)):
D = olAA[i][3][4]
if D == 2:
# Compute back to start cell
y=olAA[i][0]
x=olAA[i][1]
posold = transReversYX(y,x,D)
yold = posold[0]
xold = posold[1]
# Compute forward with D-1
posnew1 = transformYX(yold,xold,D-1)
ynew1 = posnew1[0]
xnew1 = posnew1[1]
# Compute forward with D+1
Dp = D+1
if Dp>8:
Dp=1
posnew2 = transformYX(yold,xold,Dp)
ynew2 = posnew2[0]
xnew2 = posnew2[1]
# Only one append!
if mx[ynew1][xnew1] != 'O':
disallowL.append(i)
elif mx[ynew2][xnew2] != 'O':
disallowL.append(i)
else:
pass
return disallowL
# Check for eating
# If actor position matches a food object position then the actor will eat
# Format of food object: [y,x, 'F', [ID, E, +e]]
# Eating implies two effects (see: ('A':[ID,E,-e,+e,Dir])
# (i) increase energy level E of actor by +e
# (ii) decrease amount of food object by +e of olA
def eating(olA, mx, olF):
for i in range(len(olA)):
posy = olA[i][0]
posx = olA[i][1]
if mx[posy][posx] == 'F':
for j in range(len(olF)):
if (olF[j][:2] == [posy,posx]) and (olF[j][3][1] > olA[i][3][3]):
olF[j][3][1]-=olA[i][3][3]
olA[i][3][1]+= olA[i][3][3]
else:
pass
return olA,olF
# UPDATING all FOOD objects
# Take the list of all food objects olF
# Check whether the energy level (index 1) is below Maximum.
# If YES add some amount (Index 2).
# If not do nothing
def foodUpdate(olF,objL):
for i in range(len(olF)): #Cycle through all food objects
if olF[i][3][1]<objL['F'][1]: #Compare with standard maximum
olF[i][3][1]+=objL['F'][2] # If lower then increment by standard
return olF
# UPDATING all ACTOR objects
# Take the list of all actor objects olA
# REDUCE the energy level according to the standard
# CHECK whether the energy level (objL index 1) is below 0.
# If YES add REMOVE AVATAR from grid.
# objL={'F':[0,1000, 20], 'A':[0,1000,5,100]}
def actorUpdate(olA,objL,mx):
for i in range(len(olA)): #Cycle through all actor objects
olA[i][3][1]-=objL['A'][2] #Decrement the energy level by the standard
print('olA in Update : \n',olA)
# Check whether an element is below 1 with its energy
iL=[y for y in range(len(olA)) if olA[y][3][1]<1] # Generate a list of all these actors with no energy
print('iL before if\n',iL)
if iL != []: # If the list is not empty:
print('IL inside if: ',iL)
#Collect coordinates from actors in Grid
yxL=[[olA[y][x]] for y in range(len(olA)) for x in range(2) if olA[y][3][1]<1]
print('yxL inside if: ',yxL)
# Concentrate lists as (y,x) pairs
yxc=[[yxL[i][0], yxL[i+1][0]] for i in range(0,len(yxL),2)]
# Replace selected actors in the Grid by '_'
if yxc != []:
print('xyc inside :\n',yxc)
for i in range(len(yxc)):
y=yxc[i][0]
x=yxc[i][1]
mx[y][x]='_'
# Delete actor from olA list
print('iL before pop : \n',iL)
#Because pop() decreases the olA list, one has to start indexing from the 'right end' because then the decrement of the list
# keeps the other remaining indices valid!
for i in range(len(iL)-1,-1,-1):
print('pop : ', i)
olA.pop(iL[i])
else:
print('iL is empty\n')
return olA
def actorUpdates(olA,objL,mx,say):
for i in range(len(olA)): #Cycle through all actor objects
olA[i][3][1]-=objL['A'][2] #Decrement the energy level by the standard
if say == 1:
print('olA in Update : \n',olA)
# Check whether an element is below 1 with its energy
iL=[y for y in range(len(olA)) if olA[y][3][1]<1] # Generate a list of all these actors with no energy
if say == 1:
print('iL before if\n',iL)
if iL != []: # If the list is not empty:
if say == 1:
print('IL inside if: ',iL)
#Collect coordinates from actors in Grid
yxL=[[olA[y][x]] for y in range(len(olA)) for x in range(2) if olA[y][3][1]<1]
if say == 1:
print('yxL inside if: ',yxL)
# Concentrate lists as (y,x) pairs
yxc=[[yxL[i][0], yxL[i+1][0]] for i in range(0,len(yxL),2)]
# Replace selected actors in the Grid by '_'
if yxc != []:
if say == 1:
print('xyc inside :\n',yxc)
for i in range(len(yxc)):
y=yxc[i][0]
x=yxc[i][1]
mx[y][x]='_'
# Delete actor from olA list
if say == 1:
print('iL before pop : \n',iL)
#Because pop() decreases the olA list, one has to start indexing from the 'right end' because then the decrement of the list
# keeps the other remaining indices valid!
for i in range(len(iL)-1,-1,-1):
if say == 1:
print('pop : ', i)
olA.pop(iL[i])
else:
if say == 1:
print('iL is empty\n')
return olA
# To visualize the actual 2D-grid with the data after some changes a
# new show2D() function will be defined.
# This function takes an empty grid mx0 as starting point and then
# writes all new data structures into it.
def show2D(mx0, olO, olF, olA):
mx = cp.deepcopy(mx0)
for i in range(len(olO)):
y=olO[i][0]
x=olO[i][1]
mx[y][x]='O'
for i in range(len(olF)):
y=olF[i][0]
x=olF[i][1]
mx[y][x]='F'
for i in range(len(olA)):
y=olA[i][0]
x=olA[i][1]
mx[y][x]='A'
return mx