import noise import random from collections import defaultdict import math class Map(): def __init__( self, width=150, height=50, sealevel=50, scale=32, base=random.randint(1,250), lacunarity=0.5+random.random(), octaves=50, persistence=0.5, xoffset=random.randint(1,10000), yoffset=random.randint(1,10000) ): print("Initializing map") # Dealing with basic params self.width = width self.height = height self.sealevel = -0.37+((0.75/100)*sealevel) self.scale = scale self.base = base self.octaves = octaves self.persistence = persistence self.lacunarity = lacunarity self.xoffset = xoffset self.yoffset = yoffset # The master map we are going to need self.map = defaultdict(dict) self.coast = [] # All the required stuff to determine cities self.cities = [] # self.num_cities = 50+(100-int(self.sealevel)) self.num_cities = 75 self.coast_percentage = 25 self.distance = 3 def generateMap(self): print("Generating Map") # Fill in the blanks with random stuff for x in range(1,self.width+1): for y in range(1,self.height+1): area = noise.pnoise2( self.xoffset+x/self.scale, self.yoffset+y/(self.scale/3), octaves=self.octaves, persistence=self.persistence, lacunarity=self.lacunarity, repeatx=self.height, repeaty=self.width, base=self.base ) if area > self.sealevel: self.map[x][y] = "l" else: self.map[x][y] = "w" # Find coastal positions def findCoast(self): print("Finding coastal tiles") # Should replace with a range()-loop y = 1 while y <= self.height: x = 1 while x <= self.width: water = 0 if x !=1 and x!=self.width and y!=1 and y!=self.height and self.map[x][y]=="l": if self.map[x-1][y-1]=="w": water += 1 if self.map[x][y-1]=="w": water += 1 if self.map[x+1][y-1]=="w": water += 1 if self.map[x+1][y]=="w": water += 1 if self.map[x+1][y+1]=="w": water += 1 if self.map[x][y+1]=="w": water += 1 if self.map[x-1][y+1]=="w": water += 1 if self.map[x-1][y]=="w": water += 1 if water >= 1: coords = {} coords['x'] = x coords['y'] = y self.coast.append(coords) x+=1 y+=1 def generateCities(self): print("Generate cities") for round in range(0,self.num_cities): if random.randint(1,100) < self.coast_percentage: self.cities.append(random.choice(self.coast)) else: found = 0 while found == 0: randX = random.randint(1,self.width) randY = random.randint(1,self.height) if self.map[randX][randY]=="l" and self.noCityNear(self.distance,randX,randY): found = 1 coords = {} coords['x'] = randX coords['y'] = randY self.cities.append(coords) def noCityNear(self,distance,x,y): noCityNear = True counter = 0 for city in self.cities: #Lay-Z D-Bug: print( str(counter) +" x:"+ str( abs(city['x']-x) ) +"; y:"+ str( abs(city['y']-y) ) +";") # This should be an OR, but this takes forever! So this is good enough. if abs(city['x']-x)<self.distance and abs(city['y']-y)<self.distance: noCityNear = False counter+=1 return noCityNear def calcDistance(self,city,x,y): return math.ceil( math.sqrt( ((city['x']-x)**2)+((city['y']-y)**2) ) ) def addCities(self): print("Adding cities to map") for city in self.cities: self.map[city['x']][city['y']] = "c" # Print the world in its entirety # Per column we print the entire row def printWorld(self): print("Printing map: num_cities:"+str(self.num_cities)+" base:"+str(self.base)+" Offset:"+str(self.xoffset)+"/"+str(self.yoffset)) for y in range(1,self.height+1): for x in range(1,self.width+1): if self.map[x][y] == "c": print('\x1b[1;37;42m' + '*' + '\x1b[0m', end='') elif self.map[x][y] == "l": print('\x1b[1;37;42m' + ' ' + '\x1b[0m', end='') else: print('\x1b[1;37;44m' + ' ' + '\x1b[0m', end='') print("") # Dump the map that Python can work with def dumpMap(self): terrain = self.map metadata = {} metadata['width'] = self.width metadata['height'] = self.height metadata['coast_percentage'] = self.coast_percentage metadata['scale'] = self.scale metadata['base'] = self.base metadata['octaves'] = self.octaves metadata['persistence'] = self.persistence metadata['lacunarity'] = self.lacunarity metadata['xoffset'] = self.xoffset metadata['yoffset'] = self.yoffset return terrain, self.cities, self.coast, metadata