Skip to content

Commit

Permalink
Add more tests
Browse files Browse the repository at this point in the history
  • Loading branch information
IntelOrca committed Sep 4, 2024
1 parent 3cafce8 commit adfb3de
Show file tree
Hide file tree
Showing 3 changed files with 141 additions and 7 deletions.
53 changes: 51 additions & 2 deletions IntelOrca.Biohazard.BioRand.Tests/TestRouting.cs
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,55 @@ public void Basic()
}
}

[Fact]
public void KeyBehindKey()
{
for (var i = 0; i < Retries; i++)
{
var builder = new GraphBuilder();

var key0 = builder.Key(1, "KEY 0");
var key1 = builder.Key(1, "KEY 1");
var room0 = builder.AndGate("ROOM 0");
var item0a = builder.Item(1, "ITEM 0.A", room0);
var item0b = builder.Item(1, "ITEM 0.B", room0);
var item0c = builder.Item(1, "ITEM 0.C", room0, key0);
var room1 = builder.AndGate("ROOM 1", room0, key0, key1);

var route = builder.GenerateRoute(i);

AssertKeyOnce(route, key0, item0a, item0b);
AssertKeyOnce(route, key1, item0a, item0b, item0c);
Assert.True(route.AllNodesVisited);
}
}

/// <summary>
/// An edge case where the keys must be placed in a certain order,
/// otherwise we run out of accessible item nodes for all the keys.
/// </summary>
[Fact]
public void KeyOrderMatters()
{
for (var i = 0; i < Retries; i++)
{
var builder = new GraphBuilder();

var key0 = builder.Key(1, "KEY 0");
var key1 = builder.Key(1, "KEY 1");
var room0 = builder.AndGate("ROOM 0");
var item0a = builder.Item(1, "ITEM 0.A", room0);
var item0b = builder.Item(1, "ITEM 0.B", room0, key0);
var room1 = builder.AndGate("ROOM 1", room0, key0, key1);

var route = builder.GenerateRoute(i);

AssertKeyOnce(route, key0, item0a);
AssertKeyOnce(route, key1, item0b);
Assert.True(route.AllNodesVisited);
}
}

/// <summary>
/// Test that when we fulfill a key, we don't add its edges to the next list.
/// This prevents cases where we place keys prematurely before we require them.
Expand Down Expand Up @@ -185,7 +234,7 @@ private static void AssertKeyOnce(Route route, Node key, params Node[] expected)
Assert.True(items.Length == expected.Length,
string.Format("Expected {0} to be at {{{1}}} but was not placed",
key,
string.Format(", ", expected)));
string.Join(", ", expected)));
}
else
{
Expand All @@ -194,7 +243,7 @@ private static void AssertKeyOnce(Route route, Node key, params Node[] expected)
Assert.True(Array.IndexOf(expected, item) != -1,
string.Format("Expected {0} to be at {{{1}}} but was at {2}",
key,
string.Format(", ", expected),
string.Join(", ", expected),
item));
}
}
Expand Down
2 changes: 2 additions & 0 deletions IntelOrca.Biohazard.BioRand/Routing/MermaidBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ private static (string, string) GetShape(MermaidShape shape)
return shape switch
{
MermaidShape.Square => ("[", "]"),
MermaidShape.DoubleSquare => ("[[", "]]"),
MermaidShape.Rounded => ("(", ")"),
MermaidShape.Circle => ("((", "))"),
MermaidShape.Hexagon => ("{{", "}}"),
Expand All @@ -79,6 +80,7 @@ private static (string, string, string) GetEdgeType(MermaidEdgeType type)
public enum MermaidShape
{
Square,
DoubleSquare,
Rounded,
Circle,
Hexagon
Expand Down
93 changes: 88 additions & 5 deletions IntelOrca.Biohazard.BioRand/Routing/Node.cs
Original file line number Diff line number Diff line change
Expand Up @@ -261,23 +261,101 @@ public sealed class Route
{
public Graph Graph { get; }
public bool AllNodesVisited { get; }
public ImmutableDictionary<Node, Node> Fulfilled { get; }
public ImmutableDictionary<Node, Node> ItemToKey { get; }
public ImmutableDictionary<Node, ImmutableArray<Node>> KeyToItems { get; }
public string Log { get; }

public Route(Graph graph, bool allNodesVisited, ImmutableDictionary<Node, Node> fulfilled, string log)
public Route(
Graph graph,
bool allNodesVisited,
ImmutableDictionary<Node, Node> itemToKey,
ImmutableDictionary<Node, ImmutableArray<Node>> keyToItems,
string log)
{
Graph = graph;
AllNodesVisited = allNodesVisited;
Fulfilled = fulfilled;
ItemToKey = itemToKey;
KeyToItems = keyToItems;
Log = log;
}

public Node? GetItemContents(Node item)
{
if (Fulfilled.TryGetValue(item, out var result))
if (ItemToKey.TryGetValue(item, out var result))
return result;
return null;
}

public string GetDependencyTree(Node node, bool keysAsNodes = false)
{
var visited = new HashSet<Node>();
var mb = new MermaidBuilder();
Visit(node);
return mb.ToString();

void Visit(Node n)
{
if (!visited.Add(n))
return;

if (keysAsNodes || n.Kind != NodeKind.Key)
{
var label = n.Label;
if (n.Kind == NodeKind.Item && !keysAsNodes)
{
if (ItemToKey.TryGetValue(n, out var key))
{
label += $"\n<small>{key}</small>";
}
}
mb.Node($"N{n.Id}", label,
n.Kind switch
{
NodeKind.Key => MermaidShape.Hexagon,
NodeKind.Item => keysAsNodes
? MermaidShape.Square
: MermaidShape.DoubleSquare,
_ => MermaidShape.Circle,
});
}
if (n.Kind == NodeKind.Key)
{
if (KeyToItems.TryGetValue(n, out var items))
{
foreach (var item in items)
{
Visit(item);
if (keysAsNodes)
mb.Edge($"N{item.Id}", $"N{n.Id}",
type: items.Length == 1 ? MermaidEdgeType.Solid : MermaidEdgeType.Dotted);
}
}
}
else
{
foreach (var r in n.Requires)
{
Visit(r);
if (r.Kind == NodeKind.Key && !keysAsNodes)
{
if (KeyToItems.TryGetValue(r, out var items))
{
foreach (var item in items)
{
Visit(item);
mb.Edge($"N{item.Id}", $"N{n.Id}",
type: items.Length == 1 ? MermaidEdgeType.Solid : MermaidEdgeType.Dotted);
}
}
}
else
{
mb.Edge($"N{r.Id}", $"N{n.Id}");
}
}
}
}
}
}

public class RouteFinder
Expand Down Expand Up @@ -315,7 +393,12 @@ public Route Find(Graph input)
next = TakeNextNodes(IsSatisfied);
}

return new Route(_input, _next.Count == 0, _itemToKey.ToImmutableDictionary(), _log.ToString());
return new Route(
_input,
_next.Count == 0,
_itemToKey.ToImmutableDictionary(),
_keyToItems.ToImmutableDictionary(x => x.Key, x => x.Value.ToImmutableArray()),
_log.ToString());
}

private void DoSubgraph(IEnumerable<Node> start)
Expand Down

0 comments on commit adfb3de

Please sign in to comment.