- import sys
- import math
- import pygame
- pygame.init()
- screen = pygame.display.set_mode((800,600))
- scale = 20
- offsetX = scale/2
- offsetY = scale/2
- black = (0, 0, 0)
- gray = (50, 50, 50)
- white = (255, 255, 255)
- red = (255, 0, 0)
- class Board(object):
- def __init__(self):
- self.nodes = []
- def populateNodes(self, width, height):
- for x in range(0, width):
- for y in range(0, height):
- self.addNode(Node((x,y)))
- def addNode(self, node):
- self.nodes.append(node)
- def closeNode(self, point):
- for node in self.nodes:
- if node.point == point:
- node.open = False
- return
- def openNode(self, point):
- for node in self.nodes:
- if node.point == point:
- node.open = True
- return
- def clear(self):
- for node in self.nodes:
- node.open = True
- def getNodeAt(self, point):
- for node in self.nodes:
- if node.point == point and node.open:
- return node
- return None
- def getNodeAtPixel(self, pixel):
- pX = math.floor(pixel[0]/scale)
- pY = math.floor(pixel[1]/scale)
- point = (pX, pY)
- return self.getNodeAt(point)
- def drawNodes(self):
- for node in self.nodes:
- oX, oY = node.point
- rect = (oX*scale, oY*scale, scale, scale)
- width = 1
- if not node.open:
- width = 0
- pygame.draw.rect(screen, gray, rect, width)
- class Node(object):
- def __init__(self, point):
- self.open = True
- self.weight = 0
- self.distance = 0
- self.point = point
- def calculateWeight(self, creep):
- movementCost = self.calculateMovement(creep)
- distanceEstimate = self.calculateDistanceTo(creep)
- self.weight = movementCost+distanceEstimate
- def calculateMovement(self, creep):
- if self.point[0] == creep.destination[0] or self.point[1] == creep.destination[1]:
- return 10
- return 14
- def calculateDistanceTo(self, creep):
- dX = abs(creep.destination[0]-self.point[0])
- dY = abs(creep.destination[1]-self.point[1])
- return (dX+dY)*10
- def __repr__(self):
- return "<Node(X:'%d',Y:'%d',Weight:'%d')>" % (self.point[0], self.point[1], self.weight)
- class Creep(object):
- def __init__(self):
- self.board = None
- self.origin = ()
- self.point = ()
- self.destination = ()
- self.path = []
- self.pathStep = ()
- self.pathFound = False
- def attachToBoard(self, board, point):
- self.board = board
- self.point = point
- def findPath(self, destinationPoint):
- self.path = []
- self.pathStep = self.point
- self.pathFound = False
- self.destination = destinationPoint
- while self.pathFound == False:
- self.pathStep = self.scan(self.pathStep).point
- self.path.append(self.pathStep)
- self.board.closeNode(self.pathStep)
- def scan(self, currentPoint):
- nextNode = None
- nodes = []
- for x in range(-1, 2):
- for y in range(-1, 2):
- nodeX = currentPoint[0]+x
- nodeY = currentPoint[1]+y
- nodes.append(self.board.getNodeAt((nodeX,nodeY)))
- for node in nodes:
- if not node:
- continue
- node.calculateWeight(self)
- return self.lightestNode(nodes)
- def lightestNode(self, nodes):
- nextNode = None
- for node in nodes:
- if not node:
- continue
- else:
- if node.point == self.destination:
- self.pathFound = True
- return node
- if not nextNode:
- nextNode = node
- elif nextNode.weight > node.weight:
- nextNode = node
- return nextNode
- def drawPath(self):
- for point in self.path:
- oX, oY = point
- pygame.draw.circle(screen, red, ((oX*scale)+offsetX, (oY*scale)+offsetY), 5, 1)
- board = Board()
- creep = Creep()
- board.populateNodes(40,30)
- creep.attachToBoard(board, (5,5))
- while 1:
- for event in pygame.event.get():
- if event.type == pygame.MOUSEBUTTONUP:
- board.clear()
- board.closeNode((10,8))
- board.closeNode((10,9))
- board.closeNode((10,10))
- board.closeNode((10,11))
- board.closeNode((20,20))
- board.closeNode((20,19))
- board.closeNode((20,18))
- node = board.getNodeAtPixel(event.pos)
- creep.findPath(node.point)
- elif event.type == pygame.QUIT:
- sys.exit()
- screen.fill(black)
- board.drawNodes()
- creep.drawPath()
- pygame.display.flip()