def makeWall(level, box, options): # make walls boxSize = utilityFunctions.getBoxSize(box) minimumWidth = min(boxSize[0], boxSize[2]) minimumWidth = max(minimumWidth, 6) height = random.randint(5, minimumWidth) for x in range(box.minx, box.maxx): utilityFunctions.setBlockToGround(level, (options["Wall Material"].ID, 0), x, box.miny + height, box.minz, box.miny) utilityFunctions.setBlockToGround(level, (options["Wall Material"].ID, 0), x, box.miny + height, box.maxz - 1, box.miny) for z in range(box.minz, box.maxz): utilityFunctions.setBlockToGround(level, (options["Wall Material"].ID, 0), box.maxx - 1, box.miny + height, z, box.miny) utilityFunctions.setBlockToGround(level, (options["Wall Material"].ID, 0), box.minx, box.miny + height, z, box.miny) return height
def binaryPartition(box): partitions = [] # create a queue which holds the next areas to be partitioned queue = [] queue.append(box) # for as long as the queue still has boxes to partition... count = 0 while len(queue) > 0: count += 1 splitMe = queue.pop(0) (width, height, depth) = utilityFunctions.getBoxSize(splitMe) # print "Current partition width,depth",width,depth centre = 0 # this bool lets me know which dimension I will be splitting on. It matters when we create the new outer bound size isWidth = False # find the larger dimension and divide in half # if the larger dimension is < 10, then block this from being partitioned minSize = 12 if width > depth: # roll a random die, 1% change we stop anyways chance = random.randint(100) if depth < minSize or chance == 1: partitions.append(splitMe) continue isWidth = True centre = width / 2 else: chance = random.randint(10) if width < minSize or chance == 1: partitions.append(splitMe) continue centre = depth / 2 # a random modifier for binary splitting which is somewhere between 0 and 1/16 the total box side length randomPartition = random.randint(0, (centre / 8) + 1) # creating the new bound newBound = centre + randomPartition #creating the outer edge bounds outsideNewBounds = 0 if isWidth: outsideNewBound = width - newBound - 1 else: outsideNewBound = depth - newBound - 1 # creating the bounding boxes # NOTE: BoundingBoxes are objects contained within pymclevel and can be instantiated as follows # BoundingBox((x,y,z), (sizex, sizey, sizez)) # in this instance, you specifiy which corner to start, and then the size of the box dimensions # this is an if statement to separate out binary partitions by dimension (x and z) if isWidth: queue.append(BoundingBox((splitMe.minx, splitMe.miny, splitMe.minz), (newBound-1, 256, depth))) queue.append(BoundingBox((splitMe.minx + newBound + 1, splitMe.miny, splitMe.minz), (outsideNewBound - 1, 256, depth))) else: queue.append(BoundingBox((splitMe.minx, splitMe.miny, splitMe.minz), (width, 256, newBound - 1))) queue.append(BoundingBox((splitMe.minx, splitMe.miny, splitMe.minz + newBound + 1), (width, 256, outsideNewBound - 1))) return partitions
def generateWalls(level, floor, buildingHeightInfo, options): print "Generating walls" # actual automata is going to be simulated in a matrix (it's much faster than rendering it in minecraft) # first we should define the matrix properties (i.e. width and height) (width, boxheight, depth) = utilityFunctions.getBoxSize(floor) height = buildingHeightInfo[0] print "X walls" for k in range(2): # we have our matrix for CA, now lets do CA matrix = [[0 for x in range(width)] for y in range(height)] matrixnew = randomlyAssign(matrix, width, height) # do 3 generations for gen in range(0,2): # print "Generation ", gen matrixnew = cellularAutomataGeneration(matrixnew, width, height) #after generation is over, place the walls according to the wall matrix, starting at the floor for y in range(height): for x in range(1,width): if k==1: # print "boom 1" if matrixnew[y][x] == 1: utilityFunctions.setBlock(level, (options["Material"].ID, 0), floor.minx+x, buildingHeightInfo[2] + y, floor.minz) else: utilityFunctions.setBlock(level, (20, 0), floor.minx+x, buildingHeightInfo[2] + y, floor.minz) else: # print "boom 2" if matrixnew[y][x] == 1: utilityFunctions.setBlock(level, (options["Material"].ID, 0), floor.minx+x, buildingHeightInfo[2] + y, floor.maxz) else: utilityFunctions.setBlock(level, (20, 0), floor.minx+x, buildingHeightInfo[2] + y, floor.maxz) print "Z Walls" for k in range(2): # we have our matrix for CA, now lets do CA matrix = [[0 for x in range(depth)] for y in range(height)] matrixnew = randomlyAssign(matrix, depth, height) # do 25 generations for gen in range(0,25): print "Generation ", gen matrixnew = cellularAutomataGeneration(matrixnew, depth, height) #after generation is over, place the walls according to the wall matrix, starting at the floor for y in range(height): for z in range(1,depth): if k==1: # print "boom 3" if matrixnew[y][z] == 1: utilityFunctions.setBlock(level, (options["Material"].ID, 0), floor.minx, buildingHeightInfo[2] + y, floor.minz+z) else: utilityFunctions.setBlock(level, (20, 0), floor.minx, buildingHeightInfo[2] + y, floor.minz+z) else: # print "boom 4" if matrixnew[y][z] == 1: utilityFunctions.setBlock(level, (options["Material"].ID, 0), floor.maxx, buildingHeightInfo[2] + y, floor.minz+z) else: utilityFunctions.setBlock(level, (20, 0), floor.maxx, buildingHeightInfo[2] + y, floor.minz+z)
def buildFence(level, box, options, buildFenceHightRange=1): boxSize = utilityFunctions.getBoxSize(box) if min(boxSize[0],boxSize[1]) < 2: return box,box,box,box fenceLeft = CutBar(box, 1,1,0,0,buildFenceHightRange).left fenceRight = CutBar(box, 1,1,0,0,buildFenceHightRange).right fenceFront = CutBar(box, 0,0,1,1,buildFenceHightRange).front fenceBack = CutBar(box, 0,0,1,1,buildFenceHightRange).back utilityFunctions.fillLayerEmpty(level,fenceLeft,0,(85,0)) utilityFunctions.fillLayerEmpty(level,fenceRight,0,(85,0)) utilityFunctions.fillLayerEmpty(level,fenceFront,0,(85,0)) utilityFunctions.fillLayerEmpty(level,fenceBack,0,(85,0)) return fenceLeft, fenceRight,fenceFront, fenceBack
def makePyramid(level, box, options, floors): [cx,cy,cz]=[(box.minx+box.maxx)/2, (box.miny+box.maxy)/2, (box.minz+box.maxz)/2] boxSize = utilityFunctions.getBoxSize(box) minWidth = min(boxSize[0], boxSize[2]) step = 2 count=0 for floor in range(floors-1): subBox = BoundingBox((box.minx+floor,floor+box.miny,box.minz+floor),(boxSize[0]-step*floor, 1, boxSize[2]-step*floor)) if subBox.width>1 and subBox.length>1: utilityFunctions.setSquareFrame(level,(options["Wall"].ID,0), subBox.minx, subBox.miny, subBox.minz, subBox.length,subBox.width) count += 1 else: break subBox = BoundingBox((box.minx+count,count+box.miny,box.minz+count),(boxSize[0]-step*count, 1, boxSize[2]-step*count)) print subBox makeFloor(level, subBox, options)
def __init__(self, box, recessLeft, recessRight, recessFront, recessBack, height=1, offSetY=0): boxSize = utilityFunctions.getBoxSize(box) middle = BoundingBox((box.minx + recessLeft, box.miny + offSetY, box.minz + recessFront), (boxSize[0] - recessLeft - recessRight, height, boxSize[2] - recessFront - recessBack)) leftBar = BoundingBox( (box.minx, box.miny + offSetY, box.minz + recessFront), (recessLeft, height, boxSize[2] - recessFront)) rightBar = BoundingBox( (box.maxx - recessRight, box.miny + offSetY, box.minz), (recessRight, height, boxSize[2] - recessBack)) backBar = BoundingBox( (box.minx + recessLeft, box.miny + offSetY, box.maxz - recessBack), (boxSize[0] - recessLeft, height, recessBack)) frontBar = BoundingBox((box.minx, box.miny + offSetY, box.minz), (boxSize[0] - recessRight, height, recessFront)) cornorLF = BoundingBox((box.minx, box.miny + offSetY, box.minz), (recessLeft, height, recessFront)) cornorLB = BoundingBox( (box.minx, box.miny + offSetY, box.maxz - recessBack), (recessLeft, height, recessBack)) cornorRF = BoundingBox( (box.maxx - recessRight, box.miny + offSetY, box.minz), (recessRight, height, recessFront)) cornorRB = BoundingBox((middle.maxx, box.miny + offSetY, middle.maxz), (recessRight, height, recessBack)) self.left = leftBar self.right = rightBar self.front = frontBar self.back = backBar self.cornorLF = cornorLF self.cornorLB = cornorLB self.cornorRF = cornorRF self.cornorRB = cornorRB self.middle = middle
def translate_floor(self): # translates the floor into minecraft blocks. Doors get two conditions, one for the door itself, and one for the wall above it for y in range(1, utilityFunctions.getBoxSize(self.box)[1]): for x in range(0, self.floor.shape[0]): for z in range(0, self.floor.shape[1]): if self.floor[x, z] == 0 or self.floor[x, z] == -1: utilityFunctions.setBlock( self.level, (self.options["Wall_Material"].ID, 0), self.box.minx + x, self.box.miny + y, self.box.minz + z) elif self.floor[x, z] == -2 and y < 3: # this is a door, figure out which direction it goes self.translate_door((x, z), y) elif self.floor[x, z] == -2 and y >= 3: utilityFunctions.setBlock( self.level, (self.options["Wall_Material"].ID, 0), self.box.minx + x, self.box.miny + y, self.box.minz + z)
def makeFloorPlan(level, box): #we have to first figure out where in the box this is going to be #find the box dimensions (width, height, depth) = utilityFunctions.getBoxSize(box) #get sixths fractionWidth = width / 6 fractionDepth = depth / 6 #create the box boundaries randFracx = random.randint(0,fractionWidth+1) randFracz = random.randint(0, fractionDepth+1) xstart = box.minx + randFracx + 2 zstart = box.minz + randFracz + 2 xsize = width * 0.6 - randFracx zsize = depth * 0.6 - randFracz floorplan = BoundingBox((xstart, box.miny, zstart),(xsize,box.maxy,zsize)) return floorplan
def __init__(self, box, addLeft, addRight, addFront, addBack, height=1, offSetY=0): boxSize = utilityFunctions.getBoxSize(box) fullBox = BoundingBox( (box.minx - addLeft, box.miny + offSetY, box.minz - addBack), (boxSize[0] + addLeft + addRight, height, boxSize[2] + addFront + addBack)) leftBar = BoundingBox((fullBox.minx, box.miny + offSetY, fullBox.minz), (addLeft, height, boxSize[2] + addFront)) rightBar = BoundingBox((box.maxx, box.miny + offSetY, box.minz), (addRight, height, boxSize[2] + addBack)) backBar = BoundingBox( (fullBox.minx, box.miny + offSetY, box.maxz + addFront), (boxSize[0] + addLeft, height, addBack)) frontBar = BoundingBox((box.minx, box.miny + offSetY, fullBox.minz), (boxSize[0] + addRight, height, addFront)) cornorLF = BoundingBox( (fullBox.minx, box.miny + offSetY, fullBox.minz), (addLeft, height, addFront)) cornorLB = BoundingBox((fullBox.minx, box.miny + offSetY, box.maxz), (addLeft, height, addBack)) cornorRF = BoundingBox((box.maxx, box.miny + offSetY, fullBox.minz), (addRight, height, addFront)) cornorRB = BoundingBox((box.maxx, box.miny + offSetY, box.maxz), (addRight, height, addBack)) self.left = leftBar self.right = rightBar self.front = frontBar self.back = backBar self.full = fullBox self.cornorLF = cornorLF self.cornorLB = cornorLB self.cornorRF = cornorRF self.cornorRB = cornorRB
boxSize = utilityFunctions.getBoxSize(box) if min(boxSize[0],boxSize[1]) < 2: return box,box,box,box fenceLeft = CutBar(box, 1,1,0,0,buildFenceHightRange).left fenceRight = CutBar(box, 1,1,0,0,buildFenceHightRange).right fenceFront = CutBar(box, 0,0,1,1,buildFenceHightRange).front fenceBack = CutBar(box, 0,0,1,1,buildFenceHightRange).back utilityFunctions.fillLayerEmpty(level,fenceLeft,0,(85,0)) utilityFunctions.fillLayerEmpty(level,fenceRight,0,(85,0)) utilityFunctions.fillLayerEmpty(level,fenceFront,0,(85,0)) utilityFunctions.fillLayerEmpty(level,fenceBack,0,(85,0)) return fenceLeft, fenceRight,fenceFront, fenceBack def buildBase(level, box, (block,data),height): boxSize = utilityFunctions.getBoxSize(box) for i in range(0, height): layer = BoundingBox((box.minx,box.miny+i,box.minz),(boxSize[0],1,boxSize[2])) utilityFunctions.fillBoxEmpty(level,CutBar(layer,i,i,i,i).middle,(block,data)) #makeFloor(level, CutBar(layer,i,i,i,i).middle, options) layer = BoundingBox((box.minx,box.miny+height,box.minz),(boxSize[0],1,boxSize[2])) return CutBar(layer,height,height,height,height,boxSize[1]-height).middle def buildWall(level, box, (block,data), height, floorInterVal=5): floorBoxes = [] curBottom = 0 floorHeight = random.randint(floorInterVal, floorInterVal+3) floorBoxes.append(BoundingBox((box.minx, box.miny+curBottom, box.minz),(box.width, floorHeight, box.length))) while height - curBottom > floorInterVal: #utilityFunctions.fillLayer(level,AddBar(box,1,1,1,1).full, curBottom, (block,data))
def perform(level, box, options): logging.info("BoundingBox coordinates: ({},{}),({},{}),({},{})".format( box.miny, box.maxy, box.minx, box.maxx, box.minz, box.maxz)) # ==== PREPARATION ===== (width, height, depth) = utilityFunctions.getBoxSize(box) logging.info("Selection box dimensions {}, {}, {}".format( width, height, depth)) world = utilityFunctions.generateMatrix(level, box, width, depth, height) world_space = utilityFunctions.dotdict({ "y_min": 0, "y_max": height - 1, "x_min": 0, "x_max": width - 1, "z_min": 0, "z_max": depth - 1 }) height_map = utilityFunctions.getHeightMap(level, box) # ==== PARTITIONING OF NEIGHBOURHOODS ==== (center, neighbourhoods) = generateCenterAndNeighbourhood(world_space, height_map) all_buildings = [] # ==== GENERATING CITY CENTER ==== minimum_h = 50 minimum_w = 25 mininum_d = 25 iterate = 100 minimum_lots = 6 available_lots = 0 maximum_tries = 50 current_try = 0 threshold = 1 partitioning_list = [] temp_partitioning_list = [] # run the partitioning algorithm for iterate times to get different partitionings of the same area logging.info( "Generating {} different partitionings for the the City Centre {}". format(iterate, center)) while available_lots < minimum_lots and current_try < maximum_tries: for i in range(iterate): # generate a partitioning through some algorithm if RNG.random() < 0.5: partitioning = binarySpacePartitioning(center[0], center[1], center[2], center[3], center[4], center[5], []) else: partitioning = quadtreeSpacePartitioning( center[0], center[1], center[2], center[3], center[4], center[5], []) # remove invalid partitions from the partitioning valid_partitioning = [] for p in partitioning: (y_min, y_max, x_min, x_max, z_min, z_max) = (p[0], p[1], p[2], p[3], p[4], p[5]) failed_conditions = [] cond1 = utilityFunctions.hasValidGroundBlocks( x_min, x_max, z_min, z_max, height_map) if cond1 == False: failed_conditions.append(1) cond2 = utilityFunctions.hasMinimumSize( y_min, y_max, x_min, x_max, z_min, z_max, minimum_h, minimum_w, mininum_d) if cond2 == False: failed_conditions.append(2) cond3 = utilityFunctions.hasAcceptableSteepness( x_min, x_max, z_min, z_max, height_map, utilityFunctions.getScoreArea_type1, threshold) if cond3 == False: failed_conditions.append(3) if cond1 and cond2 and cond3: score = utilityFunctions.getScoreArea_type1( height_map, x_min, x_max, z_min, z_max) valid_partitioning.append((score, p)) else: logging.info( "Failed Conditions {}".format(failed_conditions)) partitioning_list.extend(valid_partitioning) logging.info( "Generated a partition with {} valid lots and {} invalids ones" .format(len(valid_partitioning), len(partitioning) - len(valid_partitioning))) # order partitions by steepness partitioning_list = sorted(partitioning_list) final_partitioning = utilityFunctions.getNonIntersectingPartitions( partitioning_list) available_lots = len(final_partitioning) logging.info( "Current partitioning with most available_lots: {}, current threshold {}" .format(available_lots, threshold)) threshold += 1 current_try += 1 logging.info("Final lots ({}) for the City Centre {}: ".format( len(final_partitioning), center)) for p in final_partitioning: logging.info("\t{}".format(p)) for partition in final_partitioning: building = generateBuilding(world, partition, height_map) all_buildings.append(building) # ==== GENERATING NEIGHBOURHOODS ==== minimum_h = 3 minimum_w = 7 mininum_d = 6 iterate = 100 maximum_tries = 50 current_try = 0 minimum_lots = 20 available_lots = 0 threshold = 1 partitioning_list = [] final_partitioning = [] while available_lots < minimum_lots and current_try < maximum_tries: partitioning_list = [] for i in range(iterate): for neigh in neighbourhoods: logging.info( "Generating {} different partitionings for the neighbourhood {}" .format(iterate, neigh)) if RNG.random() < 0.5: partitioning = binarySpacePartitioning( neigh[0], neigh[1], neigh[2], neigh[3], neigh[4], neigh[5], []) else: partitioning = quadtreeSpacePartitioning( neigh[0], neigh[1], neigh[2], neigh[3], neigh[4], neigh[5], []) valid_partitioning = [] for p in partitioning: (y_min, y_max, x_min, x_max, z_min, z_max) = (p[0], p[1], p[2], p[3], p[4], p[5]) failed_conditions = [] cond1 = utilityFunctions.hasValidGroundBlocks( x_min, x_max, z_min, z_max, height_map) if cond1 == False: failed_conditions.append(1) cond2 = utilityFunctions.hasMinimumSize( y_min, y_max, x_min, x_max, z_min, z_max, minimum_h, minimum_w, mininum_d) if cond2 == False: failed_conditions.append(2) cond3 = utilityFunctions.hasAcceptableSteepness( x_min, x_max, z_min, z_max, height_map, utilityFunctions.getScoreArea_type1, threshold) if cond3 == False: failed_conditions.append(3) if cond1 and cond2 and cond3: score = utilityFunctions.getScoreArea_type1( height_map, x_min, x_max, z_min, z_max) valid_partitioning.append((score, p)) logging.info("Passed the 3 conditions!") else: logging.info( "Failed Conditions {}".format(failed_conditions)) partitioning_list.extend(valid_partitioning) logging.info( "Generated a partition with {} valid lots and {} invalids ones" .format(len(valid_partitioning), len(partitioning) - len(valid_partitioning))) temp_partitioning_list.extend(partitioning_list) # order partitions by steepness temp_partitioning_list = sorted(temp_partitioning_list) final_partitioning = utilityFunctions.getNonIntersectingPartitions( temp_partitioning_list) available_lots = len(final_partitioning) logging.info( "Current neighbourhood partitioning with most available_lots: {}, current threshold {}" .format(available_lots, threshold)) threshold += 1 current_try += 1 logging.info("Final lots ({})for the neighbourhood {}: ".format( len(final_partitioning), neigh)) for p in final_partitioning: logging.info("\t{}".format(p)) for partition in final_partitioning: house = generateHouse(world, partition, height_map) all_buildings.append(house) # ==== GENERATE PATH MAP ==== # generate a path map that gives the cost of moving to each neighbouring cell pathMap = utilityFunctions.getPathMap(height_map, width, depth) # ==== CONNECTING BUILDINGS WITH ROADS ==== logging.info("Calling MST on {} buildings".format(len(all_buildings))) MST = utilityFunctions.getMST_Manhattan(all_buildings, pathMap, height_map) pavementBlockID = 4 pavementBlockSubtype = 0 for m in MST: p1 = m[1] p2 = m[2] logging.info("Pavement with distance {} between {} and {}".format( m[0], p1.entranceLot, p2.entranceLot)) path = utilityFunctions.aStar(p1.entranceLot, p2.entranceLot, pathMap, height_map) if path != None: logging.info( "Found path between {} and {}. Generating road...".format( p1.entranceLot, p2.entranceLot)) GeneratePath.generatPath(world, path, height_map, (pavementBlockID, pavementBlockSubtype)) else: logging.info( "Couldnt find path between {} and {}. Generating a straight road between them..." .format(p1.entranceLot, p2.entranceLot)) GeneratePath.generatPath_StraightLine( world, p1.entranceLot[1], p1.entranceLot[2], p2.entranceLot[1], p2.entranceLot[2], height_map, (pavementBlockID, pavementBlockSubtype)) # ==== UPDATE WORLD ==== world.updateWorld()
def perform(level, box, options): logging.info("BoundingBox coordinates: ({},{}),({},{}),({},{})".format( box.miny, box.maxy, box.minx, box.maxx, box.minz, box.maxz)) # ==== PREPARATION ===== logging.info("Preparation") (width, height, depth) = utilityFunctions.getBoxSize(box) logging.info("Selection box dimensions {}, {}, {}".format( width, height, depth)) world = utilityFunctions.generateMatrix(level, box, width, depth, height) world_space = utilityFunctions.dotdict({ "y_min": 0, "y_max": height - 1, "x_min": 0, "x_max": width - 1, "z_min": 0, "z_max": depth - 1 }) logging.info("Generating simple height map") simple_height_map = utilityFunctions.getSimpleHeightMap( level, box) #no height = -1 when water like block logging.info("Saving and erasing the trees") list_trees = TreeGestion.prepareMap( world, simple_height_map ) #get a list of all trees and erase them, so we can put some of them back after logging.info("Generating normal height map") height_map = utilityFunctions.getHeightMap(level, box) #villageDeck = utilityFunctions.generateVillageDeck("city", width, depth) # ==== PARTITIONING OF NEIGHBOURHOODS ==== logging.info( "Partitioning of the map, getting city center and neighbourhoods") (center, neighbourhoods) = generateCenterAndNeighbourhood(world_space, height_map) all_buildings = [] # ==== GENERATING CITY CENTER ==== logging.info("Generating city center") minimum_h = 50 minimum_w = 25 mininum_d = 25 iterate = 100 minimum_lots = 6 available_lots = 0 maximum_tries = 50 current_try = 0 threshold = 20 partitioning_list = [] temp_partitioning_list = [] # run the partitioning algorithm for iterate times to get different partitionings of the same area logging.info( "Generating {} different partitionings for the the City Centre {}". format(iterate, center)) while available_lots < minimum_lots and current_try < maximum_tries: for i in range(iterate): # generate a partitioning through some algorithm if RNG.random() < 0.5: partitioning = binarySpacePartitioning(center[0], center[1], center[2], center[3], center[4], center[5], []) else: partitioning = quadtreeSpacePartitioning( center[0], center[1], center[2], center[3], center[4], center[5], []) # remove invalid partitions from the partitioning valid_partitioning = [] for p in partitioning: (y_min, y_max, x_min, x_max, z_min, z_max) = (p[0], p[1], p[2], p[3], p[4], p[5]) failed_conditions = [] cond1 = utilityFunctions.hasValidGroundBlocks( x_min, x_max, z_min, z_max, height_map) if cond1 == False: failed_conditions.append(1) cond2 = utilityFunctions.hasMinimumSize( y_min, y_max, x_min, x_max, z_min, z_max, minimum_h, minimum_w, mininum_d) if cond2 == False: failed_conditions.append(2) cond3 = utilityFunctions.hasAcceptableSteepness( x_min, x_max, z_min, z_max, height_map, utilityFunctions.getScoreArea_type4, threshold) if cond3 == False: failed_conditions.append(3) if cond1 and cond2 and cond3: score = utilityFunctions.getScoreArea_type4( height_map, x_min, x_max, z_min, z_max) valid_partitioning.append((score, p)) logging.info("Passed the 3 conditions!") else: logging.info( "Failed Conditions {}".format(failed_conditions)) partitioning_list.extend(valid_partitioning) logging.info( "Generated a partition with {} valid lots and {} invalids ones" .format(len(valid_partitioning), len(partitioning) - len(valid_partitioning))) # order partitions by steepness partitioning_list = sorted(partitioning_list) final_partitioning = utilityFunctions.getNonIntersectingPartitions( partitioning_list) available_lots = len(final_partitioning) logging.info( "Current partitioning with most available_lots: {}, current threshold {}" .format(available_lots, threshold)) threshold += 2 current_try += 1 logging.info("Final lots ({}) for the City Centre {}: ".format( len(final_partitioning), center)) for p in final_partitioning: logging.info("\t{}".format(p)) for partition in final_partitioning: building = generateBuilding(world, partition, height_map, simple_height_map) all_buildings.append(building) # ==== GENERATING NEIGHBOURHOODS ==== logging.info("Generating neighbourhoods") minimum_h = 10 minimum_w = 16 mininum_d = 16 iterate = 100 maximum_tries = 80 current_try = 0 minimum_lots = 50 available_lots = 0 threshold = 50 partitioning_list = [] final_partitioning = [] while available_lots < minimum_lots and current_try < maximum_tries: partitioning_list = [] for i in range(iterate): for neigh in neighbourhoods: logging.info( "Generating {} different partitionings for the neighbourhood {}" .format(iterate, neigh)) if RNG.random() < 0.5: partitioning = binarySpacePartitioning( neigh[0], neigh[1], neigh[2], neigh[3], neigh[4], neigh[5], []) else: partitioning = quadtreeSpacePartitioning( neigh[0], neigh[1], neigh[2], neigh[3], neigh[4], neigh[5], []) valid_partitioning = [] for p in partitioning: (y_min, y_max, x_min, x_max, z_min, z_max) = (p[0], p[1], p[2], p[3], p[4], p[5]) failed_conditions = [] cond1 = utilityFunctions.hasValidGroundBlocks( x_min, x_max, z_min, z_max, height_map) if cond1 == False: failed_conditions.append(1) cond2 = utilityFunctions.hasMinimumSize( y_min, y_max, x_min, x_max, z_min, z_max, minimum_h, minimum_w, mininum_d) if cond2 == False: failed_conditions.append(2) cond3 = utilityFunctions.hasAcceptableSteepness( x_min, x_max, z_min, z_max, height_map, utilityFunctions.getScoreArea_type4, threshold) if cond3 == False: failed_conditions.append(3) if cond1 and cond2 and cond3: score = utilityFunctions.getScoreArea_type4( height_map, x_min, x_max, z_min, z_max) valid_partitioning.append((score, p)) logging.info("Passed the 3 conditions!") else: logging.info( "Failed Conditions {}".format(failed_conditions)) partitioning_list.extend(valid_partitioning) logging.info( "Generated a partition with {} valid lots and {} invalids ones" .format(len(valid_partitioning), len(partitioning) - len(valid_partitioning))) temp_partitioning_list.extend(partitioning_list) # order partitions by steepness temp_partitioning_list = sorted(temp_partitioning_list) final_partitioning = utilityFunctions.getNonIntersectingPartitions( temp_partitioning_list) available_lots = len(final_partitioning) logging.info( "Current neighbourhood partitioning with most available_lots: {}, current threshold {}" .format(available_lots, threshold)) threshold += 2 current_try += 1 logging.info("Final lots ({})for the neighbourhood {}: ".format( len(final_partitioning), neigh)) for p in final_partitioning: logging.info("\t{}".format(p)) logging.info("Building in the neighbourhood") n = 0 for i in xrange(0, int(len(final_partitioning) * 0.50) + 1): house = generateHouse(world, final_partitioning[i], height_map, simple_height_map) all_buildings.append(house) logging.info("House number : {} built on lot number {}".format( n + 1, i + 1)) n += 1 n = 0 for i in xrange( int(len(final_partitioning) * 0.50) + 1, int(len(final_partitioning) * 0.70) + 1): # generate either a regular farm or a smiley farm farm = generateFarm(world, final_partitioning[i], height_map, simple_height_map) if (RNG.randint( 0, 2) == 0) else generateFarm( world, final_partitioning[i], height_map, simple_height_map, "smiley") all_buildings.append(farm) logging.info("Farm number : {} built on lot number {}".format( n + 1, i + 1)) n += 1 n = 0 m = 0 for i in xrange( int(len(final_partitioning) * 0.70) + 1, len(final_partitioning)): slopeStructure = generateSlopeStructure(world, final_partitioning[i], height_map, simple_height_map) if slopeStructure.type == "tower": all_buildings.append(slopeStructure) logging.info("Tower number : {} built on lot number {}".format( n + 1, i + 1)) n += 1 else: logging.info( "RollerCoaster number : {} built on lot number {}".format( m + 1, i + 1)) m += 1 # ==== GENERATE PATH MAP ==== # generate a path map that gives the cost of moving to each neighbouring cell logging.info("Generating path map and simple path map") pathMap = utilityFunctions.getPathMap(height_map, width, depth) simple_pathMap = utilityFunctions.getPathMap(simple_height_map, width, depth) #not affected by water # ==== CONNECTING BUILDINGS WITH ROADS ==== logging.info("Calling MST on {} buildings".format(len(all_buildings))) MST = utilityFunctions.getMST_Manhattan(all_buildings) for m in MST: p1 = m[1] p2 = m[2] if p1.type == "farm" or p2.type == "farm": pavement_Type = "Grass" bridge_Type = "Wood" else: pavement_Type = "Stone" bridge_Type = "Stone" try: logging.info( "Trying to find a path between {} and {}, finding potential bridges" .format(p1.entranceLot, p2.entranceLot)) simple_path = utilityFunctions.simpleAStar( p1.entranceLot, p2.entranceLot, simple_pathMap, simple_height_map) #water and height are not important list_end_points = utilityFunctions.findBridgeEndPoints( world, simple_path, simple_height_map) if list_end_points != []: for i in xrange(0, len(list_end_points), 2): logging.info( "Found water between {} and {}. Trying to generating a {} bridge..." .format(list_end_points[i], list_end_points[i + 1], bridge_Type)) GenerateBridge.generateBridge(world, simple_height_map, list_end_points[i], list_end_points[i + 1], bridge_Type) list_end_points.insert(0, p1.entranceLot) list_end_points.append(p2.entranceLot) for i in xrange(0, len(list_end_points), 2): path = utilityFunctions.aStar(list_end_points[i], list_end_points[i + 1], pathMap, height_map) logging.info( "Connecting end points of the bridge(s), Generating {} road between {} and {}" .format(pavement_Type, list_end_points[i], list_end_points[i + 1])) GeneratePath.generatePath(world, path, height_map, pavement_Type) else: logging.info( "No potential bridge found, Generating road between {} and {}" .format(list_end_points[i], list_end_points[i + 1])) GeneratePath.generatePath(world, simple_path, height_map, pavement_Type) except: logging.info( "Bridge found but is not buildable, Trying to find a path between {} and {} avoiding water" .format(p1.entranceLot, p2.entranceLot)) path = utilityFunctions.aStar(p1.entranceLot, p2.entranceLot, pathMap, height_map) if path != None: logging.info( "Path found, Generating {} road between {} and {}".format( pavement_Type, p1.entranceLot, p2.entranceLot)) GeneratePath.generatePath(world, path, height_map, pavement_Type) else: logging.info( "Couldnt find path between {} and {}. Generating a straight road" .format(p1.entranceLot, p2.entranceLot)) GeneratePath.generatePath_StraightLine( world, p1.entranceLot[1], p1.entranceLot[2], p2.entranceLot[1], p2.entranceLot[2], height_map, pavement_Type) # ==== PUT BACK UNTOUCHED TREES ==== logging.info("Putting back untouched trees") TreeGestion.putBackTrees( world, height_map, list_trees ) #put back the trees that are not cut buy the building and are not in unwanted places # ==== UPDATE WORLD ==== world.updateWorld()
def transform_to_floor(self): # changes 3d Minecraft space into 2d numpy array box_size = utilityFunctions.getBoxSize(self.box) floor = np.zeros((box_size[0], box_size[2])) return floor
def perform(level, box, options): logging.info("BoundingBox coordinates: ({},{}),({},{}),({},{})".format( box.miny, box.maxy, box.minx, box.maxx, box.minz, box.maxz)) # ==== PREPARATION ===== (width, height, depth) = utilityFunctions.getBoxSize(box) logging.info("Selection box dimensions {}, {}, {}".format( width, height, depth)) world = utilityFunctions.generateMatrix(level, box, width, depth, height) world_space = utilityFunctions.dotdict({ "y_min": 0, "y_max": height - 1, "x_min": 0, "x_max": width - 1, "z_min": 0, "z_max": depth - 1 }) height_map = utilityFunctions.getHeightMap(level, box, None, False) # === Wood quantity and Biome analyzer === # air_like = [ 0, 4, 5, 6, 20, 23, 29, 30, 35, 37, 38, 39, 40, 44, 46, 47, 50, 59, 66, 83, 85, 86, 95, 102, 104, 105, 107, 126, 141, 142, 160, 175 ] wood_height_map = utilityFunctions.getHeightMap(level, box, air_like, True) (usable_wood, biome) = EnvironmentAnalyzer.determinate_usable_wood( level, wood_height_map, box.minx, box.maxx, box.minz, box.maxz) # === City stats === # biome_with_well = ['Desert', 'Badlands'] APARTMENT_SIZE = 2 HOUSE_SIZE = 4 GREENHOUSE_CAPACITY = 15 inhabitants = 0 greenhouse_count = 0 well_count = 0 # ==== PARTITIONING OF THE SELECTION IN AREA IN ORDER TO FLATTEN ==== # Work in progress do not use #earthwork_height_map = utilityFunctions.getHeightMap(level,box, None, True) #area_partitioning_and_flattening(world_space, earthwork_height_map, world, biome) # ==== PARTITIONING OF NEIGHBOURHOODS ==== (center, neighbourhoods) = generateCenterAndNeighbourhood(world_space, height_map) all_buildings = [] # ==== GENERATING CITY CENTER ==== minimum_h = 50 minimum_w = 25 mininum_d = 25 iterate = 100 minimum_lots = 6 available_lots = 0 maximum_tries = 50 current_try = 0 threshold = 1 partitioning_list = [] temp_partitioning_list = [] # run the partitioning algorithm for iterate times to get different partitionings of the same area logging.info( "Generating {} different partitionings for the the City Centre {}". format(iterate, center)) while available_lots < minimum_lots and current_try < maximum_tries: for i in range(iterate): # generate a partitioning through some algorithm if RNG.random() < 0.5: partitioning = binarySpacePartitioning(center[0], center[1], center[2], center[3], center[4], center[5], []) else: partitioning = quadtreeSpacePartitioning( center[0], center[1], center[2], center[3], center[4], center[5], []) # remove invalid partitions from the partitioning valid_partitioning = [] for p in partitioning: (y_min, y_max, x_min, x_max, z_min, z_max) = (p[0], p[1], p[2], p[3], p[4], p[5]) failed_conditions = [] cond1 = utilityFunctions.hasValidGroundBlocks( x_min, x_max, z_min, z_max, height_map) if cond1 == False: failed_conditions.append(1) cond2 = utilityFunctions.hasMinimumSize( y_min, y_max, x_min, x_max, z_min, z_max, minimum_h, minimum_w, mininum_d) if cond2 == False: failed_conditions.append(2) cond3 = utilityFunctions.hasAcceptableSteepness( x_min, x_max, z_min, z_max, height_map, utilityFunctions.getScoreArea_type1, threshold) if cond3 == False: failed_conditions.append(3) if cond1 and cond2 and cond3: score = utilityFunctions.getScoreArea_type1( height_map, x_min, x_max, z_min, z_max) valid_partitioning.append((score, p)) else: logging.info( "Failed Conditions {}".format(failed_conditions)) partitioning_list.extend(valid_partitioning) logging.info( "Generated a partition with {} valid lots and {} invalids ones" .format(len(valid_partitioning), len(partitioning) - len(valid_partitioning))) # order partitions by steepness partitioning_list = sorted(partitioning_list) final_partitioning = utilityFunctions.getNonIntersectingPartitions( partitioning_list) available_lots = len(final_partitioning) logging.info( "Current partitioning with most available_lots: {}, current threshold {}" .format(available_lots, threshold)) threshold += 1 current_try += 1 logging.info("Final lots ({}) for the City Centre {}: ".format( len(final_partitioning), center)) for p in final_partitioning: logging.info("\t{}".format(p)) for partition in final_partitioning: building, apartments_inhabitants = generateBuilding( world, partition, height_map, usable_wood, biome) inhabitants += apartments_inhabitants all_buildings.append(building) # ==== GENERATING NEIGHBOURHOODS ==== minimum_h = 10 minimum_w = 16 mininum_d = 16 iterate = 100 maximum_tries = 50 current_try = 0 minimum_lots = 20 available_lots = 0 threshold = 1 partitioning_list = [] final_partitioning = [] while available_lots < minimum_lots and current_try < maximum_tries: partitioning_list = [] for i in range(iterate): for neigh in neighbourhoods: logging.info( "Generating {} different partitionings for the neighbourhood {}" .format(iterate, neigh)) if RNG.random() < 0.5: partitioning = binarySpacePartitioning( neigh[0], neigh[1], neigh[2], neigh[3], neigh[4], neigh[5], []) else: partitioning = quadtreeSpacePartitioning( neigh[0], neigh[1], neigh[2], neigh[3], neigh[4], neigh[5], []) valid_partitioning = [] for p in partitioning: (y_min, y_max, x_min, x_max, z_min, z_max) = (p[0], p[1], p[2], p[3], p[4], p[5]) failed_conditions = [] cond1 = utilityFunctions.hasValidGroundBlocks( x_min, x_max, z_min, z_max, height_map) if cond1 == False: failed_conditions.append(1) cond2 = utilityFunctions.hasMinimumSize( y_min, y_max, x_min, x_max, z_min, z_max, minimum_h, minimum_w, mininum_d) if cond2 == False: failed_conditions.append(2) cond3 = utilityFunctions.hasAcceptableSteepness( x_min, x_max, z_min, z_max, height_map, utilityFunctions.getScoreArea_type1, threshold) if cond3 == False: failed_conditions.append(3) if cond1 and cond2 and cond3: score = utilityFunctions.getScoreArea_type1( height_map, x_min, x_max, z_min, z_max) valid_partitioning.append((score, p)) logging.info("Passed the 3 conditions!") else: logging.info( "Failed Conditions {}".format(failed_conditions)) partitioning_list.extend(valid_partitioning) logging.info( "Generated a partition with {} valid lots and {} invalids ones" .format(len(valid_partitioning), len(partitioning) - len(valid_partitioning))) temp_partitioning_list.extend(partitioning_list) # order partitions by steepness temp_partitioning_list = sorted(temp_partitioning_list) final_partitioning = utilityFunctions.getNonIntersectingPartitions( temp_partitioning_list) available_lots = len(final_partitioning) logging.info( "Current neighbourhood partitioning with most available_lots: {}, current threshold {}" .format(available_lots, threshold)) threshold += 1 current_try += 1 logging.info("Final lots ({})for the neighbourhood {}: ".format( len(final_partitioning), neigh)) for p in final_partitioning: logging.info("\t{}".format(p)) for partition in final_partitioning: if well_count < 1 and biome in biome_with_well: well = generateWell(world, partition, height_map, biome) well_count += 1 all_buildings.append(well) elif greenhouse_count * GREENHOUSE_CAPACITY < inhabitants: greenhouse = generateGreenhouse(world, partition, height_map, usable_wood, biome) greenhouse_count += 1 all_buildings.append(greenhouse) else: house = generateHouse(world, partition, height_map, usable_wood, biome) inhabitants += RNG.randint(1, HOUSE_SIZE) all_buildings.append(house) # ==== GENERATE PATH MAP ==== # generate a path map that gives the cost of moving to each neighbouring cell pathMap = utilityFunctions.getPathMap(height_map, width, depth) # ==== CONNECTING BUILDINGS WITH ROADS ==== logging.info("Calling MST on {} buildings".format(len(all_buildings))) MST = utilityFunctions.getMST_Manhattan(all_buildings, pathMap, height_map) pavementBlockID = BlocksInfo.getPavmentId(biome) for m in MST: p1 = m[1] p2 = m[2] logging.info("Pavement with distance {} between {} and {}".format( m[0], p1.entranceLot, p2.entranceLot)) path = utilityFunctions.aStar(p1.entranceLot, p2.entranceLot, pathMap, height_map) if path != None: logging.info( "Found path between {} and {}. Generating road...".format( p1.entranceLot, p2.entranceLot)) GeneratePath.generatPath(world, path, height_map, pavementBlockID) else: logging.info( "Couldnt find path between {} and {}. Generating a straight road between them..." .format(p1.entranceLot, p2.entranceLot)) GeneratePath.generatPath_StraightLine(world, p1.entranceLot[1], p1.entranceLot[2], p2.entranceLot[1], p2.entranceLot[2], height_map, pavementBlockID) # ==== UPDATE WORLD ==== world.updateWorld()