rj-action-library/Runtime/Graphs/GraphWalker.cs

140 lines
3.0 KiB
C#

using System.Collections;
using System.Collections.Generic;
using System;
namespace Rokojori
{
public abstract class GraphWalker<N> where N:class
{
public virtual int NumConnectedFrom( N node ){ return 0;}
public virtual N GetConnectedFrom( N node, int index ){ return default(N);}
public abstract int NumConnectedTo( N node );
public abstract N GetConnectedTo( N node, int index );
public int NumConnectedAll( N node )
{
return NumConnectedTo( node ) + NumConnectedFrom( node );
}
public N GetConnected( N node, int index )
{
var fromConnections = NumConnectedFrom( node );
return index < fromConnections ? GetConnectedFrom( node, index ) : GetConnectedTo( node, index - fromConnections );
}
public bool IsConnectedTo( N source, N destination )
{
var processed = new HashSet<N>();
var toDo = new List<N>();
toDo.Add( source );
while ( toDo.Count > 0 )
{
var current = Lists.RemoveFirst( toDo );
if ( processed.Contains( current ) )
{
continue;
}
processed.Add( current );
var numConnected = NumConnectedTo( current );
for ( int i = 0; i < numConnected; i++ )
{
var connected = GetConnected( current, i );
if ( connected == destination )
{
return true;
}
if ( ! processed.Contains( connected ) )
{
toDo.Add( connected );
}
}
}
return false;
}
public bool IsDirectlyConnectedTo( N node, N other )
{
if ( node == null || other == null )
{
return false;
}
var connected = NumConnectedTo( node );
for ( int i = 0; i < connected; i++ )
{
if ( GetConnected( node, i ) == other )
{
return true;
}
}
return false;
}
public List<N> ComputeOrder( List<N> nodes )
{
var processed = new HashSet<N>();
var unprocessed = nodes.Clone();
var order = new List<N>();
while ( unprocessed.Count > 0 )
{
var itemIndex = -1;
for ( int i = 0; itemIndex == -1 && i < unprocessed.Count; i++ )
{
if ( CanProcess( unprocessed[ i ], processed ) )
{
itemIndex = i;
}
}
if ( itemIndex == -1 )
{
order.AddRange( unprocessed );
return order;
}
var item = unprocessed[ itemIndex ];
unprocessed.RemoveAt( itemIndex );
processed.Add( item );
order.Add( item );
}
return order;
}
bool CanProcess( N n, HashSet<N> processed )
{
var dependencies = NumConnectedFrom( n );
for ( int i = 0 ; i < dependencies; i++ )
{
var connected = GetConnectedFrom( n, i );
if ( ! processed.Contains( connected ) )
{
return false;
}
}
return true;
}
}
}