A* Algorytm - ścinanie rogów

0

Witam serdecznie. Od wczoraj zmagam się z problemem i nie do końca wiem jak go rozwiązać. Otóż chciałbym napisać pathfinder'a i poniekąd udało mi się to zrobić, z tym że ścina on rogi i nie bardzo mnie to cieszy. Nie wiem jak zbytnio temu zaradzić. Korzystam tak jak w tytule z A*.
Chciałbym, żeby on zachowywał się jak na poniższym pierwszym obrazku.path.png

Proszę o wskazówkę jak do tego doprowadzić i zerknięcie na kod, bowiem tu też może czaić się jakiś błąd. Z góry dziękuję za poświęcony czas :).

private Comparator<Node> nodeSorter = new Comparator<Node>() {

		public int compare(Node o1, Node o2) {
			if (o1.gCost > o2.gCost) return 1;
			else if (o1.gCost < o2.gCost) return -1;
			else return 0;
		}

	};

	public boolean checkIfInList(List<Node> list, Vector2i vector) {
		for (int i = 0; i < list.size(); i++) {
			if (list.get(i).tile.equals(vector)) return true;
		}
		return false;
	}

	public int getIndex(List<Node> list, Vector2i vector) {
		for (int i = 0; i < list.size(); i++) {
			if (list.get(i).tile.equals(vector)) return i;
		}
		return -1;
	}

	public List<Node> getPath(Vector2i start, Vector2i goal) {
		List<Node> openList = new ArrayList<Node>();
		List<Node> closedList = new ArrayList<Node>();
		Node currentNode = new Node(start, null, 0, start.getManhattanDistance(goal));
		openList.add(currentNode);

		while (openList.size() > 0) {
			Collections.sort(openList, nodeSorter);
			currentNode = openList.get(0);
			closedList.add(currentNode);
			openList.remove(0);

			if (currentNode.tile.equals(goal)) {
				List<Node> path = new ArrayList<Node>();
				while (currentNode.parent != null) {
					path.add(currentNode);
					currentNode = currentNode.parent;
				}
				return path;
			}

			int x = currentNode.tile.getX();
			int y = currentNode.tile.getY();

			for (int i = 0; i < 9; i++) {
				if (i == 4) continue; // środek kwadratu 3x3

				int xx = i % 3 - 1;
				int yy = i / 3 - 1;
				Vector2i ajacent = new Vector2i(x + xx, y + yy);

				Color color = getTile(ajacent.getX() << 5, ajacent.getY() << 5);

				if (checkIfInList(closedList, ajacent) || color.equals(Color.CYAN)) {
					continue; // dotąd działa jak należy
				} else if (color.equals(Color.BLACK)) {

					continue;
				} else if (!checkIfInList(openList, ajacent)) {
					double gCost = currentNode.gCost + currentNode.tile.getManhattanDistance(ajacent);
					double hCost = ajacent.getManhattanDistance(goal);
					// System.out.println(
					// "gCost=" + gCost + ", hCost=" + hCost + ", currentNode=" + currentNode.tile.getX());

					openList.add(new Node(ajacent, currentNode, gCost, hCost));

				} else {
					int index = getIndex(openList, ajacent);
					double gCost = currentNode.gCost + currentNode.tile.getManhattanDistance(ajacent);
					if (gCost < openList.get(index).gCost) {
						openList.get(index).updateNode(currentNode, gCost);
					}
				}
			}
		}
		return null;
	}

	
	
3

Przecież sam definiujsz gdzie graf ma krawędzie. Możesz więc zdefiniować że nie ma krawędzi po skosie. Niech graf ma krawędzie tylko pionowe i poziome pomiędzy środkami tych twoich kratek.

0

To byłaby bardzo dobra opcja jeśli całkowicie odrzuciłbym ruch po skosie, jednakże tego bym nie chciał. Zależy mi jedynie na tym, żeby ruch po skosie był zakazany tylko w takich przypadkach, gdy ścieżka 'ociera się' o bloczek nie do przejścia:

path1.png

Dlaczego by zakazywać np. takiego przejścia?
path2.png

2

W takim wypadku nie wyliczysz prawidłowej odległości od celu. Zostanie Ci przeszukiwanie wszerz.

Jeżeli jednak chciałbyś to zrobić, to polecam rozbicie programu i napisanie funkcji która przyjmie pole i zwróci pola na które można przejść. To uniwersalne rozwiązanie i w ten sposób możesz bez problemu zmienić sposób poruszania, nawet na np. tak dziwny jak ruch skoczka po szachownicy.

0

To nadal jest problem definiowania krawędzi.
Po prostu musisz dodać warunek czy krawędź istnieje czy nie, albo zakazanej krawędzi nadawać nieskończoną wagę.

Poza tym twój ostatni rysunek jest sprzeczny z pierwszym (pierwszy poprawny przypadek powinien mieć skos z prawej strony).

0

@Kakaranish no dobra to odrzuc ruch po skosie jeśli ocierasz się o przeszkodę, gdzie ty widzisz problem?

1 użytkowników online, w tym zalogowanych: 0, gości: 1