def MakeMaze(self, width, height): self.width = width self.height = height self.canvasWidth = width * self.SCALE_FACTOR self.canvasHeight = height * self.SCALE_FACTOR self.disjointSets = DisjointSets(width * height) self.mazeCells = [[MazeCell(x, y) for y in range(height)] for x in range(width)] Xs = list(range(self.width)) Ys = list(range(self.height)) # cartesian product X x Y randomCoords = list(itertools.product(Xs, Ys)) randomCoords.extend(randomCoords) random.shuffle(randomCoords) for (row, column) in randomCoords: mazeCell = self.mazeCells[row][column] wallRemoveDirection = random.sample( [Direction.RIGHT, Direction.DOWN], 1)[0] if (mazeCell.visitedCount == 1): wallRemoveDirection = Direction.RIGHT if mazeCell.rightWallExists else Direction.DOWN a = self._findSetIndex(row, column) b = self._findSetIndex(row, column, wallRemoveDirection) if (self._checkBoundary(row, column, wallRemoveDirection) and self.disjointSets.SetUnion(a, b)): self._setWall(mazeCell, wallRemoveDirection, False) mazeCell.visitedCount += 1
def makemaze(w,h,tw): random.seed() size = w*h ds = DisjointSets(size) walls = ([(a,a+1) for a in [x for x in range(size) if (x+1)%w != 0]] + [(a,a+w) for a in [x for x in range(size-w)]]) while not _done(ds): a,b = walls[random.randint(0, len(walls)-1)] x,y = ds.find(a), ds.find(b) if not x == y: ds.union(x,y) walls.remove((a,b)) tiles = ([Tile('wall',_newp(i,tw),_newp(j,tw),tw) for i in range(2*w+1) for j in range(2*h+1) if (i == 0 or j == 0 or i == w*2 or j == h*2 or (i%2==0 and j%2==0)) and not (j == 2*h-1 and i == 2*w)] + [Tile('floor',_newp(i,tw),_newp(j,tw),tw) for i in range(1,2*w+1) for j in range(1,2*h+1) if (i%2==1 and j%2==1) or (j == 2*h-1 and i == 2*w)] + [Tile('wall' if i%2==0 and list(set([(a,a+1) for a in range(i/2-1,size,w)]) & set([(b,b+1) for b in range(j/2*w,(j/2+1)*w-1)]))[0] in walls or i%2==1 and list(set([(a,a+w) for a in range(i/2,size,w)]) & set([(b,b+w) for b in range((j/2-1)*w,j/2*w)]))[0] in walls else 'floor' ,_newp(i,tw),_newp(j,tw),tw) for i in range(1,2*w) for j in range(1,2*h) if i%2 != j%2]) return tiles
def test_SetUnion(self): numElements = 5 test = DisjointSets(numElements) self.assertEqual(test.SetUnion(0, 2), True) self.assertEqual(test.uptrees, [2, -1, -2, -1, -1]) self.assertEqual(test.SetUnion(0, 2), False) self.assertEqual(test.uptrees, [2, -1, -2, -1, -1]) self.assertEqual(test.SetUnion(1, 2), True) self.assertEqual(test.uptrees, [2, 2, -3, -1, -1]) self.assertEqual(test.SetUnion(4, 4), False) self.assertEqual(test.uptrees, [2, 2, -3, -1, -1]) self.assertEqual(test.SetUnion(5, 5), False) self.assertEqual(test.uptrees, [2, 2, -3, -1, -1]) self.assertEqual(test.SetUnion(3, 4), True) self.assertEqual(test.uptrees, [2, 2, -3, 4, -2]) self.assertEqual(test.SetUnion(0, 3), True) self.assertEqual(test.uptrees, [2, 2, -5, 4, 2]) self.assertEqual(test.SetUnion(-1, -2), False) self.assertEqual(test.uptrees, [2, 2, -5, 4, 2])
def test_FindRoot(self): numElements = 5 test = DisjointSets(numElements) test.uptrees = [2, 2, -4, -1, 2] self.assertEqual(test.FindRoot(2), 2) self.assertEqual(test.FindRoot(0), 2) self.assertEqual(test.FindRoot(-1), -1)
def mst(n, edges): weight_sum, m, tree = 0, n - 1, [] edges.sort(key=lambda x: -x[2]) sets = DS() vertices = [sets.make_set(i) for i in range(n)] while m > 0: edge = edges.pop() if not sets.union(vertices[edge[0]], vertices[edge[1]]): continue tree.append(edge) weight_sum += edge[2] m -= 1 return tree, weight_sum
def __init__(self, meta=None, fields=tuple()): if meta is None: meta = {} self.meta = meta self.fields = list(fields) self.instances = WeakCollection() # Each set of linked subfields means that those subfields are linked and share the same instance self.links = DisjointSets()
def nbr_clustering(self, I, r): ''' Epsilon ball clustering Parameters: ---------- I: int, array The indices of elements to be clustered r: float, scale The distance threshold ''' ds = DisjointSets(I) n_data = len(I) for i in range(n_data): for j in range(i + 1, n_data): if self.distM[I[i], I[j]] <= r: ds.merge_byelm(I[i], I[j]) return ds
class Class(object): def __init__(self, meta=None, fields=tuple()): if meta is None: meta = {} self.meta = meta self.fields = list(fields) self.instances = WeakCollection() # Each set of linked subfields means that those subfields are linked and share the same instance self.links = DisjointSets() def __repr__(self): return '<%s, meta=%r, fields=%r>' % (self.__class__.__name__, self.meta, len(self.fields)) def add_field(self, field): self.fields.append(field) for instance in self.instances: instance.new_field(field) def create_instance(self, **kw): instance = Instance(self, **kw) self.instances.add(instance) return instance def union(self, src_subfield_hierarchy, dst_subfield_hierarchy): src_subfield_hierarchy = tuple(src_subfield_hierarchy) dst_subfield_hierarchy = tuple(dst_subfield_hierarchy) self.links.union(src_subfield_hierarchy, dst_subfield_hierarchy) assert dst_subfield_hierarchy in self.links.set_of(src_subfield_hierarchy) assert src_subfield_hierarchy in self.links.set_of(dst_subfield_hierarchy) for instance in self.instances: # Find the subfield's_instance for this instance (extract the instance from the deepest level) src_subfield_instance = instance.get_subfield_instance(src_subfield_hierarchy, False) # Tell the instance that the subfield has changed, it will update all internally linked fields to point # to the new instance. instance.subfield_linked(src_subfield_hierarchy, src_subfield_instance) def split(self, subfield_hierarchy): self.links.split(subfield_hierarchy) for instance in self.instances: instance.subfield_unlinked(subfield_hierarchy)
def kruskal(graph): """Find the minimum spanning tree of a graph.""" msf = set() forest = DisjointSets() for v in graph.keys(): forest.makeset(v) edges = [] for u, adjlist in graph.items(): for (v, weight) in adjlist.items(): edges.append((u, v, weight)) edges.sort(key=lambda edge: edge[2]) for u, v, w in edges: if forest.find(u) != forest.find(v): msf.add((u, v, w)) forest.union(u, v) return msf
def kruskal(G): aristas = G.aristas() aristas.sort() D = DisjointSets(G.num_verts) return aristas_sin_ciclos(aristas, D)
class Maze(object): SCALE_FACTOR = 10 def __init__(self, width=0, height=0): self.width = 0 self.height = 0 self.canvasWidth = 0 self.canvasHeight = 0 self.mazeCells = [] self.MakeMaze(width, height) def MakeMaze(self, width, height): self.width = width self.height = height self.canvasWidth = width * self.SCALE_FACTOR self.canvasHeight = height * self.SCALE_FACTOR self.disjointSets = DisjointSets(width * height) self.mazeCells = [[MazeCell(x, y) for y in range(height)] for x in range(width)] Xs = list(range(self.width)) Ys = list(range(self.height)) # cartesian product X x Y randomCoords = list(itertools.product(Xs, Ys)) randomCoords.extend(randomCoords) random.shuffle(randomCoords) for (row, column) in randomCoords: mazeCell = self.mazeCells[row][column] wallRemoveDirection = random.sample( [Direction.RIGHT, Direction.DOWN], 1)[0] if (mazeCell.visitedCount == 1): wallRemoveDirection = Direction.RIGHT if mazeCell.rightWallExists else Direction.DOWN a = self._findSetIndex(row, column) b = self._findSetIndex(row, column, wallRemoveDirection) if (self._checkBoundary(row, column, wallRemoveDirection) and self.disjointSets.SetUnion(a, b)): self._setWall(mazeCell, wallRemoveDirection, False) mazeCell.visitedCount += 1 def _resetMazeCells(self): for row in range(self.height): for col in range(self.width): self.mazeCells[row][col].marked = False def _findSetIndex(self, row, column, direction=Direction.NONE): if direction is Direction.NONE: return (row * self.width) + column return (row * self.width) + column + 1 if direction is Direction.RIGHT else ( (row + 1) * self.width) + column def _setWall(self, mazeCell, direction, exists): if (direction is Direction.RIGHT): mazeCell.rightWallExists = exists elif (direction is Direction.DOWN): mazeCell.downWallExists = exists def DrawSolution(self, pixels, solution): currentRow = self.SCALE_FACTOR // 2 currentCol = self.SCALE_FACTOR // 2 for step in solution.path: cv2.imshow('image', pixels) if (step is Direction.DOWN): self._colorWall(pixels, Orientation.VERTICAL, currentRow, currentRow + self.SCALE_FACTOR, currentCol, Color.RED) currentRow += self.SCALE_FACTOR elif (step is Direction.RIGHT): self._colorWall(pixels, Orientation.HORIZONTAL, currentCol, currentCol + self.SCALE_FACTOR, currentRow, Color.RED) currentCol += self.SCALE_FACTOR elif (step is Direction.LEFT): self._colorWall(pixels, Orientation.HORIZONTAL, currentCol - self.SCALE_FACTOR, currentCol, currentRow, Color.RED) currentCol -= self.SCALE_FACTOR elif (step is Direction.UP): self._colorWall(pixels, Orientation.VERTICAL, currentRow - self.SCALE_FACTOR, currentRow, currentCol, Color.RED) currentRow -= self.SCALE_FACTOR cv2.waitKey(0) currentRow += self.SCALE_FACTOR // 2 currentCol -= self.SCALE_FACTOR // 2 # Drawing exit self._colorWall(pixels, Orientation.HORIZONTAL, currentCol, currentCol + self.SCALE_FACTOR, currentRow, Color.WHITE) def _blackenCells(self, pixels): for row in range(self.height): for column in range(self.width): mazeCell = self.mazeCells[row][column] if (mazeCell.rightWallExists): rowStart = (row * self.SCALE_FACTOR) columnFixed = (column * self.SCALE_FACTOR ) + MazeCell.RIGHT_WALL_OFFSET_PX self._colorWall(pixels, Orientation.VERTICAL, rowStart, rowStart + self.SCALE_FACTOR, columnFixed, Color.BLACK) if (mazeCell.downWallExists): rowFixed = ( row * self.SCALE_FACTOR) + MazeCell.DOWN_WALL_OFFSET_PX columnStart = (column * self.SCALE_FACTOR) self._colorWall(pixels, Orientation.HORIZONTAL, columnStart, columnStart + self.SCALE_FACTOR, rowFixed, Color.BLACK) def _blackenTop(self, pixels): DOOR_OFFSET = 10 self._colorWall(pixels, Orientation.HORIZONTAL, DOOR_OFFSET, self.canvasWidth, 0, Color.BLACK) def _blackenLeft(self, pixels): self._colorWall(pixels, Orientation.VERTICAL, 0, self.canvasHeight, 0, Color.BLACK) def _colorWall(self, pixels, orientation, start, end, fixedDimension, color): if (orientation is Orientation.VERTICAL): for i in range(start, end): pixels[fixedDimension, i] = tuple(color) elif (orientation is Orientation.HORIZONTAL): for i in range(start, end): pixels[i, fixedDimension] = tuple(color) def _canTravel(self, row, column, direction): return self._checkBoundary(row, column, direction) and \ not self._hasWall(row, column, direction) and \ not self._isVisited(row, column, direction) def _isVisited(self, row, column, direction): if (direction is Direction.DOWN): return (self.mazeCells[row + 1][column].marked) elif (direction is Direction.RIGHT): return (self.mazeCells[row][column + 1].marked) elif (direction is Direction.LEFT): return (self.mazeCells[row][column - 1].marked) elif (direction is Direction.UP): return (self.mazeCells[row - 1][column].marked) def _checkBoundary(self, row, column, direction): MIN_HEIGHT, MIN_WIDTH = 0, 0 MAX_HEIGHT = self.height - 1 MAX_WIDTH = self.width - 1 if (direction is Direction.DOWN): return (row + 1 <= MAX_HEIGHT) elif (direction is Direction.RIGHT): return (column + 1 <= MAX_WIDTH) elif (direction is Direction.LEFT): return (column - 1 >= MIN_WIDTH) elif (direction is Direction.UP): return (row - 1 >= MIN_HEIGHT) def _hasWall(self, row, column, direction): if (direction is Direction.RIGHT): return self.mazeCells[row][column].rightWallExists elif (direction is Direction.DOWN): return self.mazeCells[row][column].downWallExists elif (direction is Direction.LEFT): return self.mazeCells[row][column - 1].rightWallExists elif (direction is Direction.UP): return self.mazeCells[row - 1][column].downWallExists def DrawMaze_CV(self, mazeSolution): imageWidth = (self.canvasWidth) + 1 imageHeight = (self.canvasHeight) + 1 RGB_DIMENSION = 3 # 2D array of 1D arays of length 3 for pixel representation pixels = np.repeat(255,imageWidth*imageHeight*RGB_DIMENSION).astype('u1') \ .reshape((imageWidth,imageHeight,RGB_DIMENSION)) self._blackenTop(pixels) self._blackenLeft(pixels) self._blackenCells(pixels) self.DrawSolution(pixels, mazeSolution)
def test_AddElements(self): numElements = 5 test = DisjointSets(numElements) self.assertEqual(test.uptrees, list(np.repeat(-1, numElements)))