git.fiddlerwoaroof.com
Raw Blame History
import random
import copy

class DjikstraMap(object):
	def __init__(self, mp=None):
		#print '__init__ djm'
		self.map = None
		if mp is not None:
			self.load_map(mp)

	def load_map(self, mp):
		self.map = [
			[ [255,None][cell] for cell in row ]
				for row in mp
		]
		self.width = len(self.map)
		self.height = len(self.map[0])
	def set_goals(self, *args, **k):
		for x,y in args:
			self.map[x][y] = k.get('weight', 0)

	def iter_map(self):
		for x, row in enumerate(self.map):
			for y, cell in enumerate(row):
				if cell is not None:
					yield (x,y), cell

	def get_cross(self, pos, rad):
		ox,oy = pos
		# up, down, left, right
		result = [
			(ox, oy-rad),
			(ox, oy+rad),
			(ox-rad, oy),
			(ox+rad, oy),
		]
		for idx, (x,y) in enumerate(result):
			if x < 0 or x >= self.width:
				result[idx] = None
			elif y < 0 or y >= self.height:
				result[idx] = None
			else:
				result[idx] = self.map[x][y]
		return result

	def get_rect(self, pos, rad):
		x,y = pos
		result = []
		for cx in range(x-rad, x+rad+1):
			result.append([])
			for cy in range(y-rad, y+rad+1):
				if cx < 0 or cx >= len(self.map):
					result[-1].append(None)
				elif cy < 0 or cy >= len(self.map[0]):
					result[-1].append(None)
				else:
					result[-1].append(self.map[cx][cy])

		return result

	def get_line(self, pos1, pos2):
		x1,y1 = pos1
		x2,y2 = pos2
		if y1 == y2:
			return [ (x,y1) for x in range(x1,x2+1) ]
		if x1 == x2:
			return [ (x1,y) for y in range(y1,y2+1) ]

	def get_borders(self, pos, rad):
		x,y = pos

		results = []
		results.extend(
			self.get_line(
				(min(x-rad, 0), min(y-rad, 0)),
				(min(x-rad, 0), min(y+rad, self.height))
			)
		)
		results.extend(
			self.get_line(
				(min(x-rad, 0),          min(y-rad, 0)),
				(min(x+rad, self.width), min(y-rad, 0))
			)
		)

		results.extend(
			self.get_line(
				(min(x+rad, self.width), min(y+rad, self.height)),
				(min(x-rad, 0),          min(y+rad, self.height))
			)
		)

		results.extend(
			self.get_line(
				(min(x+rad, self.width), min(y+rad, self.height)),
				(min(x+rad, self.width), min(y-rad, 0))
			)
		)

	def iter(self, num):
		result = True
		for _ in range(num):
			result = self.cycle()
			if result == False:
				break
		return result

	def cycle(self):
		changed = False
		out = self.map
		for pos, cell in self.iter_map():
			x,y = pos

			#rect = self.get_rect(pos, 2)
			#neighbors = [n for n in borders(rect)]
			neighbors = (r for r in sum(self.get_rect(pos, 1), []) if r is not None)
			#neighbors = (r for r in self.get_cross(pos, 1) if r is not None)

			try:
				min_neighbor = min(neighbors)
			except ValueError: continue

			if cell > min_neighbor + 1:
				changed = True
				out[x][y] = min_neighbor + 1
		return changed

	def visualize(self):
		print
		for row in zip(*self.map):
			for cell in row:
				if cell is None: print ' ',
				elif cell > 9: print '*',
				else: print cell,
			print

	def get_neighbor_values(self, x,y):
		b = enumerate((enumerate(r,-1) for r in self.get_rect( (x,y), 1 )),-1)
		result = [(i1,i2, v) for i1, r in b for i2,v in r if v is not None]
		#print result
		return result

	def get_low_neighbors(self, x,y, num=2):
		result = sorted(self.get_neighbor_values(x,y), key=lambda a: a[-1])
		return result[:num]

	def categorize(self, values):
		results = {}
		for i1,i2,v in values:
			results.setdefault(v,[]).append( (i1,i2) )
		return results
	def nav(self, x,y):
		results = self.get_neighbor_values(x,y)
		results = self.categorize(results)
		dx,dy = random.choice(results[min(results)])
		#print dx,dy,min(results)

		return dx,dy

def borders(rect):
	mx, my = len(rect)-1, len(rect[0])-1
	for x, row in enumerate(rect):
		for y, cell in enumerate(row):
			if x in {0,mx} or y in {0,my}:
				if cell is not None:
					yield cell

def dist( p1, p2 ):
	x1,y1 = p1
	x2,y2 = p2
	return int( ( (x2-x1)**2+(y2-y1)**2 ) ** .5 )