Fix: Clean up code

Removing unused comment, refactor and remove some unused script
This commit is contained in:
Bobby Rafael
2025-07-17 12:04:03 +07:00
parent 083b9b33b6
commit 2ccba85268
14 changed files with 148 additions and 2453 deletions

View File

@ -2,12 +2,16 @@ using UnityEngine;
public class FrameLimiter : MonoBehaviour
{
// Start is called before the first frame update
/// <summary>
/// Melimit frame rate game ke 60 FPS
/// Limit dilakukan agar kalkulasi CPU yang digunakan sesuai dengan target FPS
/// </summary>
[SerializeField] private int frameRate = 60;
private int vSyncValue = 0;
void Start()
{
// Set the target frame rate to 60
QualitySettings.vSyncCount = 0;
QualitySettings.vSyncCount = vSyncValue;
Application.targetFrameRate = frameRate;
}
}

File diff suppressed because it is too large Load Diff

View File

@ -9,42 +9,18 @@ using UnityEngine;
/// </summary>
public class GridNode : PathFinding.Node<Vector2Int>
{
/// <summary>
/// Menentukan apakah node ini dapat dilalui oleh karakter.
/// True jika node dapat dilalui, false jika node adalah penghalang.
/// </summary>
public bool IsWalkable { get; set; }
public bool IsWalkable { get; set; }
/// <summary>
/// Referensi ke GridMap yang mengelola seluruh grid.
/// Digunakan untuk mendapatkan tetangga dan operasi lain yang berhubungan dengan grid.
/// </summary>
public GridMap gridMap; // Change to internal or public
internal GridMap gridMap;
/// <summary>
/// Constructor untuk membuat GridNode baru.
/// </summary>
/// <param name="value">Koordinat Vector2Int yang merepresentasikan posisi node di dalam grid</param>
/// <param name="gridMap">Referensi ke GridMap yang mengelola grid ini</param>
public GridNode(Vector2Int value, GridMap gridMap)
: base(value)
{
IsWalkable = true; // Secara default node dapat dilalui
this.gridMap = gridMap; // Simpan referensi ke GridMap
}
public GridNode(Vector2Int value, GridMap gridMap) : base(value)
{
IsWalkable = true;
this.gridMap = gridMap;
}
/// <summary>
/// Mengimplementasikan metode abstrak dari kelas dasar untuk mendapatkan daftar node tetangga.
/// Metode ini akan memanggil GridMap.GetNeighbours() untuk mendapatkan semua node tetangga yang dapat dilalui.
/// </summary>
/// <returns>Daftar node tetangga yang dapat dicapai dari node ini</returns>
public override
List<PathFinding.Node<Vector2Int>> GetNeighbours()
{
// Return an empty list for now.
// Later we will call gridMap's GetNeighbours
// function.
//return new List<PathFinding.Node<Vector2Int>>();
return gridMap.GetNeighbours(this);
}
public override List<PathFinding.Node<Vector2Int>> GetNeighbours()
{
return gridMap.GetNeighbours(this);
}
}

View File

