using System.Diagnostics;
using System.Text.Json;
using AntColony.Algorithm;
namespace AntColony;
class Program
{
///
/// Путь до файла с ребрами
/// Файл представлен в формате JSON вместо TSV
/// Файл содержит заголовок
/// Количество итераций
/// Скорость испарения феромонов
public static void Main(FileInfo file, bool json = false, bool hasHeader = false, int iterations = 100, double evaporationRate = 0.1)
{
Console.Write("Чтение файла...");
var sw = new Stopwatch();
sw.Start();
double[][] distances = json ? ParseEdgeJsonAsync(file.FullName).Result! : ParseEdgeFile(file.FullName, hasHeader);
Console.WriteLine($"\rСчитано {distances.Length} вершин за {sw.Elapsed} ({sw.ElapsedMilliseconds} мс).\n");
var aco = new AntColonyOptimizer(distances: distances, evaporationRate: evaporationRate)
.AddAnts(10, 1, 2, 100) // 10 муравьев, для которых расстояние в 2 раза важнее феромонов
.AddAnts(10, 1, 1, 100) // 10 муравьев, для которых расстояние столь же важно, сколько феромоны
.AddAnts(10, 1, 5, 200) // 10 муравьев, для которых расстояние в 5 раз важнее феромонов, и которые оставляют в 2 раза больше феромонов
.CompileAnts(shuffle: true); // перемешиваем муравьев. По надобности можно оставить в исходном порядке
sw.Reset();
Console.CancelKeyPress += (e, f) =>
{
var (tour, distance) = aco.EarlyExit();
Console.WriteLine("\n\n" + new string('-', Console.BufferWidth));
Console.CursorLeft = 0;
Console.WriteLine($"\nРанняя остановка. Время работы: {sw.Elapsed}\n");
if (tour.Count == 0) Console.WriteLine("Путь не найден.");
else Console.WriteLine($"Лучший путь (длина {distance}):\n[ {string.Join(", ", tour)} ]");
};
sw.Start();
var (bestTour, bestDistance) = aco.Solve(iterations);
Console.WriteLine(new string('-', Console.BufferWidth));
Console.WriteLine($"Задача решена за {sw.Elapsed} ({sw.ElapsedMilliseconds} мс).");
if (bestTour.Count == 0)
{
Console.WriteLine("Гамильтонов цикл не найден.");
return;
}
Console.WriteLine($"Лучший путь:\n[ {string.Join(", ", bestTour)} ]");
Console.WriteLine($"Длина: {bestDistance}.");
}
private static async Task ParseEdgeJsonAsync(string filePath)
{
using var s = File.OpenRead(filePath);
return await JsonSerializer.DeserializeAsync(s);
}
private static double[][] ParseEdgeFile(string filePath, bool skipHeader)
{
List lines = [.. File.ReadAllLines(filePath)];
if (skipHeader) lines.RemoveAt(0);
HashSet vertices = [];
int maxVertex = 0;
foreach (string line in lines)
{
string[] parts = line.Split();
if (parts.Length != 3)
continue;
if (int.TryParse(parts[0], out int v1))
vertices.Add(v1);
if (int.TryParse(parts[1], out int v2))
vertices.Add(v2);
maxVertex = int.Max(maxVertex, v1);
maxVertex = int.Max(maxVertex, v2);
}
double[][] adjacencyMatrix = new double[maxVertex + 1][];
for (int i = 0; i < maxVertex + 1; i++)
{
adjacencyMatrix[i] = new double[maxVertex + 1];
for (int j = 0; j < maxVertex + 1; j++)
{
adjacencyMatrix[i][j] = 0.0;
}
}
foreach (string line in lines)
{
string[] parts = line.Split();
if (parts.Length != 3)
continue;
if (int.TryParse(parts[0], out int v1) &&
int.TryParse(parts[1], out int v2) &&
double.TryParse(parts[2], out double distance))
{
adjacencyMatrix[v1][v2] = distance;
adjacencyMatrix[v2][v1] = distance;
}
}
return adjacencyMatrix;
}
}