namespace Katas.Shorts
{
public class Edge
{
public Edge(Vertex firstVertex, Vertex secondVertex, double weight)
{
FirstVertex = firstVertex;
SecondVertex = secondVertex;
Weight = weight;
}
public Vertex FirstVertex { get; }
public Vertex SecondVertex { get; }
public double Weight { get; }
public override string ToString()
{
return $"{FirstVertex}-{Weight}-{SecondVertex}";
}
}
public class Vertex : IEnumerable<Vertex>
{
private readonly List<Edge> _neighbours = new List<Edge>();
public string Name { get; set; }
public double Cost { get; set; } = Double.PositiveInfinity;
public bool Visited { get; set; }
public Vertex(string name)
{
Name = name;
}
private void AddNeighbour(Edge edge)
{
_neighbours.Add(edge);
}
public void AddNeighbour(Vertex neighbour, double weight)
{
var edge = new Edge(this, neighbour, weight);
_neighbours.Add(edge);
neighbour.AddNeighbour(edge);
}
public Vertex FindLowestCost()
{
return _neighbours.Select(i => i.FirstVertex == this ? i.SecondVertex : i.FirstVertex)
.Where(i => i.Visited == false)
.OrderBy(i => i.Cost)
.FirstOrDefault();
}
public IEnumerator<Vertex> GetEnumerator()
{
foreach (Edge neighbour in _neighbours)
{
yield return neighbour.FirstVertex == this ? neighbour.SecondVertex : neighbour.FirstVertex;
}
}
public double GetWeightBetween(Vertex oppositeVertex)
{
var edge = _neighbours.FirstOrDefault(i =>
(i.FirstVertex == this && oppositeVertex == i.SecondVertex) ||
(i.SecondVertex == this && oppositeVertex == i.FirstVertex));
if (edge == null)
throw new InvalidOperationException();
return edge.Weight;
}
public override string ToString()
{
return Name;
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
public class Dijkstra
{
private static List<string> GetPath(Dictionary<string, string> parents)
{
string node = "fin";
var list = new List<string>();
while (parents.ContainsKey(node))
{
list.Add(node);
node = parents[node];
}
list.Add(node);
list.Reverse();
return list;
}
public static void Show()
{
var startNode = new Vertex("start");
startNode.Visited = true;
var a = new Vertex("a");
var b = new Vertex("b");
var c = new Vertex("c");
var d = new Vertex("d");
var e = new Vertex("e");
var fin = new Vertex("fin");
startNode.AddNeighbour(a, 6);
a.Cost = 6;
startNode.AddNeighbour(b, 2);
b.Cost = 2;
a.AddNeighbour(b, 3);
c.AddNeighbour(a, 1);
c.AddNeighbour(b, 5);
c.AddNeighbour(d, 2);
c.AddNeighbour(e, 3);
d.AddNeighbour(e, 1);
fin.AddNeighbour(d, 4);
fin.AddNeighbour(e, 5);
var parents = new Dictionary<string, string>();
var node = startNode.FindLowestCost();
while (node != null)
{
var cost = node.Cost;
foreach (Vertex vertex in node)
{
var newCost = cost + vertex.GetWeightBetween(node);
if (vertex.Cost > newCost)
{
vertex.Cost = newCost;
parents[vertex.Name] = node.Name;
}
}
node.Visited = true;
node = node.FindLowestCost();
}
Console.WriteLine($"Path: {string.Join("->", GetPath(parents))}");
}
}
}