# The idea of this project is that there will be an n by n matrix representing # a grid. Then there will be g genders and k people of each gender # placed more or less randomly around the grid. # A space with a 0 (or a dot in the output representation) is empty. # A space with an integer k (where 0 < k <= g) represents a person of gender k. # In a parallel step, a client process sends a set of moves each consisting # of a quadruple (i1, j1, i2, j2) where (i1, j1) is the original grid position # of a person and i2, j2 is the place where that person moves in the step. # The rules about the moves are that a person may move only once in a step. # The move must be one position vertically or horizontally but not both. # No two people may end up in the same spot. # If any of these rules are violated, the team loses. # The game is complete when there are k disjoint line segments each # containing one person of every gender though the order of genders # does not matter. # Functions in this file: # Function genmat generates the initial matrix # Function printmat prints out the matrix. # Function onestep takes a matrix and a set of moves and either determines that # they are illegal or changes the matrix appropriately. # Function alldone determines whether there are k line segments with all # g genders. There could be more if they are lined up properly though this # is hard to do if there are three or more genders. # Function rightstep creates the moves to cause # the non-zeroes in the matrix to move one position to # the right (under certain conditions). It should go in the client # in the code we give to the students as a standin function for what they # should change. # In the competition, all teams will get the same initial matrix # and each team will communicate moves using zeromq until that team make an # illegal move (in which case they lose) or that team completes. import random import copy # generate a square matrix of size n # having g kinds of genders # and k of each gender # We want k*g << n*n # In the output, 0 represents space and the genders are number 1 through g # inclusive def genmat(n,g,k): i = 0 mat = [] for i in range(n): x = [0 for j in range(n)] mat.append(x) tot = k * g i = 0 gender = 1 while (i < tot): mypair = findpair(mat) mat[mypair[0]][mypair[1]] = gender if (gender == g): gender = 1 else: gender+= 1 i+=1 return mat # Randomly choose a random place that is still 0 def findpair(mat): while True: i = random.randint(0,len(mat)-1) j = random.randint(0,len(mat)-1) if (mat[i][j] == 0): return([i,j]) # Output a matrix as a set of strings def printmat(mat): for line in mat: s = "" for num in line: if num == 0: s+="." else: s+=str(num) print(s) # mat is the current matrix # moves is a set of moves. # Each move is a quadruple that moves a non-zero to # a neighbor. If a move doesn't go to a neighbor or # if two moves end up in the same square, # that will be an automatic loss. def onestep(mat, moves): outmat = copy.deepcopy(mat) destcoords = [] for move in moves: totdist = abs(move[0] - move[2]) + abs(move[1]-move[3]) if totdist == 1: destcoords.append(str(move[2]) + "_" + str(move[3])) outmat[move[2]][move[3]] = mat[move[0]][move[1]] if (str(move[0]) + "_" + str(move[1])) not in destcoords: outmat[move[0]][move[1]] = 0 else: print("Bad move from [" + str(move[0]) + "," + str(move[1]) + "] to [" + str(move[2]) + "," + str(move[3]) + "]") return([False, []]) seen = set() for mystring in destcoords: if mystring not in seen: seen.add(mystring) else: print("This destination location is a duplicate: " + mystring) return([False, []]) return([True, outmat]) # See whether a matrix has k line segments of g genders, # either vertical or horizontal. # Return True if successful and False otherwise. def alldone(mat,g,k): segmentcount = 0 for line in mat: genders_collected =set() for n in line: if n > 0: genders_collected.add(n) if len(genders_collected) == g: segmentcount+=1 genders_collected =set() else: # reset to empty genders_collected =set() numcols = len(mat) for i in range(numcols): line = [val[i] for val in mat] genders_collected =set() for n in line: if n > 0: genders_collected.add(n) if len(genders_collected) == g: segmentcount+=1 genders_collected =set() else: # reset to empty genders_collected =set() numcols = len(mat) print("segmentcount is ", str(segmentcount)) return(segmentcount >= k) # rightstep just moves elements right unless there is some danger # of pushing off the right side. # Outputs a set of quadruples representing starting and ending # positions # THIS IS A STAND-IN FUNCTION FOR WHAT THE STUDENTS WILL DO def rightstep(mat): moves = [] for i in range(len(mat) ): for j in range(len(mat[0]) - 1): # if (mat[i][j] > 0) and (mat[i][j+1] == 0): if (mat[i][j] > 0) and (mat[i][len(mat[0]) - 1] == 0): moves.append([i,j,i,j+1]) return(moves) # DATA n = 8 # n by n matrix g = 3 # number of genders k = 3 # number of instances of each gender # SAMPLE SINGLE PROCESS RUN matout = genmat(n,g,k) printmat(matout) alldone(matout,g,k) mymoves = rightstep(matout) print("mymoves = ", mymoves) pair = onestep(matout, mymoves) if pair[0] == True: matout = copy.deepcopy(pair[1]) printmat(matout) alldone(matout,g,k)