@ -6,36 +6,19 @@ using UnityEngine;
/// </summary>
public class GridNodeView : MonoBehaviour
{
/// <summary>
/// Referensi ke SpriteRenderer untuk bagian dalam node.
/// </summary>
[SerializeField]
SpriteRenderer innerSprite;
/// <summary>
/// Referensi ke SpriteRenderer untuk bagian luar node.
/// </summary>
[SerializeField]
SpriteRenderer outerSprite;
/// <summary>
/// Properti yang menyimpan referensi ke objek GridNode yang terkait dengan view ini.
/// </summary>
public GridNode Node { get; set; }
/// <summary>
/// Mengatur warna sprite bagian dalam dari node.
/// </summary>
/// <param name="col">Warna yang akan diaplikasikan pada sprite bagian dalam.</param>
public void SetInnerColor(Color col)
{
innerSprite.color = col;
}
/// <summary>
/// Mengatur warna sprite bagian luar dari node.
/// </summary>
/// <param name="col">Warna yang akan diaplikasikan pada sprite bagian luar.</param>
public void SetOuterColor(Color col)
{
outerSprite.color = col;

View File

@ -5,19 +5,20 @@ using System.Collections.Generic;
using System.Diagnostics;
using UnityEngine;
/// <summary>
/// Metrik yang digunakan untuk mengukur performa pathfinding.
/// Dibuat dalam bentuk struct untuk efisiensi memori dan kemudahan penggunaan.
/// </summary>
public struct PathfindingMetrics
{
// Untuk Pengukuran Kinerja
public float timeTaken; // in milliseconds
public float timeTaken; // miliseconds
public int pathLength;
public int nodesExplored; // number of nodes in path
public long memoryUsed; // memory used by pathfinding in bytes
public int nodesExplored;
public long memoryUsed; // bytes
// Untuk Visualisasi
public int maxOpenListSize; // maximum size of open list during pathfinding
public int maxClosedListSize; // maximum size of closed list during pathfinding
public int maxOpenListSize;
public int maxClosedListSize;
// Tambahan untuk cost metrics
public float totalGCost; // Total biaya G untuk jalur (jarak sebenarnya)
public float totalHCost; // Total biaya H untuk jalur (heuristik)
public float totalFCost; // Total biaya F untuk jalur (G + H)
@ -31,16 +32,10 @@ public class NPC : MonoBehaviour
{
public float speed = 2.0f;
public Queue<Vector2> wayPoints = new Queue<Vector2>();
// Event that fires when pathfinding is complete with performance metrics
public event Action<PathfindingMetrics> OnPathfindingComplete;
// Last measured memory usage (for accessing from outside)
public event Action<PathfindingMetrics> OnPathfindingComplete;
public long LastMeasuredMemoryUsage { get; private set; } = 0;
/// <summary>
/// Enumerasi yang merepresentasikan berbagai algoritma pathfinding yang tersedia.
/// </summary>
public enum PathFinderType
{
ASTAR,
@ -57,36 +52,21 @@ public class NPC : MonoBehaviour
public GridMap Map { get; set; }
// List to store all steps for visualization playback
private List<PathfindingVisualizationStep> visualizationSteps = new List<PathfindingVisualizationStep>();
private bool isVisualizingPath = false;
private bool isMoving = false;
// Public accessor for visualization state
public bool IsVisualizingPath => isVisualizingPath;
// Public accessor for movement state
public bool IsMoving => isMoving;
// Event that fires when visualization is complete
public event Action OnVisualizationComplete;
// Event that fires when movement is complete
public event Action OnMovementComplete;
// Properties to control visualization
[SerializeField]
public float visualizationSpeed = 0.0f;
public int visualizationBatch = 1;
// Visualization speed is time between visualization steps
public float visualizationSpeed = 0.0f; // Default 0; set higher for slower visualization
public bool showVisualization = true;
// Visualization batch is the number of steps to visualize at once
public int visualizationBatch = 1; // Default 1; set higher value for faster visualization
[SerializeField]
public bool showVisualization = true; // Whether to show visualization at all
// Struct to store each step of the pathfinding process for visualization
private struct PathfindingVisualizationStep
{
public enum StepType { CurrentNode, OpenList, ClosedList, FinalPath }
@ -132,27 +112,25 @@ public class NPC : MonoBehaviour
{
while (wayPoints.Count > 0)
{
// Set the moving flag when starting to move
if (!isMoving && wayPoints.Count > 0)
{
isMoving = true;
UnityEngine.Debug.Log("NPC movement started");
}
yield return StartCoroutine(
Coroutine_MoveToPoint(
wayPoints.Dequeue(),
speed));
}
// If we were moving but now have no more waypoints, signal movement completion
if (isMoving && wayPoints.Count == 0)
{
isMoving = false;
UnityEngine.Debug.Log("NPC movement complete, invoking OnMovementComplete event");
OnMovementComplete?.Invoke();
}
yield return null;
}
}
@ -163,7 +141,6 @@ public class NPC : MonoBehaviour
node.Value.x * Map.GridNodeWidth,
node.Value.y * Map.GridNodeHeight));
// We set a color to show the path.
GridNodeView gnv = Map.GetGridNodeView(node.Value.x, node.Value.y);
gnv.SetInnerColor(Map.COLOR_PATH);
}
@ -179,26 +156,20 @@ public class NPC : MonoBehaviour
private void Start()
{
// Initialize pathfinder based on type
InitializePathFinder();
// Start the movement coroutine
StartCoroutine(Coroutine_MoveTo());
}
private void InitializePathFinder()
{
// Hitung perkiraan jumlah node dalam grid
int estimatedNodeCount = 0;
if (Map != null)
{
estimatedNodeCount = Map.NumX * Map.NumY;
}
// Log informasi ukuran grid dan strategi optimisasi
bool isLargeGrid = estimatedNodeCount > 2500;
// Create new pathfinder instance
switch (pathFinderType)
{
case PathFinderType.ASTAR:
@ -218,24 +189,20 @@ public class NPC : MonoBehaviour
break;
}
// Set up callbacks
pathFinder.onSuccess = OnSuccessPathFinding;
pathFinder.onFailure = OnFailurePathFinding;
// Gunakan setting asli
pathFinder.HeuristicCost = GridMap.GetManhattanCost;
pathFinder.NodeTraversalCost = GridMap.GetEuclideanCost;
}
public void MoveTo(GridNode destination, bool silentMode = false)
{
// inialisaasi pathfinder jika belum ada
if (pathFinder == null)
{
InitializePathFinder();
}
if (pathFinder.Status == PathFinderStatus.RUNNING)
{
return;
@ -252,7 +219,6 @@ public class NPC : MonoBehaviour
SetStartNode(start);
// Reset grid colors
if (!silentMode)
{
Map.ResetGridNodeColours();
@ -261,7 +227,6 @@ public class NPC : MonoBehaviour
visualizationSteps.Clear();
isVisualizingPath = false;
// jika gagal menginisialisasi pathfinder, tidak perlu melanjutkan
if (!pathFinder.Initialise(start, destination))
{
return;
@ -274,9 +239,7 @@ public class NPC : MonoBehaviour
{
yield return StartCoroutine(MeasurePerformance(silentMode));
// Start visualization after calculation is complete regardless of success or failure
// This allows visualization of the explored area even when no path is found
if (showVisualization && !silentMode &&
if (showVisualization && !silentMode &&
(pathFinder.Status == PathFinderStatus.SUCCESS || pathFinder.Status == PathFinderStatus.FAILURE))
{
yield return StartCoroutine(VisualizePathfinding());
@ -285,71 +248,54 @@ public class NPC : MonoBehaviour
IEnumerator MeasurePerformance(bool silentMode = false)
{
// Memory tracking for pathfinding structures - tetap untuk visualisasi
int maxOpenListSize = 0;
int currentOpenListSize = 0;
int maxClosedListSize = 0;
int currentClosedListSize = 0;
// Pre-allocate visualizationSteps with estimated capacity to avoid reallocations
visualizationSteps = new List<PathfindingVisualizationStep>(4);
//GC.Collect(2, GCCollectionMode.Forced, true, true);
//GC.WaitForPendingFinalizers(); // Tunggu semua finalizers selesai
// ===== MEMORY MEASUREMENT START: Ukur memory sebelum algoritma =====
long memoryBefore = System.GC.GetTotalMemory(false);
// Setup callbacks before running algorithm
SetupCallbacks(silentMode, ref maxOpenListSize, ref currentOpenListSize,
ref maxClosedListSize, ref currentClosedListSize);
// ===== STOPWATCH START: Pengukuran waktu algoritma =====
Stopwatch algorithmTimer = Stopwatch.StartNew();
// Counter untuk jumlah step yang dilakukan algoritma
int stepCount = 0;
// Execute the pathfinding algorithm synchronously in a single frame without visualization
while (pathFinder.Status == PathFinderStatus.RUNNING)
{
stepCount++;
pathFinder.Step();
}
// ===== STOPWATCH STOP: Akhir pengukuran waktu algoritma =====
algorithmTimer.Stop();
// ===== MEMORY MEASUREMENT END: Ukur memory setelah algoritma =====
long memoryAfter = System.GC.GetTotalMemory(false);
long memoryUsed = memoryAfter - memoryBefore;
// Store the memory usage for external access
LastMeasuredMemoryUsage = memoryUsed > 0 ? memoryUsed : 1024;
float milliseconds = (algorithmTimer.ElapsedTicks * 1000.0f) / Stopwatch.Frequency;
// Calculate path length once and reuse
int pathLength = 0;
int nodesExplored = 0;
float totalGCost = 0;
float totalHCost = 0;
float totalFCost = 0;
// Add memory for path reconstruction (final path)
if (pathFinder.Status == PathFinderStatus.SUCCESS)
{
pathLength = CalculatePathLength();
nodesExplored = pathFinder.ClosedListCount;
// Hitung total G, H, dan F cost
CalculatePathCosts(out totalGCost, out totalHCost, out totalFCost);
}
// Create and send metrics - waktu pengukuran algoritma yang tepat
PathfindingMetrics metrics = new PathfindingMetrics
{
timeTaken = milliseconds, // Waktu algoritma yang diukur dengan stopwatch
timeTaken = milliseconds,
pathLength = pathLength,
nodesExplored = nodesExplored,
memoryUsed = memoryUsed,
@ -360,25 +306,20 @@ public class NPC : MonoBehaviour
totalFCost = totalFCost,
};
// *** IMPORTANT FIX: Always invoke the event, regardless of silent mode ***
// Report metrics before visualization
OnPathfindingComplete?.Invoke(metrics);
// Path visualization and handling
HandlePathFindingResult(silentMode, pathLength);
// Pastikan untuk mengembalikan nilai di akhir coroutine
yield return null;
}
/// <summary>
/// Setup callbacks for tracking nodes in open/closed lists and visualization
/// </summary>
private void SetupCallbacks(bool silentMode, ref int maxOpenListSize, ref int currentOpenListSize,
ref int maxClosedListSize, ref int currentClosedListSize)
private void SetupCallbacks(
bool silentMode,
ref int maxOpenListSize,
ref int currentOpenListSize,
ref int maxClosedListSize,
ref int currentClosedListSize)
{
// Buat variabel lokal untuk menghindari masalah dengan ref parameter dalam lambda
int localCurrentOpenListSize = currentOpenListSize;
int localMaxOpenListSize = maxOpenListSize;
int localCurrentClosedListSize = currentClosedListSize;
@ -386,7 +327,6 @@ public class NPC : MonoBehaviour
if (silentMode)
{
// In silent mode, just set minimal callbacks for metrics
pathFinder.onAddToOpenList = (node) =>
{
localCurrentOpenListSize++;
@ -399,12 +339,11 @@ public class NPC : MonoBehaviour
localCurrentClosedListSize++;
if (localCurrentClosedListSize > localMaxClosedListSize)
localMaxClosedListSize = localCurrentClosedListSize;
localCurrentOpenListSize--; // When a node is moved from open to closed list
localCurrentOpenListSize--;
};
}
else
{
// In regular mode, track and prepare for visualization
pathFinder.onAddToOpenList = (node) =>
{
visualizationSteps.Add(new PathfindingVisualizationStep(
@ -426,7 +365,7 @@ public class NPC : MonoBehaviour
if (localCurrentClosedListSize > localMaxClosedListSize)
localMaxClosedListSize = localCurrentClosedListSize;
localCurrentOpenListSize--; // When a node is moved from open to closed list
localCurrentOpenListSize--;
};
pathFinder.onChangeCurrentNode = (node) =>
@ -439,38 +378,29 @@ public class NPC : MonoBehaviour
}
// Setelah lambda selesai dijalankan, perbarui variabel ref
maxOpenListSize = localMaxOpenListSize;
currentOpenListSize = localCurrentOpenListSize;
maxClosedListSize = localMaxClosedListSize;
currentClosedListSize = localCurrentClosedListSize;
}
/// <summary>
/// Handle path finding result (success or failure)
/// </summary>
private void HandlePathFindingResult(bool silentMode, int pathLength)
{
if (pathFinder.Status == PathFinderStatus.SUCCESS)
{
OnSuccessPathFinding();
// In non-silent mode, prepare visualization data for the path
if (!silentMode && showVisualization)
{
// Add the path nodes for visualization in efficient batched way
PathFinder<Vector2Int>.PathFinderNode node = pathFinder.CurrentNode;
List<Vector2Int> pathPositions = new List<Vector2Int>(pathLength); // Pre-allocate with known size
List<Vector2Int> pathPositions = new List<Vector2Int>(pathLength);
// Build path in reverse order
while (node != null)
{
pathPositions.Add(node.Location.Value);
node = node.Parent;
}
// Process path in correct order
for (int i = pathPositions.Count - 1; i >= 0; i--)
{
visualizationSteps.Add(new PathfindingVisualizationStep(
@ -482,40 +412,19 @@ public class NPC : MonoBehaviour
else if (pathFinder.Status == PathFinderStatus.FAILURE)
{
OnFailurePathFinding();
// For failure case, we don't add any final path visualization steps
// The exploration steps (open/closed lists) are already added during the search
// and will be visualized to show what nodes were explored before failure
UnityEngine.Debug.Log($"Pathfinding failed - visualization will show {visualizationSteps.Count} exploration steps");
}
}
/// <summary>
/// Memformat ukuran byte menjadi string yang lebih mudah dibaca
/// </summary>
private string FormatBytes(long bytes)
{
string[] sizes = { "B", "KB", "MB", "GB" };
int order = 0;
double size = bytes;
while (size >= 1024 && order < sizes.Length - 1)
{
order++;
size = size / 1024;
}
return $"{size:0.##} {sizes[order]}";
}
void OnSuccessPathFinding()
{
float totalGCost = 0;
float totalHCost = 0;
float totalFCost = 0;
// Hitung biaya-biaya path menggunakan metode yang sudah ada
CalculatePathCosts(out totalGCost, out totalHCost, out totalFCost);
// Informasi dasar
int pathLength = CalculatePathLength();
}
@ -525,12 +434,8 @@ public class NPC : MonoBehaviour
UnityEngine.Debug.Log("Pathfinding failed");
}
/// <summary>
/// Changes the pathfinding algorithm at runtime
/// </summary>
public void ChangeAlgorithm(PathFinderType newType)
{
// Don't change if pathfinding is in progress
if (pathFinder != null && pathFinder.Status == PathFinderStatus.RUNNING)
{
UnityEngine.Debug.Log("Cannot change algorithm while pathfinding is running");
@ -539,14 +444,12 @@ public class NPC : MonoBehaviour
pathFinderType = newType;
// Hitung perkiraan jumlah node dalam grid
int estimatedNodeCount = 0;
if (Map != null)
{
estimatedNodeCount = Map.NumX * Map.NumY;
}
// Create new pathfinder instance
switch (pathFinderType)
{
case PathFinderType.ASTAR:
@ -566,11 +469,9 @@ public class NPC : MonoBehaviour
break;
}
// Set up callbacks
pathFinder.onSuccess = OnSuccessPathFinding;
pathFinder.onFailure = OnFailurePathFinding;
// Gunakan setting asli
pathFinder.HeuristicCost = GridMap.GetManhattanCost;
pathFinder.NodeTraversalCost = GridMap.GetEuclideanCost;
}
@ -594,17 +495,14 @@ public class NPC : MonoBehaviour
UnityEngine.Debug.Log("Path visualization starting");
isVisualizingPath = true;
// First, ensure grid is reset
Map.ResetGridNodeColours();
// Visualize each step with a delay - use batch processing for efficiency
int stepCount = visualizationSteps.Count;
int batchSize = Mathf.Min(visualizationBatch, stepCount); // set higher value for faster visualization
int batchSize = Mathf.Min(visualizationBatch, stepCount);
// Detect if pathfinding failed - we'll need to know this when processing steps
bool pathfindingFailed = pathFinder.Status == PathFinderStatus.FAILURE;
if (pathfindingFailed)
{
UnityEngine.Debug.Log($"Visualizing failed pathfinding attempt with {stepCount} steps");
@ -614,7 +512,6 @@ public class NPC : MonoBehaviour
{
int end = Mathf.Min(i + batchSize, stepCount);
// Process a batch of steps
for (int j = i; j < end; j++)
{
var step = visualizationSteps[j];
@ -634,7 +531,7 @@ public class NPC : MonoBehaviour
break;
case PathfindingVisualizationStep.StepType.FinalPath:
gnv.SetInnerColor(Map.COLOR_PATH);
// Only add waypoints for successful pathfinding
if (!pathfindingFailed)
{
GridNode pathNode = Map.GetGridNode(step.position.x, step.position.y);
@ -644,60 +541,39 @@ public class NPC : MonoBehaviour
}
}
}
// Yield after each batch to prevent frame drops
yield return new WaitForSeconds(visualizationSpeed);
}
isVisualizingPath = false;
UnityEngine.Debug.Log("Path visualization complete, invoking OnVisualizationComplete event");
// Notify any listeners that visualization is complete
OnVisualizationComplete?.Invoke();
}
/// <summary>
/// Menghitung biaya G, H, dan F untuk jalur
/// </summary>
private void CalculatePathCosts(out float totalGCost, out float totalHCost, out float totalFCost)
{
// Inisialisasi nilai awal
totalGCost = 0;
totalHCost = 0;
totalFCost = 0;
// Jika tidak ada path yang ditemukan, return nilai 0
if (pathFinder.CurrentNode == null)
return;
// Untuk algoritma yang menggunakan heuristik
bool usesHeuristic = pathFinderType == PathFinderType.ASTAR ||
pathFinderType == PathFinderType.GREEDY;
// Node final berisi total cost jalur
PathFinder<Vector2Int>.PathFinderNode finalNode = pathFinder.CurrentNode;
// G cost adalah biaya sebenarnya dari start ke goal, sudah terakumulasi di node akhir
totalGCost = finalNode.GCost;
// H cost di node final idealnya 0 (sudah di tujuan),
// tapi untuk info lengkap, kita dapat path's H cost dari node awal
if (usesHeuristic)
{
// H cost dari node awal ke tujuan (untuk referensi)
totalHCost = finalNode.HCost;
// F cost adalah G + H di node akhir
totalFCost = finalNode.FCost;
}
else
{
// Algoritma tanpa heuristik (seperti Dijkstra)
totalFCost = totalGCost;
}
//// Hitung rata-rata biaya per langkah untuk analisis
//int pathLength = CalculatePathLength();
//float avgCostPerStep = pathLength > 0 ? totalGCost / pathLength : 0;
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,419 +0,0 @@
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using UnityEngine;
using UnityEngine.UI;
using TMPro;
/// <summary>
/// Utility class to analyze pathfinding test results and display statistics
/// </summary>
public class PathfindingTestAnalyzer : MonoBehaviour
{
[Header("UI References")]
public TMP_Text resultsText;
public TMP_Dropdown algorithmFilterDropdown;
public TMP_Dropdown statisticTypeDropdown;
public RectTransform graphContainer;
public GameObject barPrefab;
[Header("File Settings")]
public string resultsFileName = "pathfinding_tests.csv";
// Data structures
private List<TestResult> allResults = new List<TestResult>();
private Dictionary<string, Color> algorithmColors = new Dictionary<string, Color>()
{
{ "ASTAR", Color.blue },
{ "DIJKSTRA", Color.green },
{ "GREEDY", Color.red },
{ "BACKTRACKING", Color.yellow },
{ "BFS", Color.magenta }
};
// Struct to hold a single test result
private struct TestResult
{
public string algorithm;
public int gridSizeX;
public int gridSizeY;
public float density;
public bool diagonalMovement;
public float timeTaken;
public int pathLength;
public int nodesExplored;
public long memoryUsed;
public bool pathFound;
public int testIndex;
}
void Start()
{
SetupDropdowns();
LoadResults();
// Set default visualization
if (allResults.Count > 0)
{
GenerateStatistics();
}
}
private void SetupDropdowns()
{
// Set up algorithm filter dropdown
algorithmFilterDropdown.ClearOptions();
algorithmFilterDropdown.AddOptions(new List<string> {
"All Algorithms",
"A*",
"Dijkstra",
"Greedy BFS",
"Backtracking",
"BFS"
});
algorithmFilterDropdown.onValueChanged.AddListener(OnFilterChanged);
// Set up statistic type dropdown
statisticTypeDropdown.ClearOptions();
statisticTypeDropdown.AddOptions(new List<string> {
"Execution Time",
"Path Length",
"Nodes Explored",
"Memory Used",
"Success Rate"
});
statisticTypeDropdown.onValueChanged.AddListener(OnFilterChanged);
}
private void LoadResults()
{
string directory = Path.Combine(Application.persistentDataPath, "TestResults");
string filePath = Path.Combine(directory, resultsFileName);
if (!File.Exists(filePath))
{
Debug.LogError($"Results file not found: {filePath}");
if (resultsText != null)
{
resultsText.text = "No test results found. Run tests first.";
}
return;
}
// Read all lines and skip header
string[] lines = File.ReadAllLines(filePath);
if (lines.Length <= 1)
{
Debug.LogWarning("Results file is empty or only contains a header");
return;
}
// Clear previous results
allResults.Clear();
// Skip header row and parse data rows
for (int i = 1; i < lines.Length; i++)
{
string line = lines[i];
if (string.IsNullOrWhiteSpace(line))
continue;
string[] values = line.Split(',');
if (values.Length < 10)
{
Debug.LogWarning($"Invalid data in line {i}: {line}");
continue;
}
TestResult result = new TestResult
{
algorithm = values[0],
gridSizeX = int.Parse(values[1]),
gridSizeY = int.Parse(values[2]),
density = float.Parse(values[3]),
diagonalMovement = bool.Parse(values[4]),
timeTaken = float.Parse(values[5]),
pathLength = int.Parse(values[6]),
nodesExplored = int.Parse(values[7]),
memoryUsed = long.Parse(values[8]),
pathFound = bool.Parse(values[9]),
testIndex = int.Parse(values[10])
};
allResults.Add(result);
}
Debug.Log($"Loaded {allResults.Count} test results");
}
public void OnFilterChanged(int value)
{
GenerateStatistics();
}
private void GenerateStatistics()
{
if (allResults.Count == 0)
return;
// Clear previous graph
foreach (Transform child in graphContainer)
{
Destroy(child.gameObject);
}
// Get selected algorithm filter
string algorithmFilter = "All";
switch (algorithmFilterDropdown.value)
{
case 0: algorithmFilter = "All"; break;
case 1: algorithmFilter = "ASTAR"; break;
case 2: algorithmFilter = "DIJKSTRA"; break;
case 3: algorithmFilter = "GREEDY"; break;
case 4: algorithmFilter = "BACKTRACKING"; break;
case 5: algorithmFilter = "BFS"; break;
}
// Filter results by algorithm if not "All"
List<TestResult> filteredResults = allResults;
if (algorithmFilter != "All")
{
filteredResults = allResults.Where(r => r.algorithm == algorithmFilter).ToList();
}
if (filteredResults.Count == 0)
{
resultsText.text = "No data for selected filters.";
return;
}
// Generate statistics based on selected metric
switch (statisticTypeDropdown.value)
{
case 0: // Execution Time
GenerateTimeStatistics(filteredResults);
break;
case 1: // Path Length
GeneratePathLengthStatistics(filteredResults);
break;
case 2: // Nodes Explored
GenerateNodesExploredStatistics(filteredResults);
break;
case 3: // Memory Used
GenerateMemoryStatistics(filteredResults);
break;
case 4: // Success Rate
GenerateSuccessRateStatistics(filteredResults);
break;
}
}
private void GenerateTimeStatistics(List<TestResult> results)
{
var averageTimeByAlgorithm = results
.GroupBy(r => r.algorithm)
.Select(g => new {
Algorithm = g.Key,
AverageTime = g.Average(r => r.timeTaken)
})
.OrderByDescending(x => x.AverageTime)
.ToList();
// Generate graph bars
CreateBarsForData(averageTimeByAlgorithm.Select(x => x.Algorithm).ToList(),
averageTimeByAlgorithm.Select(x => (float)x.AverageTime).ToList(),
"ms");
// Generate text summary
resultsText.text = "Average Execution Time by Algorithm:\n\n";
foreach (var stat in averageTimeByAlgorithm)
{
resultsText.text += $"{GetAlgorithmName(stat.Algorithm)}: {stat.AverageTime:F2} ms\n";
}
}
private void GeneratePathLengthStatistics(List<TestResult> results)
{
var averagePathByAlgorithm = results
.Where(r => r.pathFound) // Only include successful paths
.GroupBy(r => r.algorithm)
.Select(g => new {
Algorithm = g.Key,
AveragePath = g.Average(r => r.pathLength)
})
.OrderByDescending(x => x.AveragePath)
.ToList();
// Generate graph bars
CreateBarsForData(averagePathByAlgorithm.Select(x => x.Algorithm).ToList(),
averagePathByAlgorithm.Select(x => (float)x.AveragePath).ToList(),
"nodes");
// Generate text summary
resultsText.text = "Average Path Length by Algorithm:\n\n";
foreach (var stat in averagePathByAlgorithm)
{
resultsText.text += $"{GetAlgorithmName(stat.Algorithm)}: {stat.AveragePath:F2} nodes\n";
}
}
private void GenerateNodesExploredStatistics(List<TestResult> results)
{
var averageNodesExploredByAlgorithm = results
.GroupBy(r => r.algorithm)
.Select(g => new {
Algorithm = g.Key,
AverageNodes = g.Average(r => r.nodesExplored)
})
.OrderByDescending(x => x.AverageNodes)
.ToList();
// Generate graph bars
CreateBarsForData(averageNodesExploredByAlgorithm.Select(x => x.Algorithm).ToList(),
averageNodesExploredByAlgorithm.Select(x => (float)x.AverageNodes).ToList(),
"nodes");
// Generate text summary
resultsText.text = "Average Nodes Explored by Algorithm:\n\n";
foreach (var stat in averageNodesExploredByAlgorithm)
{
resultsText.text += $"{GetAlgorithmName(stat.Algorithm)}: {stat.AverageNodes:F0} nodes\n";
}
}
private void GenerateMemoryStatistics(List<TestResult> results)
{
var averageMemoryByAlgorithm = results
.GroupBy(r => r.algorithm)
.Select(g => new {
Algorithm = g.Key,
AverageMemory = g.Average(r => r.memoryUsed) / 1024.0f // Convert to KB
})
.OrderByDescending(x => x.AverageMemory)
.ToList();
// Generate graph bars
CreateBarsForData(averageMemoryByAlgorithm.Select(x => x.Algorithm).ToList(),
averageMemoryByAlgorithm.Select(x => (float)x.AverageMemory).ToList(),
"KB");
// Generate text summary
resultsText.text = "Average Memory Usage by Algorithm:\n\n";
foreach (var stat in averageMemoryByAlgorithm)
{
resultsText.text += $"{GetAlgorithmName(stat.Algorithm)}: {stat.AverageMemory:F2} KB\n";
}
}
private void GenerateSuccessRateStatistics(List<TestResult> results)
{
var successRateByAlgorithm = results
.GroupBy(r => r.algorithm)
.Select(g => new {
Algorithm = g.Key,
SuccessRate = g.Count(r => r.pathFound) * 100.0f / g.Count()
})
.OrderByDescending(x => x.SuccessRate)
.ToList();
// Generate graph bars
CreateBarsForData(successRateByAlgorithm.Select(x => x.Algorithm).ToList(),
successRateByAlgorithm.Select(x => (float)x.SuccessRate).ToList(),
"%");
// Generate text summary
resultsText.text = "Success Rate by Algorithm:\n\n";
foreach (var stat in successRateByAlgorithm)
{
resultsText.text += $"{GetAlgorithmName(stat.Algorithm)}: {stat.SuccessRate:F1}%\n";
}
}
private void CreateBarsForData(List<string> labels, List<float> values, string unit)
{
if (barPrefab == null || graphContainer == null || labels.Count == 0)
return;
float graphWidth = graphContainer.rect.width;
float graphHeight = graphContainer.rect.height;
float maxValue = values.Max();
float barWidth = graphWidth / (labels.Count + 1);
for (int i = 0; i < labels.Count; i++)
{
// Create bar
GameObject barObj = Instantiate(barPrefab, graphContainer);
RectTransform barRect = barObj.GetComponent<RectTransform>();
Image barImage = barObj.GetComponent<Image>();
// Calculate height based on value
float normalizedValue = values[i] / maxValue;
float barHeight = graphHeight * normalizedValue * 0.8f; // 80% of graph height max
// Position and size bar
barRect.anchoredPosition = new Vector2((i + 0.5f) * barWidth, barHeight / 2);
barRect.sizeDelta = new Vector2(barWidth * 0.8f, barHeight);
// Set bar color
string algorithm = labels[i];
if (algorithmColors.ContainsKey(algorithm))
barImage.color = algorithmColors[algorithm];
// Add label
GameObject labelObj = new GameObject($"Label_{labels[i]}");
labelObj.transform.SetParent(barObj.transform);
TMP_Text labelText = labelObj.AddComponent<TMP_Text>();
labelText.text = $"{values[i]:F1}{unit}";
labelText.fontSize = 12;
labelText.alignment = TextAlignmentOptions.Center;
labelText.color = Color.black;
RectTransform labelRect = labelObj.GetComponent<RectTransform>();
labelRect.anchoredPosition = new Vector2(0, barHeight + 10);
labelRect.sizeDelta = new Vector2(barWidth, 20);
// Add algorithm name label at bottom
GameObject nameObj = new GameObject($"Name_{labels[i]}");
nameObj.transform.SetParent(barObj.transform);
TMP_Text nameText = nameObj.AddComponent<TMP_Text>();
nameText.text = GetAlgorithmName(labels[i]);
nameText.fontSize = 10;
nameText.alignment = TextAlignmentOptions.Center;
nameText.color = Color.black;
RectTransform nameRect = nameObj.GetComponent<RectTransform>();
nameRect.anchoredPosition = new Vector2(0, -10);
nameRect.sizeDelta = new Vector2(barWidth, 20);
}
}
private string GetAlgorithmName(string algorithm)
{
switch (algorithm)
{
case "ASTAR": return "A*";
case "DIJKSTRA": return "Dijkstra";
case "GREEDY": return "Greedy";
case "BACKTRACKING": return "Backtracking";
case "BFS": return "BFS";
default: return algorithm;
}
}
// Utility function to format memory size
private string FormatBytes(long bytes)
{
string[] sizes = { "B", "KB", "MB", "GB" };
int order = 0;
double size = bytes;
while (size >= 1024 && order < sizes.Length - 1)
{
order++;
size = size / 1024;
}
return $"{size:0.##} {sizes[order]}";
}
}

View File

@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: 9fee3f5c29ad21b428f68d801f2377f1
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -1,510 +0,0 @@
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Text;
using UnityEngine;
using UnityEngine.UI;
using TMPro;
public class PathfindingTester : MonoBehaviour
{
[Header("References")]
public GridMap gridMap;
public NPC npc;
public Button startTestButton;
public TMP_Text statusText;
public Slider progressBar;
[Header("Test Configuration")]
[Tooltip("Number of times to run each test combination")]
public int testsPerCombination = 3;
[Tooltip("Delay between tests in seconds")]
public float delayBetweenTests = 0.5f;
[Tooltip("Whether to save results to a CSV file")]
public bool saveResultsToFile = true;
[Tooltip("File name for test results (CSV)")]
public string resultsFileName = "pathfinding_tests.csv";
// Test matrix parameters
private NPC.PathFinderType[] algorithmsToTest = new NPC.PathFinderType[] {
NPC.PathFinderType.ASTAR,
NPC.PathFinderType.DIJKSTRA,
NPC.PathFinderType.GREEDY,
NPC.PathFinderType.BACKTRACKING,
NPC.PathFinderType.BFS
};
private Vector2Int[] gridSizesToTest = new Vector2Int[] {
new Vector2Int(20, 20),
new Vector2Int(35, 35),
new Vector2Int(50, 50),
new Vector2Int(40, 25) // Another non-square grid
};
private float[] mazeDensitiesToTest = new float[] {
0f, // Empty (no walls)
10f, // Very low
30f, // Medium
50f, // High
100f // Fully blocked (all walls)
};
private bool[] diagonalMovementOptions = new bool[] {
true,
false
};
// Test state tracking
private bool isTestingRunning = false;
private int totalTests;
private int completedTests;
private List<PathfindingTestResult> testResults = new List<PathfindingTestResult>();
// Current test parameters
private NPC.PathFinderType currentTestAlgorithm;
private Vector2Int currentTestGridSize;
private float currentTestDensity;
private bool currentTestDiagonal;
private int currentTestIndex;
// Structure to store test results
private struct PathfindingTestResult
{
public NPC.PathFinderType algorithm;
public Vector2Int gridSize;
public float mazeDensity;
public bool diagonalMovement;
public float timeTaken;
public int pathLength;
public int nodesExplored;
public long memoryUsed;
public bool pathFound;
public int testIndex;
}
private void Start()
{
// Subscribe to NPC's pathfinding completion event
npc.OnPathfindingComplete += OnPathfindingComplete;
// Set up the button listener
startTestButton.onClick.AddListener(StartTesting);
// Initial status message
UpdateStatus("Ready to start testing. Click the Start Tests button.");
}
private void OnDestroy()
{
// Unsubscribe from events
if (npc != null)
{
npc.OnPathfindingComplete -= OnPathfindingComplete;
}
}
private void UpdateStatus(string message)
{
if (statusText != null)
{
statusText.text = message;
}
Debug.Log(message);
// Update progress bar if available
if (progressBar != null && totalTests > 0)
{
progressBar.value = (float)completedTests / totalTests;
}
}
public void StartTesting()
{
if (isTestingRunning)
{
Debug.LogWarning("Tests are already running.");
return;
}
// Clear previous results
testResults.Clear();
// Calculate total number of tests
totalTests = algorithmsToTest.Length *
gridSizesToTest.Length *
mazeDensitiesToTest.Length *
diagonalMovementOptions.Length *
testsPerCombination;
completedTests = 0;
isTestingRunning = true;
UpdateStatus($"Starting {totalTests} tests...");
// Disable button during testing
startTestButton.interactable = false;
// Start the test coroutine
StartCoroutine(RunTestMatrix());
}
private IEnumerator RunTestMatrix()
{
// Iterate through all test combinations
foreach (var algorithm in algorithmsToTest)
{
foreach (var gridSize in gridSizesToTest)
{
foreach (var density in mazeDensitiesToTest)
{
foreach (var useDiagonals in diagonalMovementOptions)
{
for (int testIndex = 0; testIndex < testsPerCombination; testIndex++)
{
yield return StartCoroutine(RunSingleTest(algorithm, gridSize, density, useDiagonals, testIndex));
// Wait between tests
yield return new WaitForSeconds(delayBetweenTests);
}
}
}
}
}
// All tests completed
isTestingRunning = false;
startTestButton.interactable = true;
// Save results if enabled
if (saveResultsToFile)
{
SaveResultsToCSV();
}
UpdateStatus($"Testing complete! {completedTests} tests run. Results saved to {resultsFileName}");
}
private IEnumerator RunSingleTest(NPC.PathFinderType algorithm, Vector2Int gridSize, float density, bool useDiagonals, int testIndex)
{
// Update status with current test info
UpdateStatus($"Test {completedTests+1}/{totalTests}: {algorithm} - Grid: {gridSize.x}x{gridSize.y} - Density: {density}% - Diagonals: {useDiagonals}");
// Configure the test environment
yield return StartCoroutine(SetupTestEnvironment(algorithm, gridSize, density, useDiagonals));
// Generate start and destination points
GridNode startNode = FindValidStartNode();
GridNode destNode = FindValidDestinationNode(startNode);
if (startNode == null || destNode == null)
{
Debug.LogWarning($"Failed to find valid start/destination nodes for test - density: {density}%");
// Record the test as "impossible" with a failed path
PathfindingTestResult result = new PathfindingTestResult
{
algorithm = algorithm,
gridSize = gridSize,
mazeDensity = density,
diagonalMovement = useDiagonals,
timeTaken = 0f,
pathLength = 0,
nodesExplored = 0,
memoryUsed = 0,
pathFound = false,
testIndex = testIndex
};
testResults.Add(result);
completedTests++;
yield break;
}
// Position NPC at start node
npc.SetStartNode(startNode);
// Position destination
gridMap.SetDestination(destNode.Value.x, destNode.Value.y);
// Wait a frame to ensure everything is set up
yield return null;
// Store the current test parameters
currentTestAlgorithm = algorithm;
currentTestGridSize = gridSize;
currentTestDensity = density;
currentTestDiagonal = useDiagonals;
currentTestIndex = testIndex;
// Flag to track if callback was triggered
bool callbackTriggered = false;
// Setup a temporary callback listener to detect if the event fires
System.Action<PathfindingMetrics> tempCallback = (metrics) => { callbackTriggered = true; };
npc.OnPathfindingComplete += tempCallback;
// Run pathfinding in silent mode - now the event will still fire with our NPC fix
npc.MoveTo(destNode, true);
// Wait for pathfinding to complete
float timeout = 10.0f;
float elapsed = 0f;
while (npc.pathFinder != null && npc.pathFinder.Status == PathFinding.PathFinderStatus.RUNNING && elapsed < timeout)
{
yield return null;
elapsed += Time.deltaTime;
}
// Wait a bit more to ensure completion
yield return new WaitForSeconds(0.1f);
// Remove the temporary callback
npc.OnPathfindingComplete -= tempCallback;
// If callback wasn't triggered but pathfinding is complete, manually record the result
if (!callbackTriggered && npc.pathFinder != null && npc.pathFinder.Status != PathFinding.PathFinderStatus.RUNNING)
{
Debug.LogWarning($"Callback wasn't triggered for test {completedTests+1}. Recording results manually.");
// Create a metrics object with available data
PathfindingMetrics metrics = new PathfindingMetrics
{
timeTaken = elapsed * 1000f, // convert to ms
pathLength = CalculatePathLength(npc.pathFinder),
nodesExplored = npc.pathFinder.ClosedListCount,
memoryUsed = npc.LastMeasuredMemoryUsage // Get the last memory measurement from NPC
};
// Create a test result entry directly
PathfindingTestResult result = new PathfindingTestResult
{
algorithm = currentTestAlgorithm,
gridSize = currentTestGridSize,
mazeDensity = currentTestDensity,
diagonalMovement = currentTestDiagonal,
timeTaken = metrics.timeTaken,
pathLength = metrics.pathLength,
nodesExplored = metrics.nodesExplored,
memoryUsed = metrics.memoryUsed,
pathFound = npc.pathFinder.Status == PathFinding.PathFinderStatus.SUCCESS,
testIndex = currentTestIndex
};
// Add to results directly
testResults.Add(result);
// Log result
Debug.Log($"Test {completedTests} (manual): {GetAlgorithmName(result.algorithm)} - {result.timeTaken:F2}ms - Path: {result.pathLength} - Nodes: {result.nodesExplored}");
}
// Increment test counter
completedTests++;
}
private int CalculatePathLength(PathFinding.PathFinder<Vector2Int> pathFinder)
{
if (pathFinder == null || pathFinder.CurrentNode == null)
return 0;
int length = 0;
var node = pathFinder.CurrentNode;
while (node != null)
{
length++;
node = node.Parent;
}
return length;
}
private IEnumerator SetupTestEnvironment(NPC.PathFinderType algorithm, Vector2Int gridSize, float density, bool useDiagonals)
{
Debug.Log($"Setting up test environment: Algorithm={algorithm}, Grid={gridSize.x}x{gridSize.y}, Density={density}, Diagonals={useDiagonals}");
// Resize grid
gridMap.ResizeGrid(gridSize.x, gridSize.y);
yield return null;
// Set algorithm
npc.ChangeAlgorithm(algorithm);
yield return null;
// Set diagonal movement
gridMap.AllowDiagonalMovement = useDiagonals;
yield return null;
// Generate maze with specified density
gridMap.GenerateRandomMaze(density);
yield return null;
// Note: We no longer change visualization settings here
// This is handled in the RunSingleTest method
yield return null;
}
private GridNode FindValidStartNode()
{
// Find a walkable node for start position, starting from the top left
for (int x = 0; x < gridMap.NumX; x++)
{
for (int y = 0; y < gridMap.NumY; y++)
{
GridNode node = gridMap.GetGridNode(x, y);
if (node != null && node.IsWalkable)
{
return node;
}
}
}
return null;
}
private GridNode FindValidDestinationNode(GridNode startNode)
{
if (startNode == null)
return null;
// Find a walkable node far from the start position, starting from the bottom right
int maxDistance = 0;
GridNode bestNode = null;
// First try to find a node with good distance
for (int x = gridMap.NumX - 1; x >= 0; x--)
{
for (int y = gridMap.NumY - 1; y >= 0; y--)
{
GridNode node = gridMap.GetGridNode(x, y);
if (node != null && node.IsWalkable && node != startNode)
{
int distance = Mathf.Abs(x - startNode.Value.x) + Mathf.Abs(y - startNode.Value.y);
if (distance > maxDistance)
{
maxDistance = distance;
bestNode = node;
}
}
}
}
// If we found a node and the distance is decent, use it
if (bestNode != null && maxDistance > gridMap.NumX / 4)
{
return bestNode;
}
// If no good node was found or distance is too small, try harder to find any walkable node
// different from start node (this helps with very high density mazes)
for (int x = 0; x < gridMap.NumX; x++)
{
for (int y = 0; y < gridMap.NumY; y++)
{
GridNode node = gridMap.GetGridNode(x, y);
if (node != null && node.IsWalkable && node != startNode)
{
return node; // Return the first walkable node that isn't the start
}
}
}
// If we get here and bestNode is null, there's only one walkable node in the entire grid
// In this case, we have to return null and the test should be skipped
return bestNode;
}
private void OnPathfindingComplete(PathfindingMetrics metrics)
{
if (!isTestingRunning)
{
Debug.Log("OnPathfindingComplete called but test is not running - ignoring");
return;
}
Debug.Log($"OnPathfindingComplete called for test {completedTests+1} with algorithm {currentTestAlgorithm}");
// Create a test result entry
PathfindingTestResult result = new PathfindingTestResult
{
algorithm = currentTestAlgorithm,
gridSize = currentTestGridSize,
mazeDensity = currentTestDensity,
diagonalMovement = currentTestDiagonal,
timeTaken = metrics.timeTaken,
pathLength = metrics.pathLength,
nodesExplored = metrics.nodesExplored,
memoryUsed = metrics.memoryUsed,
pathFound = npc.pathFinder.Status == PathFinding.PathFinderStatus.SUCCESS,
testIndex = currentTestIndex
};
// Add to results
testResults.Add(result);
// Log result
Debug.Log($"Test {completedTests+1}: {GetAlgorithmName(result.algorithm)} - {result.timeTaken:F2}ms - Path: {result.pathLength} - Nodes: {result.nodesExplored} - Success: {result.pathFound} - Results count: {testResults.Count}");
}
private void SaveResultsToCSV()
{
try
{
Debug.Log($"Saving {testResults.Count} test results to CSV...");
if (testResults.Count == 0)
{
Debug.LogWarning("No test results to save!");
return;
}
// Create directory if it doesn't exist
string directory = Path.Combine(Application.persistentDataPath, "TestResults");
if (!Directory.Exists(directory))
{
Directory.CreateDirectory(directory);
}
string filePath = Path.Combine(directory, resultsFileName);
StringBuilder csv = new StringBuilder();
// Write header
csv.AppendLine("Algorithm,GridSizeX,GridSizeY,Density,DiagonalMovement,TimeTaken,PathLength,NodesExplored,MemoryUsed,PathFound,TestIndex");
// Write each result
foreach (var result in testResults)
{
csv.AppendLine($"{result.algorithm},{result.gridSize.x},{result.gridSize.y},{result.mazeDensity},{result.diagonalMovement}," +
$"{result.timeTaken},{result.pathLength},{result.nodesExplored},{result.memoryUsed},{result.pathFound},{result.testIndex}");
}
// Write file
File.WriteAllText(filePath, csv.ToString());
Debug.Log($"Test results saved to {filePath}");
// Make it easier to find in Windows Explorer
System.Diagnostics.Process.Start("explorer.exe", $"/select,\"{filePath}\"");
}
catch (System.Exception e)
{
Debug.LogError($"Error saving test results: {e.Message}");
}
}
// Utility method to get algorithm name as a string
private string GetAlgorithmName(NPC.PathFinderType algorithm)
{
switch (algorithm)
{
case NPC.PathFinderType.ASTAR: return "A*";
case NPC.PathFinderType.DIJKSTRA: return "Dijkstra";
case NPC.PathFinderType.GREEDY: return "Greedy";
case NPC.PathFinderType.BACKTRACKING: return "Backtracking";
case NPC.PathFinderType.BFS: return "BFS";
default: return "Unknown";
}
}
}

View File

@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: ed03b279fa9f3194f8caed356ea838dc
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -6,6 +6,11 @@ using UnityEngine.UI;
using TMPro;
using System.IO;
/// <summary>
/// PathfindingUIManager merupakan kelas yang mengelola antarmuka pengguna untuk sistem pathfinding.
/// pengguna dapat mengatur ukuran grid, memilih algoritma pathfinding, menjalankan pathfinding.
/// </summary>
public class PathfindingUIManager : MonoBehaviour
{
[Header("References")]
@ -22,12 +27,11 @@ public class PathfindingUIManager : MonoBehaviour
public TMP_Dropdown algorithmDropdown;
public Button runPathfindingButton;
public Button resetButton;
public Toggle allowDiagonalToggle; // Toggle untuk diagonal movement
public Toggle allowDiagonalToggle;
[Header("Visualization Controls")]
public Slider visualizationSpeedSlider;
public Slider visualizationBatchSlider;
// public Toggle showVisualizationToggle;
public TMP_Text speedValueText;
public TMP_Text batchValueText;
@ -36,7 +40,7 @@ public class PathfindingUIManager : MonoBehaviour
public TMP_Text pathLengthText;
public TMP_Text nodesExploredText;
public TMP_Text memoryUsageText;
public TMP_Text cpuUsageText; // Text untuk menampilkan penggunaan CPU
public TMP_Text cpuUsageText;
[Header("Map Save/Load")]
public TMP_InputField mapNameInput;
@ -44,7 +48,7 @@ public class PathfindingUIManager : MonoBehaviour
public Button loadButton;
[Header("Application Controls")]
public Button exitButton; // Tombol untuk keluar aplikasi
public Button exitButton;
[Header("Optimization")]
[SerializeField] private bool performWarmup = true;
@ -54,29 +58,16 @@ public class PathfindingUIManager : MonoBehaviour
public TMP_Dropdown mazeSizeDropdown;
public TMP_Dropdown mazeDensityDropdown;
[Header("Automated Testing")]
[SerializeField] private GameObject testerPanelPrefab;
[SerializeField] private Transform testerPanelParent;
private GameObject testerPanelInstance;
// Konstanta untuk perhitungan CPU usage
private const float TARGET_FRAME_TIME_MS = 16.67f; // 60 FPS = 16.67ms per frame
// Add a flag to track if pathfinding is running
private bool isPathfindingRunning = false;
// Add a flag to track if visualization is running
private bool isVisualizationRunning = false;
// Add a flag to track if NPC is moving
private bool isNpcMoving = false;
private void Start()
{
// Initialize UI elements
InitializeUI();
// Add listeners
applyGridSizeButton.onClick.AddListener(OnApplyGridSize);
runPathfindingButton.onClick.AddListener(OnRunPathfinding);
resetButton.onClick.AddListener(OnResetPathfinding);
@ -84,56 +75,38 @@ public class PathfindingUIManager : MonoBehaviour
saveButton.onClick.AddListener(OnSaveMap);
loadButton.onClick.AddListener(OnLoadMap);
// Add exit button listener if the button exists
if (exitButton != null)
exitButton.onClick.AddListener(OnExitApplication);
// Add listener for maze generator
if (generateMazeButton != null)
generateMazeButton.onClick.AddListener(OnGenerateMaze);
// Add visualization control listeners
if (visualizationSpeedSlider != null)
visualizationSpeedSlider.onValueChanged.AddListener(OnVisualizationSpeedChanged);
if (visualizationBatchSlider != null)
visualizationBatchSlider.onValueChanged.AddListener(OnVisualizationBatchChanged);
//if (showVisualizationToggle != null)
//{
// showVisualizationToggle.isOn = npc.showVisualization;
// showVisualizationToggle.onValueChanged.AddListener(OnShowVisualizationChanged);
//}
// Subscribe to NPC's pathfinding events
npc.OnPathfindingComplete += UpdatePerformanceMetrics;
npc.OnPathfindingComplete += OnPathfindingCompleted;
// Subscribe to visualization completion event
npc.OnVisualizationComplete += OnVisualizationCompleted;
// Subscribe to movement completion event
npc.OnMovementComplete += OnMovementCompleted;
// Initialize performance metrics
ClearPerformanceMetrics();
// Initialize visualization controls
InitializeVisualizationControls();
// Perform algorithm warmup
if (performWarmup)
{
StartCoroutine(WarmupPathfindingSystem());
}
// Tampilkan lokasi penyimpanan
ShowSaveLocation();
}
private IEnumerator WarmupPathfindingSystem()
{
// Wait one frame to ensure everything is initialized
yield return null;
if (showWarmupMessage)
@ -141,20 +114,16 @@ public class PathfindingUIManager : MonoBehaviour
//Debug.Log("Performing pathfinding warmup...");
}
// Get current NPC position
Vector3 npcPos = npc.transform.position;
int startX = (int)(npcPos.x / gridMap.GridNodeWidth);
int startY = (int)(npcPos.y / gridMap.GridNodeHeight);
// Find destination node for warmup (try to use opposite corner)
int destX = gridMap.NumX - 1;
int destY = gridMap.NumY - 1;
// Ensure destination is walkable
GridNode destNode = gridMap.GetGridNode(destX, destY);
if (destNode == null || !destNode.IsWalkable)
{
// Find any walkable node for warmup
for (int x = 0; x < gridMap.NumX; x++)
{
for (int y = 0; y < gridMap.NumY; y++)
@ -173,66 +142,46 @@ public class PathfindingUIManager : MonoBehaviour
}
}
// Save current destination position
Vector3 originalDestPos = gridMap.Destination.position;
// Set temporary destination for warmup
gridMap.SetDestination(destX, destY);
// Run pathfinding quietly (without visualization)
GridNode startNode = gridMap.GetGridNode(startX, startY);
if (startNode != null && destNode != null && destNode.IsWalkable)
{
// Temporarily disable visualization for warmup
float originalVisualizationSpeed = npc.visualizationSpeed;
npc.visualizationSpeed = 0f;
bool originalShowVisualization = npc.showVisualization;
npc.showVisualization = false;
// Do warmup for each algorithm type to JIT compile all code paths
foreach (NPC.PathFinderType algoType in System.Enum.GetValues(typeof(NPC.PathFinderType)))
{
// Save current algorithm
NPC.PathFinderType originalAlgorithm = npc.pathFinderType;
// Change to this algorithm
npc.ChangeAlgorithm(algoType);
// Run silent pathfinding
npc.MoveTo(destNode, true);
// Wait a bit to ensure completion
yield return new WaitForSeconds(0.05f);
// Reset back to original algorithm
npc.ChangeAlgorithm(originalAlgorithm);
}
// Restore visualization settings
npc.visualizationSpeed = originalVisualizationSpeed;
npc.showVisualization = originalShowVisualization;
}
// Restore original destination
gridMap.Destination.position = originalDestPos;
// Clear metrics from warmup
ClearPerformanceMetrics();
if (showWarmupMessage)
{
//Debug.Log("Pathfinding warmup complete");
}
// Reset grid colors
gridMap.ResetGridNodeColours();
}
private void OnDestroy()
{
// Unsubscribe from events
if (npc != null)
{
npc.OnPathfindingComplete -= UpdatePerformanceMetrics;
@ -241,7 +190,6 @@ public class PathfindingUIManager : MonoBehaviour
npc.OnMovementComplete -= OnMovementCompleted;
}
// Unsubscribe from UI events
if (allowDiagonalToggle != null)
{
allowDiagonalToggle.onValueChanged.RemoveListener(OnDiagonalMovementChanged);
@ -250,19 +198,15 @@ public class PathfindingUIManager : MonoBehaviour
private void InitializeUI()
{
// Set initial values
gridSizeXInput.text = gridMap.NumX.ToString();
gridSizeYInput.text = gridMap.NumY.ToString();
// Set input fields to only accept integers
gridSizeXInput.contentType = TMP_InputField.ContentType.IntegerNumber;
gridSizeYInput.contentType = TMP_InputField.ContentType.IntegerNumber;
// Add input validation events
gridSizeXInput.onValidateInput += ValidateNumberInput;
gridSizeYInput.onValidateInput += ValidateNumberInput;
// Setup algorithm dropdown
algorithmDropdown.ClearOptions();
algorithmDropdown.AddOptions(new System.Collections.Generic.List<string> {
"A*",
@ -272,14 +216,12 @@ public class PathfindingUIManager : MonoBehaviour
"BFS"
});
// Initialize diagonal movement toggle
if (allowDiagonalToggle != null)
{
allowDiagonalToggle.isOn = gridMap.AllowDiagonalMovement;
allowDiagonalToggle.onValueChanged.AddListener(OnDiagonalMovementChanged);
}
// Setup maze size dropdown
if (mazeSizeDropdown != null)
{
mazeSizeDropdown.ClearOptions();
@ -292,7 +234,6 @@ public class PathfindingUIManager : MonoBehaviour
});
}
// Setup maze density dropdown
if (mazeDensityDropdown != null)
{
mazeDensityDropdown.ClearOptions();
@ -306,17 +247,15 @@ public class PathfindingUIManager : MonoBehaviour
ClearPerformanceMetrics();
}
// Validation function to only allow numeric input
private char ValidateNumberInput(string text, int charIndex, char addedChar)
{
// Only allow digits
if (char.IsDigit(addedChar))
{
return addedChar;
}
else
{
return '\0'; // Return null character to reject the input
return '\0';
}
}
@ -336,7 +275,6 @@ public class PathfindingUIManager : MonoBehaviour
nodesExploredText.text = $"{metrics.nodesExplored} nodes";
memoryUsageText.text = FormatBytes(metrics.memoryUsed);
// Hitung dan tampilkan CPU usage
if (cpuUsageText != null)
{
float cpuUsagePercentage = (metrics.timeTaken / TARGET_FRAME_TIME_MS) * 100f;
@ -362,38 +300,29 @@ public class PathfindingUIManager : MonoBehaviour
if (int.TryParse(gridSizeXInput.text, out int newSizeX) &&
int.TryParse(gridSizeYInput.text, out int newSizeY))
{
// Validate grid size limits
const int MAX_GRID_SIZE = 200;
const int MIN_GRID_SIZE = 2;
if (newSizeX > MAX_GRID_SIZE || newSizeY > MAX_GRID_SIZE)
{
// Display an error message
Debug.LogWarning($"Grid size cannot exceed {MAX_GRID_SIZE}x{MAX_GRID_SIZE}. Resize operation cancelled.");
// Revert input fields to current grid size
gridSizeXInput.text = gridMap.NumX.ToString();
gridSizeYInput.text = gridMap.NumY.ToString();
// Don't proceed with resize
return;
}
// Check for minimum size
if (newSizeX < MIN_GRID_SIZE || newSizeY < MIN_GRID_SIZE)
{
// Display an error message
Debug.LogWarning($"Grid size cannot be less than {MIN_GRID_SIZE}x{MIN_GRID_SIZE}. Resize operation cancelled.");
// Revert input fields to current grid size
gridSizeXInput.text = gridMap.NumX.ToString();
gridSizeYInput.text = gridMap.NumY.ToString();
// Don't proceed with resize
return;
}
// Apply the grid size (only if within limits)
if (gridMap.ResizeGrid(newSizeX, newSizeY))
{
ClearPerformanceMetrics();
@ -403,17 +332,14 @@ public class PathfindingUIManager : MonoBehaviour
private void OnRunPathfinding()
{
// Get current NPC position
Vector3 npcPos = npc.transform.position;
int startX = (int)(npcPos.x / gridMap.GridNodeWidth);
int startY = (int)(npcPos.y / gridMap.GridNodeHeight);
// Get destination position
Vector3 destPos = gridMap.Destination.position;
int destX = (int)(destPos.x / gridMap.GridNodeWidth);
int destY = (int)(destPos.y / gridMap.GridNodeHeight);
// Run pathfinding
GridNode startNode = gridMap.GetGridNode(startX, startY);
GridNode endNode = gridMap.GetGridNode(destX, destY);
@ -421,10 +347,9 @@ public class PathfindingUIManager : MonoBehaviour
{
ClearPerformanceMetrics();
// Set flags that pathfinding, visualization, and movement will happen
isPathfindingRunning = true;
isVisualizationRunning = true;
isNpcMoving = true; // assume movement will happen
isNpcMoving = true;
SetUIInteractivity(false);
npc.MoveTo(endNode);
@ -433,20 +358,15 @@ public class PathfindingUIManager : MonoBehaviour
private void OnResetPathfinding()
{
// Reset all flags to ensure UI will be enabled after reload
isPathfindingRunning = false;
isVisualizationRunning = false;
isNpcMoving = false;
// Force enable UI - this ensures buttons will be enabled
// after reset regardless of editor/build status
SetUIInteractivity(true);
// Reload the current scene
UnityEngine.SceneManagement.SceneManager.LoadScene(
UnityEngine.SceneManagement.SceneManager.GetActiveScene().name);
//Debug.Log("Reloading scene...");
}
private void OnAlgorithmChanged(int index)
@ -460,7 +380,6 @@ public class PathfindingUIManager : MonoBehaviour
ClearPerformanceMetrics();
}
// Helper method to get the readable name of the algorithm
private string GetAlgorithmName(NPC.PathFinderType type)
{
switch (type)
@ -488,7 +407,6 @@ public class PathfindingUIManager : MonoBehaviour
return;
}
// Buat direktori jika belum ada
string saveDirectory = Path.Combine(Application.persistentDataPath, "GridSaves");
if (!Directory.Exists(saveDirectory))
{
@ -501,20 +419,13 @@ public class PathfindingUIManager : MonoBehaviour
Debug.Log($"Map saved to: {filePath} (includes grid state, NPC position, and destination position)");
}
/// <summary>
/// Membuka folder penyimpanan di File Explorer
/// </summary>
public void OpenSaveFolder()
{
string saveDirectory = Path.Combine(Application.persistentDataPath, "GridSaves");
// Buat direktori jika belum ada
if (!Directory.Exists(saveDirectory))
{
Directory.CreateDirectory(saveDirectory);
}
// Buka folder di file explorer
System.Diagnostics.Process.Start("explorer.exe", saveDirectory);
}
@ -530,22 +441,15 @@ public class PathfindingUIManager : MonoBehaviour
if (!File.Exists(filePath))
{
//Debug.LogWarning($"Map file not found: {filePath}");
return;
}
gridMap.LoadGridState(filePath);
ClearPerformanceMetrics();
//Debug.Log($"Map loaded from: {filePath}");
}
/// <summary>
/// Generates a random maze with the selected size and density
/// </summary>
private void OnGenerateMaze()
{
// Get selected maze size
int sizeX = 20;
int sizeY = 20;
bool isLargeGrid = false;
@ -569,10 +473,8 @@ public class PathfindingUIManager : MonoBehaviour
sizeX = sizeY = 100;
isLargeGrid = true;
break;
// If more options are added that exceed MAX_GRID_SIZE, they'll be rejected
}
// Check if size exceeds maximum or is below minimum - reject if it does
if (sizeX > MAX_GRID_SIZE || sizeY > MAX_GRID_SIZE)
{
Debug.LogWarning($"Maze size {sizeX}x{sizeY} exceeds maximum of {MAX_GRID_SIZE}x{MAX_GRID_SIZE}. Operation cancelled.");
@ -585,22 +487,18 @@ public class PathfindingUIManager : MonoBehaviour
return;
}
// Resize grid if needed
if (gridMap.NumX != sizeX || gridMap.NumY != sizeY)
{
if (!gridMap.ResizeGrid(sizeX, sizeY))
{
// Resize failed, abort maze generation
return;
}
// Update grid size inputs
gridSizeXInput.text = sizeX.ToString();
gridSizeYInput.text = sizeY.ToString();
}
// Get selected density
float density = 30f; // Default medium
float density = 30f;
switch (mazeDensityDropdown.value)
{
@ -615,61 +513,40 @@ public class PathfindingUIManager : MonoBehaviour
break;
}
// Untuk grid besar, nonaktifkan visualisasi sementara untuk performa lebih baik
bool originalShowVisualization = false;
float originalVisualizationSpeed = 0f;
if (isLargeGrid && npc != null)
{
// Simpan nilai asli
originalShowVisualization = npc.showVisualization;
originalVisualizationSpeed = npc.visualizationSpeed;
// Nonaktifkan visualisasi untuk grid besar
npc.showVisualization = false;
}
// Generate the maze with selected density
gridMap.GenerateRandomMaze(density);
// Kembalikan nilai visualisasi jika diubah
if (isLargeGrid && npc != null)
{
npc.showVisualization = originalShowVisualization;
npc.visualizationSpeed = originalVisualizationSpeed;
}
// Clear performance metrics
ClearPerformanceMetrics();
// Tampilkan pesan khusus untuk grid besar
if (isLargeGrid)
{
//Debug.Log("Large maze generated. For best performance, consider disabling visualization during pathfinding.");
}
//Debug.Log($"Generated maze with size {sizeX}x{sizeY} and density {density}%");
}
/// <summary>
/// Menampilkan lokasi penyimpanan file di konsol
/// </summary>
private void ShowSaveLocation()
{
string saveDirectory = Path.Combine(Application.persistentDataPath, "GridSaves");
}
/// <summary>
/// Menutup aplikasi saat tombol exit ditekan
/// </summary>
public void OnExitApplication()
{
#if UNITY_EDITOR
// Jika di Unity Editor
UnityEditor.EditorApplication.isPlaying = false;
#else
// Jika di build
Application.Quit();
// Jika di build
Application.Quit();
#endif
Debug.Log("Application exit requested");
@ -677,7 +554,6 @@ public class PathfindingUIManager : MonoBehaviour
private void InitializeVisualizationControls()
{
// Set initial slider values based on NPC settings
if (visualizationSpeedSlider != null)
{
visualizationSpeedSlider.value = npc.visualizationSpeed;
@ -699,7 +575,6 @@ public class PathfindingUIManager : MonoBehaviour
private void OnVisualizationBatchChanged(float newValue)
{
// Pastikan nilai batch adalah integer
int batchValue = Mathf.RoundToInt(newValue);
npc.visualizationBatch = batchValue;
UpdateBatchValueText(batchValue);
@ -725,31 +600,22 @@ public class PathfindingUIManager : MonoBehaviour
batchValueText.text = value.ToString();
}
}
/// <summary>
/// Menangani perubahan toggle diagonal movement
/// </summary>
private void OnDiagonalMovementChanged(bool isOn)
{
gridMap.AllowDiagonalMovement = isOn;
// Reset performance metrics
ClearPerformanceMetrics();
}
// New method to handle pathfinding completion
private void OnPathfindingCompleted(PathfindingMetrics metrics)
{
// Pathfinding is completed, but visualization might still be running
isPathfindingRunning = false;
// Check if pathfinding failed by looking at metrics or path length
bool pathfindingFailed = (metrics.pathLength == 0) ||
(npc.pathFinder != null &&
npc.pathFinder.Status == PathFinding.PathFinderStatus.FAILURE);
if (pathfindingFailed)
{
// If pathfinding failed, there won't be any visualization or movement
Debug.Log("Pathfinding failed - re-enabling UI controls immediately");
isVisualizationRunning = false;
isNpcMoving = false;
@ -765,22 +631,15 @@ public class PathfindingUIManager : MonoBehaviour
return;
}
// If pathfinding succeeded, continue with normal flow
// Very important: Keep UI disabled regardless of visualization state to prevent
// the brief window of interactivity between pathfinding completion and visualization start
if (npc.showVisualization)
{
// If visualization is enabled in settings, assume it will start soon
// Keep UI disabled by keeping isVisualizationRunning true
isVisualizationRunning = true;
// Do NOT enable UI here - wait for visualization to complete
}
else
{
// Only if visualization is completely disabled in settings, enable UI
isVisualizationRunning = false;
// Only re-enable in editor mode
#if UNITY_EDITOR
SetUIInteractivity(true);
#else
@ -790,25 +649,18 @@ public class PathfindingUIManager : MonoBehaviour
}
}
// New method to handle visualization completion
private void OnVisualizationCompleted()
{
// Visualization is completed, but NPC may start moving
isVisualizationRunning = false;
// Check if NPC is moving or will move
if (npc.IsMoving || npc.wayPoints.Count > 0)
{
// Movement is starting or in progress
isNpcMoving = true;
// Leave UI disabled
}
else
{
// No movement expected
isNpcMoving = false;
// Only re-enable in editor mode
#if UNITY_EDITOR
SetUIInteractivity(true);
#else
@ -818,13 +670,10 @@ public class PathfindingUIManager : MonoBehaviour
}
}
// New method to handle movement completion
private void OnMovementCompleted()
{
// Movement is completed, re-enable UI buttons only in editor
isNpcMoving = false;
// Only re-enable in editor mode
#if UNITY_EDITOR
SetUIInteractivity(true);
#else
@ -834,13 +683,10 @@ public class PathfindingUIManager : MonoBehaviour
#endif
}
// Method to enable/disable UI elements based on pathfinding, visualization, and movement state
private void SetUIInteractivity(bool enabled)
{
// If any process is running, disable controls
bool shouldEnable = enabled && !isPathfindingRunning && !isVisualizationRunning && !isNpcMoving;
// In builds (not editor), once disabled, buttons stay disabled until reset
#if !UNITY_EDITOR
if (shouldEnable && (isPathfindingRunning || isVisualizationRunning || isNpcMoving))
{
@ -850,13 +696,10 @@ public class PathfindingUIManager : MonoBehaviour
}
#endif
// Add debug logging
Debug.Log($"SetUIInteractivity called with enabled={enabled}, pathfinding={isPathfindingRunning}, " +
$"visualization={isVisualizationRunning}, movement={isNpcMoving}, shouldEnable={shouldEnable}, " +
$"inEditor={Application.isEditor}");
// Keep reset and exit buttons always enabled
// Disable all other buttons when processes are running
if (applyGridSizeButton != null)
applyGridSizeButton.interactable = shouldEnable;
@ -899,17 +742,12 @@ public class PathfindingUIManager : MonoBehaviour
if (mapNameInput != null)
mapNameInput.interactable = shouldEnable;
// Reset and exit buttons remain enabled
// resetButton and exitButton stay interactable
}
private void Update()
{
// Continuously check for various states - this ensures buttons stay disabled
if (npc != null)
{
// Check visualization
if (npc.IsVisualizingPath && !isVisualizationRunning)
{
Debug.Log("Detected active visualization - updating UI state");
@ -917,7 +755,6 @@ public class PathfindingUIManager : MonoBehaviour
SetUIInteractivity(false);
}
// Check movement
if (npc.IsMoving && !isNpcMoving)
{
Debug.Log("Detected active NPC movement - updating UI state");

View File

@ -9,21 +9,10 @@ using System.Collections.Generic;
/// <typeparam name="TPriority">Tipe prioritas yang digunakan, harus implementasi IComparable</typeparam>
public class PriorityQueue<TElement, TPriority> where TPriority : IComparable<TPriority>
{
// Menyimpan pasangan elemen dan prioritasnya dalam struktur heap
private List<Tuple<TElement, TPriority>> elements = new List<Tuple<TElement, TPriority>>();
// Menyimpan indeks setiap elemen dalam heap untuk akses cepat
private Dictionary<TElement, int> elementIndexMap = new Dictionary<TElement, int>();
/// <summary>
/// Mendapatkan jumlah elemen dalam antrean prioritas
/// </summary>
public int Count => elements.Count;
/// <summary>
/// Menambahkan elemen baru ke dalam antrean prioritas dengan prioritas tertentu
/// </summary>
/// <param name="element">Elemen yang akan ditambahkan</param>
/// <param name="priority">Prioritas dari elemen</param>
public void Enqueue(TElement element, TPriority priority)
{
elements.Add(Tuple.Create(element, priority));
@ -31,12 +20,6 @@ public class PriorityQueue<TElement, TPriority> where TPriority : IComparable<TP
HeapifyUp(elements.Count - 1);
}
/// <summary>
/// Mengambil dan menghapus elemen dengan prioritas tertinggi (nilai terkecil)
/// dari antrean prioritas
/// </summary>
/// <returns>Elemen dengan prioritas tertinggi</returns>
/// <exception cref="InvalidOperationException">Dilempar jika antrean kosong</exception>
public TElement Dequeue()
{
if (elements.Count == 0)
@ -48,7 +31,6 @@ public class PriorityQueue<TElement, TPriority> where TPriority : IComparable<TP
if (elements.Count > 0)
{
// Pindahkan elemen terakhir ke root, lalu atur ulang heap
elements[0] = last;
elementIndexMap[last.Item1] = 0;
HeapifyDown(0);
@ -58,12 +40,6 @@ public class PriorityQueue<TElement, TPriority> where TPriority : IComparable<TP
return element;
}
/// <summary>
/// Memperbarui prioritas elemen yang sudah ada dalam antrean
/// </summary>
/// <param name="element">Elemen yang akan diperbarui prioritasnya</param>
/// <param name="newPriority">Nilai prioritas baru</param>
/// <exception cref="InvalidOperationException">Dilempar jika elemen tidak ditemukan</exception>
public void UpdatePriority(TElement element, TPriority newPriority)
{
if (!elementIndexMap.ContainsKey(element))
@ -73,23 +49,16 @@ public class PriorityQueue<TElement, TPriority> where TPriority : IComparable<TP
var oldPriority = elements[index].Item2;
elements[index] = Tuple.Create(element, newPriority);
// Jika prioritas baru lebih tinggi (nilai lebih kecil), heapify up
if (newPriority.CompareTo(oldPriority) < 0)
{
HeapifyUp(index);
}
// Jika prioritas baru lebih rendah (nilai lebih besar), heapify down
else
{
HeapifyDown(index);
}
}
/// <summary>
/// Mempertahankan properti heap dengan memindahkan elemen ke atas jika
/// prioritasnya lebih tinggi dari parent
/// </summary>
/// <param name="index">Indeks elemen yang akan dipindahkan ke atas</param>
private void HeapifyUp(int index)
{
var parentIndex = (index - 1) / 2;
@ -100,18 +69,12 @@ public class PriorityQueue<TElement, TPriority> where TPriority : IComparable<TP
}
}
/// <summary>
/// Mempertahankan properti heap dengan memindahkan elemen ke bawah jika
/// prioritasnya lebih rendah dari child
/// </summary>
/// <param name="index">Indeks elemen yang akan dipindahkan ke bawah</param>
private void HeapifyDown(int index)
{
var leftChildIndex = 2 * index + 1;
var rightChildIndex = 2 * index + 2;
var smallest = index;
// Cari child dengan prioritas tertinggi (nilai terkecil)
if (leftChildIndex < elements.Count && elements[leftChildIndex].Item2.CompareTo(elements[smallest].Item2) < 0)
{
smallest = leftChildIndex;
@ -122,7 +85,6 @@ public class PriorityQueue<TElement, TPriority> where TPriority : IComparable<TP
smallest = rightChildIndex;
}
// Jika child memiliki prioritas lebih tinggi, tukar dan lanjutkan heapify down
if (smallest != index)
{
Swap(index, smallest);
@ -130,18 +92,12 @@ public class PriorityQueue<TElement, TPriority> where TPriority : IComparable<TP
}
}
/// <summary>
/// Menukar posisi dua elemen dalam heap dan memperbarui elementIndexMap
/// </summary>
/// <param name="i">Indeks elemen pertama</param>
/// <param name="j">Indeks elemen kedua</param>
private void Swap(int i, int j)
{
var temp = elements[i];
elements[i] = elements[j];
elements[j] = temp;
// Perbarui elementIndexMap untuk mencerminkan posisi baru
elementIndexMap[elements[i].Item1] = i;
elementIndexMap[elements[j].Item1] = j;
}

View File

@ -1,271 +0,0 @@
Algorithm,GridSizeX,GridSizeY,Density,DiagonalMovement,TimeTaken,PathLength,NodesExplored,MemoryUsed,PathFound,TestIndex
ASTAR,20,20,10,True,1.0282,24,26,4096,True,0
ASTAR,20,20,10,True,0.1261,22,22,4096,True,1
ASTAR,20,20,10,True,0.1369,21,20,4096,True,2
ASTAR,20,20,10,False,0.12,39,38,4096,True,0
ASTAR,20,20,10,False,0.1708,39,53,8192,True,1
ASTAR,20,20,10,False,0.2009,39,69,12288,True,2
ASTAR,20,20,30,True,0.1264,26,27,8192,True,0
ASTAR,20,20,30,True,0.1366,26,29,8192,True,1
ASTAR,20,20,30,True,0.1186,24,25,8192,True,2
ASTAR,20,20,30,False,0.1441,39,45,4096,True,0
ASTAR,20,20,30,False,0.1042,39,48,12288,True,1
ASTAR,20,20,30,False,0.2301,39,87,24576,True,2
ASTAR,20,20,50,True,0.1618,43,89,16384,True,0
ASTAR,20,20,50,True,0.3753,54,171,8192,True,1
ASTAR,20,20,50,True,0.2745,48,130,8192,True,2
ASTAR,20,20,50,False,0.1702,63,104,0,True,0
ASTAR,20,20,50,False,0.1628,59,98,12288,True,1
ASTAR,20,20,50,False,0.3159,135,180,40960,True,2
ASTAR,35,35,10,True,0.2377,36,35,16384,True,0
ASTAR,35,35,10,True,0.2482,38,39,16384,True,1
ASTAR,35,35,10,True,0.2412,40,39,16384,True,2
ASTAR,35,35,10,False,0.2433,69,68,8192,True,0
ASTAR,35,35,10,False,0.281,69,95,24576,True,1
ASTAR,35,35,10,False,0.2874,69,93,20480,True,2
ASTAR,35,35,30,True,0.2388,47,46,20480,True,0
ASTAR,35,35,30,True,0.3082,45,68,4096,True,1
ASTAR,35,35,30,True,0.2438,42,44,4096,True,2
ASTAR,35,35,30,False,0.3319,69,111,4096,True,0
ASTAR,35,35,30,False,0.4247,69,139,20480,True,1
ASTAR,35,35,30,False,0.2607,69,86,12288,True,2
ASTAR,35,35,50,True,0.4856,101,261,36864,True,0
ASTAR,35,35,50,True,1.0796,219,563,98304,True,1
ASTAR,35,35,50,True,1.0919,97,529,114688,True,2
ASTAR,35,35,50,False,0.4922,145,300,69632,True,0
ASTAR,35,35,50,False,0.2173,97,134,24576,True,1
ASTAR,35,35,50,False,0.4082,77,191,28672,True,2
ASTAR,50,50,10,True,0.3457,54,53,40960,True,0
ASTAR,50,50,10,True,0.3793,54,53,16384,True,1
ASTAR,50,50,10,True,0.3698,57,56,16384,True,2
ASTAR,50,50,10,False,0.3816,99,98,20480,True,0
ASTAR,50,50,10,False,0.3855,99,120,20480,True,1
ASTAR,50,50,10,False,0.4885,99,158,24576,True,2
ASTAR,50,50,30,True,0.3388,59,61,16384,True,0
ASTAR,50,50,30,True,0.3565,57,59,20480,True,1
ASTAR,50,50,30,True,0.3343,64,67,20480,True,2
ASTAR,50,50,30,False,1.1702,99,412,102400,True,0
ASTAR,50,50,30,False,0.4831,99,153,32768,True,1
ASTAR,50,50,30,False,0.4641,99,200,8192,True,2
ASTAR,50,50,50,True,2.2106,147,926,73728,True,0
ASTAR,50,50,50,True,1.8848,162,854,73728,True,1
ASTAR,50,50,50,True,1.8428,305,1033,196608,True,2
ASTAR,50,50,50,False,1.3853,259,813,155648,True,0
ASTAR,50,50,50,False,1.3047,289,809,151552,True,1
ASTAR,50,50,50,False,0.7769,223,485,77824,True,2
DIJKSTRA,20,20,10,True,0.5732,21,360,69632,True,0
DIJKSTRA,20,20,10,True,0.6119,21,360,69632,True,1
DIJKSTRA,20,20,10,True,0.5995,20,360,81920,True,2
DIJKSTRA,20,20,10,False,0.4575,39,360,126976,True,0
DIJKSTRA,20,20,10,False,0.4468,39,359,114688,True,1
DIJKSTRA,20,20,10,False,0.4462,39,361,32768,True,2
DIJKSTRA,20,20,30,True,0.4703,23,281,32768,True,0
DIJKSTRA,20,20,30,True,0.4805,25,281,32768,True,1
DIJKSTRA,20,20,30,True,0.4821,24,281,61440,True,2
DIJKSTRA,20,20,30,False,0.3919,39,282,65536,True,0
DIJKSTRA,20,20,30,False,0.3812,41,280,61440,True,1
DIJKSTRA,20,20,30,False,0.3457,39,281,61440,True,2
DIJKSTRA,20,20,50,True,0.2829,44,197,28672,True,0
DIJKSTRA,20,20,50,True,0.2141,58,144,20480,True,1
DIJKSTRA,20,20,50,True,0.2861,66,192,32768,True,2
DIJKSTRA,20,20,50,False,0.2427,59,189,28672,True,0
DIJKSTRA,20,20,50,False,0.1485,51,115,24576,True,1
DIJKSTRA,20,20,50,False,0.1985,91,159,45056,True,2
DIJKSTRA,35,35,10,True,2.1114,37,1103,327680,True,0
DIJKSTRA,35,35,10,True,2.0576,37,1103,94208,True,1
DIJKSTRA,35,35,10,True,2.1407,37,1104,94208,True,2
DIJKSTRA,35,35,10,False,1.5362,69,1103,253952,True,0
DIJKSTRA,35,35,10,False,1.4893,69,1103,204800,True,1
DIJKSTRA,35,35,10,False,1.4763,69,1103,200704,True,2
DIJKSTRA,35,35,30,True,1.5209,42,858,163840,True,0
DIJKSTRA,35,35,30,True,1.435,42,857,155648,True,1
DIJKSTRA,35,35,30,True,1.4548,40,857,159744,True,2
DIJKSTRA,35,35,30,False,1.129,69,856,253952,True,0
DIJKSTRA,35,35,30,False,1.1949,69,855,253952,True,1
DIJKSTRA,35,35,30,False,1.1977,69,856,294912,True,2
DIJKSTRA,35,35,50,True,0.6041,136,400,28672,True,0
DIJKSTRA,35,35,50,True,0.6758,145,487,28672,True,1
DIJKSTRA,35,35,50,True,0.6081,137,424,28672,True,2
DIJKSTRA,35,35,50,False,0.58,0,0,8192,False,0
DIJKSTRA,35,35,50,False,0.4809,129,362,65536,True,1
DIJKSTRA,35,35,50,False,0.7123,77,532,98304,True,2
DIJKSTRA,50,50,10,True,4.5189,51,2250,409600,True,0
DIJKSTRA,50,50,10,True,4.5321,53,2250,409600,True,1
DIJKSTRA,50,50,10,True,4.3824,54,2251,573440,True,2
DIJKSTRA,50,50,10,False,3.1707,99,2250,659456,True,0
DIJKSTRA,50,50,10,False,3.3113,99,2250,663552,True,1
DIJKSTRA,50,50,10,False,3.3981,99,2251,188416,True,2
DIJKSTRA,50,50,30,True,3.2778,58,1750,258048,True,0
DIJKSTRA,50,50,30,True,3.0818,58,1751,327680,True,1
DIJKSTRA,50,50,30,True,3.1183,58,1750,323584,True,2
DIJKSTRA,50,50,30,False,2.4624,99,1749,323584,True,0
DIJKSTRA,50,50,30,False,2.5493,99,1751,323584,True,1
DIJKSTRA,50,50,30,False,2.4891,99,1749,319488,True,2
DIJKSTRA,50,50,50,True,1.2986,301,880,217088,True,0
DIJKSTRA,50,50,50,True,1.6238,194,1187,344064,True,1
DIJKSTRA,50,50,50,True,2.5347,174,565,184320,True,2
DIJKSTRA,50,50,50,False,1.2548,271,896,73728,True,0
DIJKSTRA,50,50,50,False,1.3304,409,934,90112,True,1
DIJKSTRA,50,50,50,False,0.7657,357,612,122880,True,2
GREEDY,20,20,10,True,0.1293,22,22,8192,True,0
GREEDY,20,20,10,True,0.1508,21,21,8192,True,1
GREEDY,20,20,10,True,0.1445,21,21,4096,True,2
GREEDY,20,20,10,False,0.1191,39,39,4096,True,0
GREEDY,20,20,10,False,0.1347,41,41,4096,True,1
GREEDY,20,20,10,False,0.1692,43,46,12288,True,2
GREEDY,20,20,30,True,0.1515,25,27,4096,True,0
GREEDY,20,20,30,True,0.1471,25,25,8192,True,1
GREEDY,20,20,30,True,0.1325,28,28,8192,True,2
GREEDY,20,20,30,False,0.166,43,46,0,True,0
GREEDY,20,20,30,False,0.1449,39,45,0,True,1
GREEDY,20,20,30,False,0.1382,41,45,0,True,2
GREEDY,20,20,50,True,0.2456,47,95,0,True,0
GREEDY,20,20,50,True,0.3083,60,119,12288,True,1
GREEDY,20,20,50,True,0.2403,60,80,8192,True,2
GREEDY,20,20,50,False,0.2485,67,115,12288,True,0
GREEDY,20,20,50,False,0.173,59,91,20480,True,1
GREEDY,20,20,50,False,0.3466,79,193,20480,True,2
GREEDY,35,35,10,True,0.2559,39,39,16384,True,0
GREEDY,35,35,10,True,0.2487,38,38,16384,True,1
GREEDY,35,35,10,True,0.2573,40,40,24576,True,2
GREEDY,35,35,10,False,0.3217,83,95,20480,True,0
GREEDY,35,35,10,False,0.6061,69,69,32768,True,1
GREEDY,35,35,10,False,0.281,69,69,4096,True,2
GREEDY,35,35,30,True,0.2408,43,45,8192,True,0
GREEDY,35,35,30,True,0.2331,43,43,4096,True,1
GREEDY,35,35,30,True,0.2392,42,42,12288,True,2
GREEDY,35,35,30,False,0.225,71,77,8192,True,0
GREEDY,35,35,30,False,0.2613,83,83,12288,True,1
GREEDY,35,35,30,False,0.23,71,71,8192,True,2
GREEDY,35,35,50,True,0.9538,91,365,65536,True,0
GREEDY,35,35,50,True,0.9843,147,364,81920,True,1
GREEDY,35,35,50,True,0.7238,197,300,94208,True,2
GREEDY,35,35,50,False,0.3991,147,194,28672,True,0
GREEDY,35,35,50,False,0.4047,117,211,49152,True,1
GREEDY,35,35,50,False,0.3874,183,196,4096,True,2
GREEDY,50,50,10,True,0.3848,57,58,16384,True,0
GREEDY,50,50,10,True,0.3706,58,58,20480,True,1
GREEDY,50,50,10,True,0.3754,54,54,24576,True,2
GREEDY,50,50,10,False,0.3671,99,99,28672,True,0
GREEDY,50,50,10,False,0.3749,99,99,12288,True,1
GREEDY,50,50,10,False,0.3661,101,102,24576,True,2
GREEDY,50,50,30,True,0.3392,63,63,24576,True,0
GREEDY,50,50,30,True,0.3247,64,64,20480,True,1
GREEDY,50,50,30,True,0.3234,68,69,24576,True,2
GREEDY,50,50,30,False,0.4684,123,147,8192,True,0
GREEDY,50,50,30,False,0.3809,107,108,4096,True,1
GREEDY,50,50,30,False,0.3617,101,109,4096,True,2
GREEDY,50,50,50,True,0.7341,208,268,45056,True,0
GREEDY,50,50,50,True,0.849,172,316,65536,True,1
GREEDY,50,50,50,True,0.6744,168,222,32768,True,2
GREEDY,50,50,50,False,1.0245,211,568,98304,True,0
GREEDY,50,50,50,False,1.2286,507,721,143360,True,1
GREEDY,50,50,50,False,1.2725,419,670,172032,True,2
BACKTRACKING,20,20,10,True,0.3594,121,131,69632,True,0
BACKTRACKING,20,20,10,True,0.3929,111,164,61440,True,1
BACKTRACKING,20,20,10,True,0.2945,104,116,65536,True,2
BACKTRACKING,20,20,10,False,0.4242,183,241,28672,True,0
BACKTRACKING,20,20,10,False,0.3568,187,205,28672,True,1
BACKTRACKING,20,20,10,False,0.3895,177,221,28672,True,2
BACKTRACKING,20,20,30,True,0.3235,75,129,28672,True,0
BACKTRACKING,20,20,30,True,0.3471,77,167,36864,True,1
BACKTRACKING,20,20,30,True,0.3286,92,140,36864,True,2
BACKTRACKING,20,20,30,False,0.3422,147,203,45056,True,0
BACKTRACKING,20,20,30,False,0.2824,137,191,32768,True,1
BACKTRACKING,20,20,30,False,0.3286,157,193,36864,True,2
BACKTRACKING,20,20,50,True,0.2677,30,137,28672,True,0
BACKTRACKING,20,20,50,True,0.2214,37,130,24576,True,1
BACKTRACKING,20,20,50,True,0.1721,42,104,20480,True,2
BACKTRACKING,20,20,50,False,0.1367,71,124,36864,True,0
BACKTRACKING,20,20,50,False,0.2432,79,179,8192,True,1
BACKTRACKING,20,20,50,False,0.2324,43,186,8192,True,2
BACKTRACKING,35,35,10,True,1.465,328,401,106496,True,0
BACKTRACKING,35,35,10,True,1.3811,323,409,188416,True,1
BACKTRACKING,35,35,10,True,1.1492,285,349,147456,True,2
BACKTRACKING,35,35,10,False,1.4213,521,635,188416,True,0
BACKTRACKING,35,35,10,False,1.4778,527,680,188416,True,1
BACKTRACKING,35,35,10,False,1.4704,573,649,184320,True,2
BACKTRACKING,35,35,30,True,1.1103,290,408,110592,True,0
BACKTRACKING,35,35,30,True,1.0674,241,456,208896,True,1
BACKTRACKING,35,35,30,True,1.1679,270,445,212992,True,2
BACKTRACKING,35,35,30,False,0.931,429,556,245760,True,0
BACKTRACKING,35,35,30,False,1.0727,403,561,69632,True,1
BACKTRACKING,35,35,30,False,1.5718,401,618,69632,True,2
BACKTRACKING,35,35,50,True,0.6532,77,428,24576,True,0
BACKTRACKING,35,35,50,True,0.2979,79,179,28672,True,1
BACKTRACKING,35,35,50,True,0.4046,125,241,40960,True,2
BACKTRACKING,35,35,50,False,0.3571,0,0,4096,False,0
BACKTRACKING,35,35,50,False,0.652,193,506,102400,True,1
BACKTRACKING,35,35,50,False,0.3799,0,0,16384,False,2
BACKTRACKING,50,50,10,True,3.1519,636,758,438272,True,0
BACKTRACKING,50,50,10,True,2.5557,565,614,495616,True,1
BACKTRACKING,50,50,10,True,3.3404,651,845,610304,True,2
BACKTRACKING,50,50,10,False,3.7901,1137,1239,241664,True,0
BACKTRACKING,50,50,10,False,3.601,1099,1299,200704,True,1
BACKTRACKING,50,50,10,False,3.2003,967,1197,319488,True,2
BACKTRACKING,50,50,30,True,2.6415,593,733,212992,True,0
BACKTRACKING,50,50,30,True,2.1968,520,708,217088,True,1
BACKTRACKING,50,50,30,True,2.4687,557,787,225280,True,2
BACKTRACKING,50,50,30,False,2.5318,703,1337,294912,True,0
BACKTRACKING,50,50,30,False,2.1927,687,1132,430080,True,1
BACKTRACKING,50,50,30,False,2.2509,821,1179,438272,True,2
BACKTRACKING,50,50,50,True,1.2183,145,849,262144,True,0
BACKTRACKING,50,50,50,True,0.8606,234,570,204800,True,1
BACKTRACKING,50,50,50,True,1.8035,150,1043,131072,True,2
BACKTRACKING,50,50,50,False,1.2391,655,933,98304,True,0
BACKTRACKING,50,50,50,False,0.9434,335,763,131072,True,1
BACKTRACKING,50,50,50,False,0.7697,195,577,114688,True,2
BFS,20,20,10,True,0.4677,20,360,61440,True,0
BFS,20,20,10,True,0.621,21,361,77824,True,1
BFS,20,20,10,True,0.5292,21,361,65536,True,2
BFS,20,20,10,False,0.3891,39,361,65536,True,0
BFS,20,20,10,False,0.4235,39,361,65536,True,1
BFS,20,20,10,False,0.4674,39,360,90112,True,2
BFS,20,20,30,True,0.3917,25,282,73728,True,0
BFS,20,20,30,True,0.3715,26,281,86016,True,1
BFS,20,20,30,True,0.449,23,282,24576,True,2
BFS,20,20,30,False,0.3117,39,255,16384,True,0
BFS,20,20,30,False,0.3499,39,281,24576,True,1
BFS,20,20,30,False,0.3472,39,282,57344,True,2
BFS,20,20,50,True,0.2092,42,144,20480,True,0
BFS,20,20,50,True,0.2498,41,161,32768,True,1
BFS,20,20,50,True,0.2399,38,163,24576,True,2
BFS,20,20,50,False,0.2321,59,155,24576,True,0
BFS,20,20,50,False,0.2403,71,162,24576,True,1
BFS,20,20,50,False,0.1412,51,100,16384,True,2
BFS,35,35,10,True,1.679,38,1104,233472,True,0
BFS,35,35,10,True,1.6694,36,1103,294912,True,1
BFS,35,35,10,True,1.7347,39,1104,425984,True,2
BFS,35,35,10,False,1.4652,69,1103,118784,True,0
BFS,35,35,10,False,1.3521,69,1103,118784,True,1
BFS,35,35,10,False,1.3525,69,1103,221184,True,2
BFS,35,35,30,True,1.2777,40,855,139264,True,0
BFS,35,35,30,True,1.2761,43,857,143360,True,1
BFS,35,35,30,True,1.3204,43,857,147456,True,2
BFS,35,35,30,False,1.1577,69,857,176128,True,0
BFS,35,35,30,False,1.1088,69,854,143360,True,1
BFS,35,35,30,False,1.1091,69,857,188416,True,2
BFS,35,35,50,True,0.6461,53,490,155648,True,0
BFS,35,35,50,True,0.6363,88,510,155648,True,1
BFS,35,35,50,True,0.4843,100,350,110592,True,2
BFS,35,35,50,False,0.9047,79,544,57344,True,0
BFS,35,35,50,False,0.3727,0,0,4096,False,1
BFS,35,35,50,False,0.4923,0,0,8192,False,2
BFS,50,50,10,True,3.7701,53,2250,581632,True,0
BFS,50,50,10,True,3.4752,52,2250,462848,True,1
BFS,50,50,10,True,3.5727,52,2250,458752,True,2
BFS,50,50,10,False,2.7849,99,2251,471040,True,0
BFS,50,50,10,False,2.7301,99,2251,598016,True,1
BFS,50,50,10,False,2.6218,99,2251,716800,True,2
BFS,50,50,30,True,2.346,62,1751,491520,True,0
BFS,50,50,30,True,2.3452,58,1750,118784,True,1
BFS,50,50,30,True,2.6295,58,1751,118784,True,2
BFS,50,50,30,False,2.2686,99,1751,290816,True,0
BFS,50,50,30,False,2.1289,99,1751,286720,True,1
BFS,50,50,30,False,2.2602,99,1751,294912,True,2
BFS,50,50,50,True,1.0863,240,773,139264,True,0
BFS,50,50,50,True,0.8318,174,592,118784,True,1
BFS,50,50,50,True,0.7613,160,535,110592,True,2
BFS,50,50,50,False,1.3722,487,1120,282624,True,0
BFS,50,50,50,False,0.8369,227,677,200704,True,1
BFS,50,50,50,False,1.3386,223,996,311296,True,2
1 Algorithm GridSizeX GridSizeY Density DiagonalMovement TimeTaken PathLength NodesExplored MemoryUsed PathFound TestIndex
2 ASTAR 20 20 10 True 1.0282 24 26 4096 True 0
3 ASTAR 20 20 10 True 0.1261 22 22 4096 True 1
4 ASTAR 20 20 10 True 0.1369 21 20 4096 True 2
5 ASTAR 20 20 10 False 0.12 39 38 4096 True 0
6 ASTAR 20 20 10 False 0.1708 39 53 8192 True 1
7 ASTAR 20 20 10 False 0.2009 39 69 12288 True 2
8 ASTAR 20 20 30 True 0.1264 26 27 8192 True 0
9 ASTAR 20 20 30 True 0.1366 26 29 8192 True 1
10 ASTAR 20 20 30 True 0.1186 24 25 8192 True 2
11 ASTAR 20 20 30 False 0.1441 39 45 4096 True 0
12 ASTAR 20 20 30 False 0.1042 39 48 12288 True 1
13 ASTAR 20 20 30 False 0.2301 39 87 24576 True 2
14 ASTAR 20 20 50 True 0.1618 43 89 16384 True 0
15 ASTAR 20 20 50 True 0.3753 54 171 8192 True 1
16 ASTAR 20 20 50 True 0.2745 48 130 8192 True 2
17 ASTAR 20 20 50 False 0.1702 63 104 0 True 0
18 ASTAR 20 20 50 False 0.1628 59 98 12288 True 1
19 ASTAR 20 20 50 False 0.3159 135 180 40960 True 2
20 ASTAR 35 35 10 True 0.2377 36 35 16384 True 0
21 ASTAR 35 35 10 True 0.2482 38 39 16384 True 1
22 ASTAR 35 35 10 True 0.2412 40 39 16384 True 2
23 ASTAR 35 35 10 False 0.2433 69 68 8192 True 0
24 ASTAR 35 35 10 False 0.281 69 95 24576 True 1
25 ASTAR 35 35 10 False 0.2874 69 93 20480 True 2
26 ASTAR 35 35 30 True 0.2388 47 46 20480 True 0
27 ASTAR 35 35 30 True 0.3082 45 68 4096 True 1
28 ASTAR 35 35 30 True 0.2438 42 44 4096 True 2
29 ASTAR 35 35 30 False 0.3319 69 111 4096 True 0
30 ASTAR 35 35 30 False 0.4247 69 139 20480 True 1
31 ASTAR 35 35 30 False 0.2607 69 86 12288 True 2
32 ASTAR 35 35 50 True 0.4856 101 261 36864 True 0
33 ASTAR 35 35 50 True 1.0796 219 563 98304 True 1
34 ASTAR 35 35 50 True 1.0919 97 529 114688 True 2
35 ASTAR 35 35 50 False 0.4922 145 300 69632 True 0
36 ASTAR 35 35 50 False 0.2173 97 134 24576 True 1
37 ASTAR 35 35 50 False 0.4082 77 191 28672 True 2
38 ASTAR 50 50 10 True 0.3457 54 53 40960 True 0
39 ASTAR 50 50 10 True 0.3793 54 53 16384 True 1
40 ASTAR 50 50 10 True 0.3698 57 56 16384 True 2
41 ASTAR 50 50 10 False 0.3816 99 98 20480 True 0
42 ASTAR 50 50 10 False 0.3855 99 120 20480 True 1
43 ASTAR 50 50 10 False 0.4885 99 158 24576 True 2
44 ASTAR 50 50 30 True 0.3388 59 61 16384 True 0
45 ASTAR 50 50 30 True 0.3565 57 59 20480 True 1
46 ASTAR 50 50 30 True 0.3343 64 67 20480 True 2
47 ASTAR 50 50 30 False 1.1702 99 412 102400 True 0
48 ASTAR 50 50 30 False 0.4831 99 153 32768 True 1
49 ASTAR 50 50 30 False 0.4641 99 200 8192 True 2
50 ASTAR 50 50 50 True 2.2106 147 926 73728 True 0
51 ASTAR 50 50 50 True 1.8848 162 854 73728 True 1
52 ASTAR 50 50 50 True 1.8428 305 1033 196608 True 2
53 ASTAR 50 50 50 False 1.3853 259 813 155648 True 0
54 ASTAR 50 50 50 False 1.3047 289 809 151552 True 1
55 ASTAR 50 50 50 False 0.7769 223 485 77824 True 2
56 DIJKSTRA 20 20 10 True 0.5732 21 360 69632 True 0
57 DIJKSTRA 20 20 10 True 0.6119 21 360 69632 True 1
58 DIJKSTRA 20 20 10 True 0.5995 20 360 81920 True 2
59 DIJKSTRA 20 20 10 False 0.4575 39 360 126976 True 0
60 DIJKSTRA 20 20 10 False 0.4468 39 359 114688 True 1
61 DIJKSTRA 20 20 10 False 0.4462 39 361 32768 True 2
62 DIJKSTRA 20 20 30 True 0.4703 23 281 32768 True 0
63 DIJKSTRA 20 20 30 True 0.4805 25 281 32768 True 1
64 DIJKSTRA 20 20 30 True 0.4821 24 281 61440 True 2
65 DIJKSTRA 20 20 30 False 0.3919 39 282 65536 True 0
66 DIJKSTRA 20 20 30 False 0.3812 41 280 61440 True 1
67 DIJKSTRA 20 20 30 False 0.3457 39 281 61440 True 2
68 DIJKSTRA 20 20 50 True 0.2829 44 197 28672 True 0
69 DIJKSTRA 20 20 50 True 0.2141 58 144 20480 True 1
70 DIJKSTRA 20 20 50 True 0.2861 66 192 32768 True 2
71 DIJKSTRA 20 20 50 False 0.2427 59 189 28672 True 0
72 DIJKSTRA 20 20 50 False 0.1485 51 115 24576 True 1
73 DIJKSTRA 20 20 50 False 0.1985 91 159 45056 True 2
74 DIJKSTRA 35 35 10 True 2.1114 37 1103 327680 True 0
75 DIJKSTRA 35 35 10 True 2.0576 37 1103 94208 True 1
76 DIJKSTRA 35 35 10 True 2.1407 37 1104 94208 True 2
77 DIJKSTRA 35 35 10 False 1.5362 69 1103 253952 True 0
78 DIJKSTRA 35 35 10 False 1.4893 69 1103 204800 True 1
79 DIJKSTRA 35 35 10 False 1.4763 69 1103 200704 True 2
80 DIJKSTRA 35 35 30 True 1.5209 42 858 163840 True 0
81 DIJKSTRA 35 35 30 True 1.435 42 857 155648 True 1
82 DIJKSTRA 35 35 30 True 1.4548 40 857 159744 True 2
83 DIJKSTRA 35 35 30 False 1.129 69 856 253952 True 0
84 DIJKSTRA 35 35 30 False 1.1949 69 855 253952 True 1
85 DIJKSTRA 35 35 30 False 1.1977 69 856 294912 True 2
86 DIJKSTRA 35 35 50 True 0.6041 136 400 28672 True 0
87 DIJKSTRA 35 35 50 True 0.6758 145 487 28672 True 1
88 DIJKSTRA 35 35 50 True 0.6081 137 424 28672 True 2
89 DIJKSTRA 35 35 50 False 0.58 0 0 8192 False 0
90 DIJKSTRA 35 35 50 False 0.4809 129 362 65536 True 1
91 DIJKSTRA 35 35 50 False 0.7123 77 532 98304 True 2
92 DIJKSTRA 50 50 10 True 4.5189 51 2250 409600 True 0
93 DIJKSTRA 50 50 10 True 4.5321 53 2250 409600 True 1
94 DIJKSTRA 50 50 10 True 4.3824 54 2251 573440 True 2
95 DIJKSTRA 50 50 10 False 3.1707 99 2250 659456 True 0
96 DIJKSTRA 50 50 10 False 3.3113 99 2250 663552 True 1
97 DIJKSTRA 50 50 10 False 3.3981 99 2251 188416 True 2
98 DIJKSTRA 50 50 30 True 3.2778 58 1750 258048 True 0
99 DIJKSTRA 50 50 30 True 3.0818 58 1751 327680 True 1
100 DIJKSTRA 50 50 30 True 3.1183 58 1750 323584 True 2
101 DIJKSTRA 50 50 30 False 2.4624 99 1749 323584 True 0
102 DIJKSTRA 50 50 30 False 2.5493 99 1751 323584 True 1
103 DIJKSTRA 50 50 30 False 2.4891 99 1749 319488 True 2
104 DIJKSTRA 50 50 50 True 1.2986 301 880 217088 True 0
105 DIJKSTRA 50 50 50 True 1.6238 194 1187 344064 True 1
106 DIJKSTRA 50 50 50 True 2.5347 174 565 184320 True 2
107 DIJKSTRA 50 50 50 False 1.2548 271 896 73728 True 0
108 DIJKSTRA 50 50 50 False 1.3304 409 934 90112 True 1
109 DIJKSTRA 50 50 50 False 0.7657 357 612 122880 True 2
110 GREEDY 20 20 10 True 0.1293 22 22 8192 True 0
111 GREEDY 20 20 10 True 0.1508 21 21 8192 True 1
112 GREEDY 20 20 10 True 0.1445 21 21 4096 True 2
113 GREEDY 20 20 10 False 0.1191 39 39 4096 True 0
114 GREEDY 20 20 10 False 0.1347 41 41 4096 True 1
115 GREEDY 20 20 10 False 0.1692 43 46 12288 True 2
116 GREEDY 20 20 30 True 0.1515 25 27 4096 True 0
117 GREEDY 20 20 30 True 0.1471 25 25 8192 True 1
118 GREEDY 20 20 30 True 0.1325 28 28 8192 True 2
119 GREEDY 20 20 30 False 0.166 43 46 0 True 0
120 GREEDY 20 20 30 False 0.1449 39 45 0 True 1
121 GREEDY 20 20 30 False 0.1382 41 45 0 True 2
122 GREEDY 20 20 50 True 0.2456 47 95 0 True 0
123 GREEDY 20 20 50 True 0.3083 60 119 12288 True 1
124 GREEDY 20 20 50 True 0.2403 60 80 8192 True 2
125 GREEDY 20 20 50 False 0.2485 67 115 12288 True 0
126 GREEDY 20 20 50 False 0.173 59 91 20480 True 1
127 GREEDY 20 20 50 False 0.3466 79 193 20480 True 2
128 GREEDY 35 35 10 True 0.2559 39 39 16384 True 0
129 GREEDY 35 35 10 True 0.2487 38 38 16384 True 1
130 GREEDY 35 35 10 True 0.2573 40 40 24576 True 2
131 GREEDY 35 35 10 False 0.3217 83 95 20480 True 0
132 GREEDY 35 35 10 False 0.6061 69 69 32768 True 1
133 GREEDY 35 35 10 False 0.281 69 69 4096 True 2
134 GREEDY 35 35 30 True 0.2408 43 45 8192 True 0
135 GREEDY 35 35 30 True 0.2331 43 43 4096 True 1
136 GREEDY 35 35 30 True 0.2392 42 42 12288 True 2
137 GREEDY 35 35 30 False 0.225 71 77 8192 True 0
138 GREEDY 35 35 30 False 0.2613 83 83 12288 True 1
139 GREEDY 35 35 30 False 0.23 71 71 8192 True 2
140 GREEDY 35 35 50 True 0.9538 91 365 65536 True 0
141 GREEDY 35 35 50 True 0.9843 147 364 81920 True 1
142 GREEDY 35 35 50 True 0.7238 197 300 94208 True 2
143 GREEDY 35 35 50 False 0.3991 147 194 28672 True 0
144 GREEDY 35 35 50 False 0.4047 117 211 49152 True 1
145 GREEDY 35 35 50 False 0.3874 183 196 4096 True 2
146 GREEDY 50 50 10 True 0.3848 57 58 16384 True 0
147 GREEDY 50 50 10 True 0.3706 58 58 20480 True 1
148 GREEDY 50 50 10 True 0.3754 54 54 24576 True 2
149 GREEDY 50 50 10 False 0.3671 99 99 28672 True 0
150 GREEDY 50 50 10 False 0.3749 99 99 12288 True 1
151 GREEDY 50 50 10 False 0.3661 101 102 24576 True 2
152 GREEDY 50 50 30 True 0.3392 63 63 24576 True 0
153 GREEDY 50 50 30 True 0.3247 64 64 20480 True 1
154 GREEDY 50 50 30 True 0.3234 68 69 24576 True 2
155 GREEDY 50 50 30 False 0.4684 123 147 8192 True 0
156 GREEDY 50 50 30 False 0.3809 107 108 4096 True 1
157 GREEDY 50 50 30 False 0.3617 101 109 4096 True 2
158 GREEDY 50 50 50 True 0.7341 208 268 45056 True 0
159 GREEDY 50 50 50 True 0.849 172 316 65536 True 1
160 GREEDY 50 50 50 True 0.6744 168 222 32768 True 2
161 GREEDY 50 50 50 False 1.0245 211 568 98304 True 0
162 GREEDY 50 50 50 False 1.2286 507 721 143360 True 1
163 GREEDY 50 50 50 False 1.2725 419 670 172032 True 2
164 BACKTRACKING 20 20 10 True 0.3594 121 131 69632 True 0
165 BACKTRACKING 20 20 10 True 0.3929 111 164 61440 True 1
166 BACKTRACKING 20 20 10 True 0.2945 104 116 65536 True 2
167 BACKTRACKING 20 20 10 False 0.4242 183 241 28672 True 0
168 BACKTRACKING 20 20 10 False 0.3568 187 205 28672 True 1
169 BACKTRACKING 20 20 10 False 0.3895 177 221 28672 True 2
170 BACKTRACKING 20 20 30 True 0.3235 75 129 28672 True 0
171 BACKTRACKING 20 20 30 True 0.3471 77 167 36864 True 1
172 BACKTRACKING 20 20 30 True 0.3286 92 140 36864 True 2
173 BACKTRACKING 20 20 30 False 0.3422 147 203 45056 True 0
174 BACKTRACKING 20 20 30 False 0.2824 137 191 32768 True 1
175 BACKTRACKING 20 20 30 False 0.3286 157 193 36864 True 2
176 BACKTRACKING 20 20 50 True 0.2677 30 137 28672 True 0
177 BACKTRACKING 20 20 50 True 0.2214 37 130 24576 True 1
178 BACKTRACKING 20 20 50 True 0.1721 42 104 20480 True 2
179 BACKTRACKING 20 20 50 False 0.1367 71 124 36864 True 0
180 BACKTRACKING 20 20 50 False 0.2432 79 179 8192 True 1
181 BACKTRACKING 20 20 50 False 0.2324 43 186 8192 True 2
182 BACKTRACKING 35 35 10 True 1.465 328 401 106496 True 0
183 BACKTRACKING 35 35 10 True 1.3811 323 409 188416 True 1
184 BACKTRACKING 35 35 10 True 1.1492 285 349 147456 True 2
185 BACKTRACKING 35 35 10 False 1.4213 521 635 188416 True 0
186 BACKTRACKING 35 35 10 False 1.4778 527 680 188416 True 1
187 BACKTRACKING 35 35 10 False 1.4704 573 649 184320 True 2
188 BACKTRACKING 35 35 30 True 1.1103 290 408 110592 True 0
189 BACKTRACKING 35 35 30 True 1.0674 241 456 208896 True 1
190 BACKTRACKING 35 35 30 True 1.1679 270 445 212992 True 2
191 BACKTRACKING 35 35 30 False 0.931 429 556 245760 True 0
192 BACKTRACKING 35 35 30 False 1.0727 403 561 69632 True 1
193 BACKTRACKING 35 35 30 False 1.5718 401 618 69632 True 2
194 BACKTRACKING 35 35 50 True 0.6532 77 428 24576 True 0
195 BACKTRACKING 35 35 50 True 0.2979 79 179 28672 True 1
196 BACKTRACKING 35 35 50 True 0.4046 125 241 40960 True 2
197 BACKTRACKING 35 35 50 False 0.3571 0 0 4096 False 0
198 BACKTRACKING 35 35 50 False 0.652 193 506 102400 True 1
199 BACKTRACKING 35 35 50 False 0.3799 0 0 16384 False 2
200 BACKTRACKING 50 50 10 True 3.1519 636 758 438272 True 0
201 BACKTRACKING 50 50 10 True 2.5557 565 614 495616 True 1
202 BACKTRACKING 50 50 10 True 3.3404 651 845 610304 True 2
203 BACKTRACKING 50 50 10 False 3.7901 1137 1239 241664 True 0
204 BACKTRACKING 50 50 10 False 3.601 1099 1299 200704 True 1
205 BACKTRACKING 50 50 10 False 3.2003 967 1197 319488 True 2
206 BACKTRACKING 50 50 30 True 2.6415 593 733 212992 True 0
207 BACKTRACKING 50 50 30 True 2.1968 520 708 217088 True 1
208 BACKTRACKING 50 50 30 True 2.4687 557 787 225280 True 2
209 BACKTRACKING 50 50 30 False 2.5318 703 1337 294912 True 0
210 BACKTRACKING 50 50 30 False 2.1927 687 1132 430080 True 1
211 BACKTRACKING 50 50 30 False 2.2509 821 1179 438272 True 2
212 BACKTRACKING 50 50 50 True 1.2183 145 849 262144 True 0
213 BACKTRACKING 50 50 50 True 0.8606 234 570 204800 True 1
214 BACKTRACKING 50 50 50 True 1.8035 150 1043 131072 True 2
215 BACKTRACKING 50 50 50 False 1.2391 655 933 98304 True 0
216 BACKTRACKING 50 50 50 False 0.9434 335 763 131072 True 1
217 BACKTRACKING 50 50 50 False 0.7697 195 577 114688 True 2
218 BFS 20 20 10 True 0.4677 20 360 61440 True 0
219 BFS 20 20 10 True 0.621 21 361 77824 True 1
220 BFS 20 20 10 True 0.5292 21 361 65536 True 2
221 BFS 20 20 10 False 0.3891 39 361 65536 True 0
222 BFS 20 20 10 False 0.4235 39 361 65536 True 1
223 BFS 20 20 10 False 0.4674 39 360 90112 True 2
224 BFS 20 20 30 True 0.3917 25 282 73728 True 0
225 BFS 20 20 30 True 0.3715 26 281 86016 True 1
226 BFS 20 20 30 True 0.449 23 282 24576 True 2
227 BFS 20 20 30 False 0.3117 39 255 16384 True 0
228 BFS 20 20 30 False 0.3499 39 281 24576 True 1
229 BFS 20 20 30 False 0.3472 39 282 57344 True 2
230 BFS 20 20 50 True 0.2092 42 144 20480 True 0
231 BFS 20 20 50 True 0.2498 41 161 32768 True 1
232 BFS 20 20 50 True 0.2399 38 163 24576 True 2
233 BFS 20 20 50 False 0.2321 59 155 24576 True 0
234 BFS 20 20 50 False 0.2403 71 162 24576 True 1
235 BFS 20 20 50 False 0.1412 51 100 16384 True 2
236 BFS 35 35 10 True 1.679 38 1104 233472 True 0
237 BFS 35 35 10 True 1.6694 36 1103 294912 True 1
238 BFS 35 35 10 True 1.7347 39 1104 425984 True 2
239 BFS 35 35 10 False 1.4652 69 1103 118784 True 0
240 BFS 35 35 10 False 1.3521 69 1103 118784 True 1
241 BFS 35 35 10 False 1.3525 69 1103 221184 True 2
242 BFS 35 35 30 True 1.2777 40 855 139264 True 0
243 BFS 35 35 30 True 1.2761 43 857 143360 True 1
244 BFS 35 35 30 True 1.3204 43 857 147456 True 2
245 BFS 35 35 30 False 1.1577 69 857 176128 True 0
246 BFS 35 35 30 False 1.1088 69 854 143360 True 1
247 BFS 35 35 30 False 1.1091 69 857 188416 True 2
248 BFS 35 35 50 True 0.6461 53 490 155648 True 0
249 BFS 35 35 50 True 0.6363 88 510 155648 True 1
250 BFS 35 35 50 True 0.4843 100 350 110592 True 2
251 BFS 35 35 50 False 0.9047 79 544 57344 True 0
252 BFS 35 35 50 False 0.3727 0 0 4096 False 1
253 BFS 35 35 50 False 0.4923 0 0 8192 False 2
254 BFS 50 50 10 True 3.7701 53 2250 581632 True 0
255 BFS 50 50 10 True 3.4752 52 2250 462848 True 1
256 BFS 50 50 10 True 3.5727 52 2250 458752 True 2
257 BFS 50 50 10 False 2.7849 99 2251 471040 True 0
258 BFS 50 50 10 False 2.7301 99 2251 598016 True 1
259 BFS 50 50 10 False 2.6218 99 2251 716800 True 2
260 BFS 50 50 30 True 2.346 62 1751 491520 True 0
261 BFS 50 50 30 True 2.3452 58 1750 118784 True 1
262 BFS 50 50 30 True 2.6295 58 1751 118784 True 2
263 BFS 50 50 30 False 2.2686 99 1751 290816 True 0
264 BFS 50 50 30 False 2.1289 99 1751 286720 True 1
265 BFS 50 50 30 False 2.2602 99 1751 294912 True 2
266 BFS 50 50 50 True 1.0863 240 773 139264 True 0
267 BFS 50 50 50 True 0.8318 174 592 118784 True 1
268 BFS 50 50 50 True 0.7613 160 535 110592 True 2
269 BFS 50 50 50 False 1.3722 487 1120 282624 True 0
270 BFS 50 50 50 False 0.8369 227 677 200704 True 1
271 BFS 50 50 50 False 1.3386 223 996 311296 True 2

View File

@ -1,7 +0,0 @@
fileFormatVersion: 2
guid: b5f5e061be1cbf946b769794cb0ba604
TextScriptImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant: