public List<Point> findPath(int startx, int starty, int endx, int endy) {
		NodeSet openSet = new NodeSet();
		nodes.get(startx).get(starty).costFromStart = 0;
		nodes.get(startx).get(starty).predictedTotalCost = nodes.get(startx)
				.get(starty).costFromStart
				+ manhattanDistance(startx, starty, endx, endy);
		openSet.add(nodes.get(startx).get(starty));
		NodeSet closedSet = new NodeSet();

		while (openSet.size() > 0) {
			Node currentNode = openSet.getNext();
			if (currentNode.x == endx && currentNode.y == endy) {
				List<Point> path = new ArrayList<Point>();
				reconstructPath(path, currentNode);
				return path;
			}

			openSet.remove(currentNode);
			closedSet.add(currentNode);

			for (Node neighbor : getNeighbors(nodes, currentNode.x,
					currentNode.y)) {
				if (closedSet.contains(neighbor)) {
					continue;
				}
				if (!neighbor.walkable) {
					continue;
				}

				double tentative_g_score = currentNode.costFromStart + 1;
				if (!openSet.contains(neighbor)
						|| tentative_g_score < neighbor.costFromStart) {
					neighbor.parent = currentNode;
					neighbor.costFromStart = tentative_g_score;
					neighbor.predictedTotalCost = tentative_g_score
							+ manhattanDistance(neighbor.x, neighbor.y, endx,
									endy);
					openSet.add(neighbor);
				}
			}
		}

		// throw noPathException!?
		return new ArrayList<Point>();
	}