using System.Collections;
using System.Collections.Generic;
static readonly string[] RomanOrdinals = new[] { "I", "II", "III", "IV", "V", "VI", "VII", "VIII", "IX", "X" };
public static void Main()
var nodes = new NodeCollection();
nodes["A"].GetPort(1, true).ConnectTo(nodes["B"].GetPort(1));
nodes["B"][2].ConnectTo(nodes["C"][1]);
nodes["C"][2].ConnectTo(nodes["D"][1]);
nodes["D"][2].ConnectTo(nodes["E"][1]);
nodes["D"][2].ConnectTo(nodes["F"][1]);
nodes["C"][2].ConnectTo(nodes["F"][1], true);
Console.WriteLine("Adding Networks...");
var AllConnections = nodes.SelectMany(n => n.AllPorts).SelectMany(n => n.NormalConnections.Concat(n.BackupConnections)).Distinct();
foreach (var connection in AllConnections.OrderBy(c => c.IsBackup).ThenBy(c => $"{c.Left}_{c.Right}").ToArray().Where(c => c.Network is null))
connection.AddToNetwork(RomanOrdinals[netNum++]);
Console.WriteLine(new string('-', 40));
Console.WriteLine("Connections:");
foreach (var connection in AllConnections.OrderBy(c => $"{c.Left}_{c.Right}"))
Console.WriteLine($"\t{connection}");
from p in new[] { c.Left, c.Right }
group p by c.Network into grp
select new { Network = grp.Key, Ports = grp.Distinct().ToArray() }
group c by c.Network into grp
select new { Network = grp.Key, Connections = grp.Distinct().ToArray() }
) on np.Network equals nc.Network
select new { np.Network, np.Ports, nc.Connections, IsBackup = nc.Connections.Any(c => c.IsBackup) };
Console.WriteLine("Networks:");
foreach (var net in networks.OrderBy(c => c.IsBackup))
Console.WriteLine($"\tNetwork: {net.Network}{(net.IsBackup ? "(b)" : string.Empty)}");
foreach (var port in net.Ports)
Console.WriteLine($"\t\tPort: {port.Node.ID}.{port.ID}");
foreach (var conn in net.Connections)
Console.WriteLine($"\t\tConn: {conn.Left.Node.ID}.{conn.Left.ID} <=> {conn.Right.Node.ID}.{conn.Right.ID}");
public string ID { get; }
private readonly Dictionary<int, Port> _ports = new Dictionary<int, Port>();
public Port this[int id] => GetPort(id);
public IEnumerable<Port> AllPorts => _ports.Values;
public Port GetPort(int id, bool create = true)
if (!_ports.TryGetValue(id, out var res))
_ports[id] = res = new Port(this, id);
public override string ToString() => $"Node_{ID}";
public Node Node { get; }
private readonly List<Connection> _connections = new List<Connection>();
public string Network => string.Join(", ", new[]
NormalConnections.FirstOrDefault(c => c.Network != null)?.Network,
BackupConnections.Where(c => c.Network != null).Select(c => c.Network + "(b)").FirstOrDefault()
}.Where(r => r != null));
public Port(Node node, int id)
public void ConnectTo(Port other, bool isBackup = false)
if (!_connections.Any(c => c.Left == other || c.Right == other))
var connection = new Connection(this, other, isBackup);
_connections.Add(connection);
other._connections.Add(connection);
public IEnumerable<Connection> NormalConnections => _connections.Where(c => !c.IsBackup);
public IEnumerable<Connection> BackupConnections => _connections.Where(c => c.IsBackup);
public override string ToString() => $"Port_{Node.ID}.{ID}{(Network is null ? string.Empty : $" [Net: {Network}]")}";
public string ToString(string format)
res += " (" + string.Join(", ", _connections.Select(c => { var x = c.Left == this ? c.Right : c.Left; return $"{x.Node.ID}.{x.ID}"; })) + ")";
public Port Left { get; }
public Port Right { get; }
public bool IsBackup { get; }
public string Network { get; private set; }
public Connection(Port p1, Port p2, bool isBackup = false)
if (string.Compare(p1.ToString(), p2.ToString()) < 0)
public void AddToNetwork(string network)
Console.WriteLine($"<{this}>.AddToNetwork({network})");
var visited = new List<Connection>();
var queue = new Queue<Connection>();
var curr = queue.Dequeue();
Console.WriteLine($"\t{curr}");
foreach (var con in new[] { Left, Right }.SelectMany(p => (IsBackup ? p.BackupConnections : p.NormalConnections)).Where(c => !visited.Contains(c)))
public override string ToString() => $"{Left.Node.ID}.{Left.ID} <=> {Right.Node.ID}.{Right.ID}{(Network is null ? string.Empty : $" N:{Network}")}{(IsBackup ? " [Backup]" : string.Empty)}";
class NodeCollection : IEnumerable<Node>
private readonly List<Node> _nodes = new List<Node>();
public Node this[string id]
if (!TryGetValue(id, out var res))
_nodes.Add(res = new Node(id));
public bool TryGetValue(string id, out Node res)
res = _nodes.FirstOrDefault(n => n.ID == id);
public void AddRange(params string[] ids)
if (!TryGetValue(id, out _))
_nodes.Add(new Node(id));
public IEnumerator<Node> GetEnumerator() => _nodes.GetEnumerator();
IEnumerator IEnumerable.GetEnumerator() => _nodes.GetEnumerator();