# 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