diff --git a/src/app/pages/algorithms/pathfinding/pathfinding.component.html b/src/app/pages/algorithms/pathfinding/pathfinding.component.html
index 1c1c6b4..e6866d4 100644
--- a/src/app/pages/algorithms/pathfinding/pathfinding.component.html
+++ b/src/app/pages/algorithms/pathfinding/pathfinding.component.html
@@ -27,9 +27,10 @@
-
-
-
+
+
+
+
diff --git a/src/app/pages/algorithms/pathfinding/pathfinding.component.ts b/src/app/pages/algorithms/pathfinding/pathfinding.component.ts
index fcfd433..9f14bb3 100644
--- a/src/app/pages/algorithms/pathfinding/pathfinding.component.ts
+++ b/src/app/pages/algorithms/pathfinding/pathfinding.component.ts
@@ -9,7 +9,7 @@ import {MatInputModule} from '@angular/material/input';
import {TranslateModule, TranslateService} from '@ngx-translate/core';
-import {DEFAULT_GRID_COLS, DEFAULT_GRID_ROWS, MAX_GRID_PX, MAX_GRID_SIZE, MIN_GRID_SIZE, Node} from './pathfinding.models';
+import {DEFAULT_GRID_COLS, DEFAULT_GRID_ROWS, MAX_GRID_PX, MAX_GRID_SIZE, MAX_RANDOM_WALLS_FACTORS, MIN_GRID_SIZE, Node} from './pathfinding.models';
import {PathfindingService} from './service/pathfinding.service';
import {UrlConstants} from '../../../constants/UrlConstants';
import {MatCard, MatCardContent, MatCardHeader, MatCardTitle} from '@angular/material/card';
@@ -70,7 +70,7 @@ export class PathfindingComponent implements AfterViewInit {
private shouldAddWall = true;
animationSpeed = 3;
- pathLength = 0;
+ pathLength = "0";
executionTime = 0;
private timeoutIds: number[] = [];
@@ -103,35 +103,28 @@ export class PathfindingComponent implements AfterViewInit {
applyGridSize(skipReset?: boolean): void {
this.gridRows = this.clampGridSize(this.gridRows, DEFAULT_GRID_ROWS);
this.gridCols = this.clampGridSize(this.gridCols, DEFAULT_GRID_COLS);
-
this.nodeSize = this.computeNodeSize(this.gridRows, this.gridCols);
this.resizeCanvas();
- if (skipReset) {
- this.initializeGrid(true, 'edge');
+ if (this.gridRows === this.grid.length && this.gridCols === this.grid[0].length)
+ {
this.drawGrid();
return;
}
- // Default after size changes: pick one consistent scenario
- this.normalCase();
+ if (skipReset) {
+ this.initializeGrid({withWalls: true, scenario: 'normal'});
+ this.drawGrid();
+ return;
+ }
+
+ this.createCase({withWalls: true, scenario: 'normal'});
}
- normalCase(): void {
+ createCase({withWalls, scenario}: { withWalls: boolean, scenario: "normal" | "edge" | "random" }): void
+ {
this.stopAnimations();
- this.initializeGrid(true, 'normal');
- this.drawGrid();
- }
-
- edgeCase(): void {
- this.stopAnimations();
- this.initializeGrid(true, 'edge');
- this.drawGrid();
- }
-
- clearBoard(): void {
- this.stopAnimations();
- this.initializeGrid(false, 'edge');
+ this.initializeGrid({withWalls, scenario});
this.drawGrid();
}
@@ -167,8 +160,15 @@ export class PathfindingComponent implements AfterViewInit {
}
const endTime = performance.now();
-
- this.pathLength = result.nodesInShortestPathOrder.length;
+ const lengthOfShortestPath = result.nodesInShortestPathOrder.length;
+ if (lengthOfShortestPath === 0)
+ {
+ this.pathLength = "∞"
+ }
+ else
+ {
+ this.pathLength = result.nodesInShortestPathOrder.length + "";
+ }
this.executionTime = endTime - startTime;
this.animateAlgorithm(result.visitedNodesInOrder, result.nodesInShortestPathOrder);
@@ -238,7 +238,7 @@ export class PathfindingComponent implements AfterViewInit {
}
// Grid init
- private initializeGrid(withWalls: boolean, scenario: 'normal' | 'edge'): void {
+ private initializeGrid({withWalls, scenario}: { withWalls: boolean, scenario: "normal" | "edge" | "random" }): void {
this.grid = this.createEmptyGrid();
const { start, end } = this.getScenarioStartEnd(scenario);
@@ -283,29 +283,81 @@ export class PathfindingComponent implements AfterViewInit {
};
}
- private getScenarioStartEnd(scenario: 'normal' | 'edge'): { start: GridPos; end: GridPos } {
+ private getScenarioStartEnd(scenario: 'normal' | 'edge' | 'random'): { start: GridPos; end: GridPos } {
if (scenario === 'edge') {
return {
start: { row: 0, col: 0 },
end: { row: this.gridRows - 1, col: this.gridCols - 1 }
};
}
+ else if (scenario === 'random') {
+ return this.createRandomStartEndPosition();
+ }
+ else {
+ // normal: mid-left -> mid-right
+ const midRow = Math.floor(this.gridRows / 2);
+ return {
+ start: { row: midRow, col: 0 },
+ end: { row: midRow, col: this.gridCols - 1 }
+ };
+ }
+ }
+
+ private createRandomStartEndPosition() {
+ const midCol = Math.floor(this.gridCols / 2);
+
+ const startRow: number = this.randomIntFromInterval(0, this.gridRows - 1);
+ const startCol: number = this.randomIntFromInterval(0, this.gridCols - 1);
+
+ const endRow: number = this.randomIntFromInterval(0, this.gridRows - 1);
+ let endCol: number;
+
+ if (startCol <= midCol) {
+ endCol = this.randomIntFromInterval(midCol + 1, this.gridCols - 1);
+ } else {
+ endCol = this.randomIntFromInterval(0, midCol);
+ }
- // normal: mid-left -> mid-right
- const midRow = Math.floor(this.gridRows / 2);
return {
- start: { row: midRow, col: 0 },
- end: { row: midRow, col: this.gridCols - 1 }
+ start: {row: startRow, col: startCol},
+ end: {row: endRow, col: endCol}
};
}
- private placeDefaultDiagonalWall(scenario: 'normal' | 'edge'): void {
+ private placeDefaultDiagonalWall(scenario: 'normal' | 'edge' | 'random'): void {
if (scenario === 'edge') {
this.createDiagonalWall();
}
else if (scenario === 'normal') {
this.createVerticalWall();
}
+ else if (scenario === 'random') {
+ this.createRandomWalls();
+ }
+ }
+
+ private createRandomWalls(){
+ const maxNumberOfWalls = Math.floor(MAX_RANDOM_WALLS_FACTORS * this.gridCols * this.gridRows);
+
+ for (let wall = 0; wall < maxNumberOfWalls; wall++) {
+
+ const row: number = this.randomIntFromInterval(0, this.gridRows - 1);
+ const col: number = this.randomIntFromInterval(0, this.gridCols - 1);
+
+ if (!this.isValidPosition(row, col)) {
+ wall--;
+ continue;
+ }
+
+ const node = this.grid[row][col];
+ if (node.isStart || node.isEnd) {
+ wall--;
+ continue;
+ }
+
+ node.isWall = true;
+ }
+
}
private createVerticalWall() {
@@ -587,5 +639,9 @@ export class PathfindingComponent implements AfterViewInit {
return ctx;
}
+ private randomIntFromInterval(min: number, max: number): number {
+ return Math.floor(Math.random() * (max - min + 1) + min);
+ }
+
protected readonly UrlConstants = UrlConstants;
}
diff --git a/src/app/pages/algorithms/pathfinding/pathfinding.models.ts b/src/app/pages/algorithms/pathfinding/pathfinding.models.ts
index b5fb259..7d34f94 100644
--- a/src/app/pages/algorithms/pathfinding/pathfinding.models.ts
+++ b/src/app/pages/algorithms/pathfinding/pathfinding.models.ts
@@ -20,3 +20,4 @@ export const MAX_GRID_SIZE = 150;
// Canvas max size (px)
export const MAX_GRID_PX = 1000;
+export const MAX_RANDOM_WALLS_FACTORS = 0.3;
diff --git a/src/assets/i18n/de.json b/src/assets/i18n/de.json
index 11c0298..72d2b97 100644
--- a/src/assets/i18n/de.json
+++ b/src/assets/i18n/de.json
@@ -303,7 +303,8 @@
"ASTAR": "Start A*",
"NORMAL_CASE": "Testaufbau",
"EDGE_CASE": "A* Grenzfall-Aufbau",
- "CLEAR_BOARD": "Board leeren",
+ "RANDOM_CASE": "Zufälliger-Aufbau",
+ "CLEAR_BOARD": "Leeres Gitter",
"VISITED": "Besucht",
"PATH": "Pfad",
"PATH_LENGTH": "Pfadlänge",
diff --git a/src/assets/i18n/en.json b/src/assets/i18n/en.json
index 7e754c2..181aecf 100644
--- a/src/assets/i18n/en.json
+++ b/src/assets/i18n/en.json
@@ -303,7 +303,8 @@
"ASTAR": "Start A*",
"NORMAL_CASE": "Test Scenario",
"EDGE_CASE": "A* Edge Case Scenario",
- "CLEAR_BOARD": "Clear Board",
+ "RANDOM_CASE": "Random Case",
+ "CLEAR_BOARD": "Empty Board",
"VISITED": "Visited",
"PATH": "Path",
"PATH_LENGTH": "Path length",