Adjusted small things, norhting serious
This commit is contained in:
@@ -13,9 +13,23 @@
|
||||
<strong>A*</strong> {{ 'PATHFINDING.EXPLANATION.ASTAR_EXPLANATION' | translate}}
|
||||
<a href="{{UrlConstants.ASTAR_WIKI}}" target="_blank" rel="noopener noreferrer">Wikipedia</a>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<strong>{{ 'PATHFINDING.EXPLANATION.NOTE' | translate}}</strong> {{ 'PATHFINDING.EXPLANATION.DISCLAIMER' | translate}}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="controls-container">
|
||||
<div class="controls">
|
||||
<button matButton="filled" (click)="visualizeDijkstra()">{{ 'PATHFINDING.DIJKSTRA' | translate }}</button>
|
||||
<button matButton="filled" (click)="visualizeAStar()">{{ 'PATHFINDING.ASTAR' | translate }}</button>
|
||||
</div>
|
||||
<div class="controls">
|
||||
<button matButton="filled" (click)="normalCase()">{{ 'PATHFINDING.NORMAL_CASE' | translate }}</button>
|
||||
<button matButton="filled" (click)="edgeCase()">{{ 'PATHFINDING.EDGE_CASE' | translate }}</button>
|
||||
<button matButton="filled" (click)="clearBoard()">{{ 'PATHFINDING.CLEAR_BOARD' | translate }}</button>
|
||||
</div>
|
||||
|
||||
<div class="controls">
|
||||
<mat-button-toggle-group [(ngModel)]="selectedNodeType" aria-label="Node Type Selection">
|
||||
<mat-button-toggle [value]="NodeType.Start">{{ 'PATHFINDING.START_NODE' | translate }}</mat-button-toggle>
|
||||
@@ -25,14 +39,6 @@
|
||||
</mat-button-toggle-group>
|
||||
</div>
|
||||
|
||||
<div class="controls">
|
||||
<button matButton="filled" (click)="visualizeDijkstra()">{{ 'PATHFINDING.DIJKSTRA' | translate }}</button>
|
||||
<button matButton="filled" (click)="visualizeAStar()">{{ 'PATHFINDING.ASTAR' | translate }}</button>
|
||||
<button matButton="filled" (click)="normalCase()">{{ 'PATHFINDING.NORMAL_CASE' | translate }}</button>
|
||||
<button matButton="filled" (click)="edgeCase()">{{ 'PATHFINDING.EDGE_CASE' | translate }}</button>
|
||||
<button matButton="filled" (click)="clearBoard()">{{ 'PATHFINDING.CLEAR_BOARD' | translate }}</button>
|
||||
</div>
|
||||
|
||||
<div class="controls">
|
||||
<div class="grid-size">
|
||||
<mat-form-field appearance="outline" class="grid-field">
|
||||
|
||||
@@ -163,6 +163,8 @@ export class PathfindingComponent implements AfterViewInit {
|
||||
|
||||
// Mouse interactions
|
||||
private onMouseDown(event: MouseEvent): void {
|
||||
this.stopAnimations();
|
||||
this.clearPath();
|
||||
const pos = this.getGridPosition(event);
|
||||
if (!pos) {
|
||||
return;
|
||||
@@ -263,7 +265,8 @@ export class PathfindingComponent implements AfterViewInit {
|
||||
isPath: false,
|
||||
distance: Infinity,
|
||||
previousNode: null,
|
||||
fScore: 0
|
||||
hScore: 0,
|
||||
fScore: Infinity,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@ export interface Node {
|
||||
distance: number;
|
||||
previousNode: Node | null;
|
||||
fScore: number;
|
||||
hScore: number;
|
||||
}
|
||||
|
||||
export const DEFAULT_GRID_ROWS = 50;
|
||||
|
||||
@@ -80,9 +80,9 @@ export class PathfindingService {
|
||||
aStar(grid: Node[][], startNode: Node, endNode: Node): { visitedNodesInOrder: Node[], nodesInShortestPathOrder: Node[] } {
|
||||
const visitedNodesInOrder: Node[] = [];
|
||||
startNode.distance = 0;
|
||||
startNode['distance'] = this.calculateHeuristic(startNode, endNode);
|
||||
startNode['hScore'] = this.calculateHeuristic(startNode, endNode);
|
||||
// fScore = gScore + hScore
|
||||
startNode['fScore'] = startNode.distance + startNode['distance'];
|
||||
startNode['fScore'] = startNode.distance + startNode['hScore'];
|
||||
|
||||
const openSet: Node[] = [startNode];
|
||||
const allNodes = this.getAllNodes(grid);
|
||||
@@ -90,7 +90,7 @@ export class PathfindingService {
|
||||
this.initNodesForAStar(allNodes, startNode);
|
||||
|
||||
while (openSet.length > 0) {
|
||||
openSet.sort((nodeA, nodeB) => nodeA['fScore'] - nodeB['fScore']);
|
||||
this.sortOpenSet(openSet);
|
||||
const currentNode = openSet.shift() as Node;
|
||||
|
||||
if (currentNode.isWall) {
|
||||
@@ -125,11 +125,22 @@ export class PathfindingService {
|
||||
return { visitedNodesInOrder, nodesInShortestPathOrder: [] };
|
||||
}
|
||||
|
||||
private sortOpenSet(openSet: Node[]) {
|
||||
openSet.sort((a, b) => {
|
||||
const f = a['fScore'] - b['fScore'];
|
||||
if (f !== 0) return f;
|
||||
|
||||
// tie-break: smaller heuristic first (more goal-directed)
|
||||
return (a['hScore'] ?? 0) - (b['hScore'] ?? 0);
|
||||
});
|
||||
}
|
||||
|
||||
private updateNeighborNode(neighbor: Node, currentNode: Node, tentativeGScore: number, endNode: Node, openSet: Node[]) {
|
||||
neighbor.previousNode = currentNode;
|
||||
neighbor.distance = tentativeGScore;
|
||||
neighbor['distance'] = this.calculateHeuristic(neighbor, endNode);
|
||||
neighbor['fScore'] = neighbor.distance + neighbor['distance'];
|
||||
neighbor['hScore'] = this.calculateHeuristic(neighbor, endNode);
|
||||
neighbor['fScore'] = neighbor.distance + neighbor['hScore'];
|
||||
|
||||
if (!openSet.includes(neighbor)) {
|
||||
openSet.push(neighbor);
|
||||
|
||||
@@ -299,10 +299,10 @@
|
||||
"END_NODE": "Endknoten",
|
||||
"WALL": "Wand",
|
||||
"CLEAR_NODE": "Löschen",
|
||||
"DIJKSTRA": "Dijkstra",
|
||||
"ASTAR": "A*",
|
||||
"DIJKSTRA": "Start Dijkstra",
|
||||
"ASTAR": "Start A*",
|
||||
"NORMAL_CASE": "Testaufbau",
|
||||
"EDGE_CASE": "A* Grenzfall",
|
||||
"EDGE_CASE": "A* Grenzfall-Aufbau",
|
||||
"CLEAR_BOARD": "Board leeren",
|
||||
"VISITED": "Besucht",
|
||||
"PATH": "Pfad",
|
||||
@@ -311,7 +311,9 @@
|
||||
"EXPLANATION": {
|
||||
"TITLE": "Algorithmen",
|
||||
"DIJKSTRA_EXPLANATION": " findet garantiert den kürzesten Weg, wenn alle Kantenkosten nicht-negativ sind. Vorteil: optimal und ohne Heuristik. Nachteil: besucht oft sehr viele Knoten (kann bei großen Grids langsamer wirken).",
|
||||
"ASTAR_EXPLANATION": " erweitert Dijkstra um eine Heuristik (z.B. Manhattan-Distanz) und kann dadurch wesentlich zielgerichteter suchen. Vorteil: oft deutlich schneller bei guter Heuristik; bei zulässiger Heuristik bleibt der Weg optimal. Nachteil: hängt stark von der Heuristik ab (schlechte Heuristik ≈ Dijkstra)."
|
||||
"ASTAR_EXPLANATION": " erweitert Dijkstra um eine Heuristik (z.B. Manhattan-Distanz) und kann dadurch wesentlich zielgerichteter suchen. Vorteil: oft deutlich schneller bei guter Heuristik; bei zulässiger Heuristik bleibt der Weg optimal. Nachteil: hängt stark von der Heuristik ab (schlechte Heuristik ≈ Dijkstra).",
|
||||
"NOTE": "HINWEIS",
|
||||
"DISCLAIMER": "Diese A*-Implementierung ist bewusst einfach gehalten. Es wird nur in vier Richtungen gegangen und jeder Schritt kostet 1. Die Heuristik ist minimal und dient nur dazu, das Prinzip von A* gegenüber Dijkstra zu demonstrieren. Ziel ist nicht ein optimaler oder produktionsreifer A*-Algorithmus, sondern eine anschauliche Visualisierung, wie Heuristiken die Suche beschleunigen können."
|
||||
},
|
||||
"ALERT": {
|
||||
"START_END_NODES": "Bitte wählen Sie einen Start- und Endknoten aus, bevor Sie den Algorithmus starten."
|
||||
|
||||
@@ -299,10 +299,10 @@
|
||||
"END_NODE": "End Node",
|
||||
"WALL": "Wall",
|
||||
"CLEAR_NODE": "Clear",
|
||||
"DIJKSTRA": "Dijkstra",
|
||||
"ASTAR": "A*",
|
||||
"DIJKSTRA": "Start Dijkstra",
|
||||
"ASTAR": "Start A*",
|
||||
"NORMAL_CASE": "Test Scenario",
|
||||
"EDGE_CASE": "A* Edge Case",
|
||||
"EDGE_CASE": "A* Edge Case Scenario",
|
||||
"CLEAR_BOARD": "Clear Board",
|
||||
"VISITED": "Visited",
|
||||
"PATH": "Path",
|
||||
@@ -311,7 +311,9 @@
|
||||
"EXPLANATION": {
|
||||
"TITLE": "Algorithms",
|
||||
"DIJKSTRA_EXPLANATION": " is guaranteed to find the shortest path if all edge costs are non-negative. Advantage: optimal and without heuristics. Disadvantage: often visits a large number of nodes (can be slower for large grids).",
|
||||
"ASTAR_EXPLANATION": " extends Dijkstra with a heuristic (e.g. Manhattan distance) and can therefore search in a much more targeted manner. Advantage: often significantly faster with good heuristics; with permissible heuristics, the path remains optimal. Disadvantage: highly dependent on heuristics (poor heuristics ≈ Dijkstra)."
|
||||
"ASTAR_EXPLANATION": " extends Dijkstra with a heuristic (e.g. Manhattan distance) and can therefore search in a much more targeted manner. Advantage: often significantly faster with good heuristics; with permissible heuristics, the path remains optimal. Disadvantage: highly dependent on heuristics (poor heuristics ≈ Dijkstra).",
|
||||
"NOTE": "Note",
|
||||
"DISCLAIMER": "This A* implementation is deliberately kept simple. It only moves in four directions and each step costs 1. The heuristic is minimal and only serves to demonstrate the principle of A* compared to Dijkstra. The goal is not an optimal or production-ready A* algorithm, but a clear visualisation of how heuristics can speed up the search."
|
||||
},
|
||||
"ALERT": {
|
||||
"START_END_NODES": "Please select a start and end node before running the algorithm."
|
||||
|
||||
Reference in New Issue
Block a user