Skip to content

Commit

Permalink
Start getting multiple same key working
Browse files Browse the repository at this point in the history
  • Loading branch information
IntelOrca committed Sep 4, 2024
1 parent d7fc455 commit 7ccab11
Show file tree
Hide file tree
Showing 2 changed files with 157 additions and 16 deletions.
89 changes: 89 additions & 0 deletions IntelOrca.Biohazard.BioRand/Routing/MultiSet.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
using System.Collections;
using System.Collections.Generic;

namespace IntelOrca.Biohazard.BioRand.Routing
{
internal class MultiSet<T> : ICollection<T>, IEnumerable<T>
{
private readonly Dictionary<T, int> _dict = new Dictionary<T, int>();
private int _count;

public int Count => _count;
public bool IsReadOnly => false;

public void Add(T item)
{
_dict.TryGetValue(item, out var count);
_dict[item] = count + 1;
_count++;
}

public void AddRange(IEnumerable<T> items)
{
foreach (var item in items)
{
Add(item);
}
}

public bool Remove(T item)
{
if (_dict.TryGetValue(item, out var count))
{
if (count > 1)
{
_dict[item] = count - 1;
_count--;
return true;
}
else
{
_dict.Remove(item);
if (count == 1)
{
_count--;
return true;
}
}
}
return false;
}

public int GetCount(T item)
{
_dict.TryGetValue(item, out var count);
return count;
}

public void Clear()
{
_dict.Clear();
_count = 0;
}

public bool Contains(T item) => GetCount(item) > 0;

public void CopyTo(T[] array, int arrayIndex)
{
foreach (var item in this)
{
array[arrayIndex++] = item;
}
}

bool ICollection<T>.Remove(T item) => Remove(item);

public IEnumerator<T> GetEnumerator()
{
foreach (var kvp in _dict)
{
for (var i = 0; i < kvp.Value; i++)
{
yield return kvp.Key;
}
}
}

IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
}
}
84 changes: 68 additions & 16 deletions IntelOrca.Biohazard.BioRand/Routing/RouteFinder.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using System.Text;

Expand All @@ -15,9 +16,9 @@ public class RouteFinder

private readonly HashSet<Node> _remainingNodes = new HashSet<Node>();
private readonly HashSet<Node> _remainingKeys = new HashSet<Node>();
private readonly HashSet<Node> _availableForKey = new HashSet<Node>();
private readonly HashSet<Node> _spareItems = new HashSet<Node>();
private readonly HashSet<Node> _visited = new HashSet<Node>();
private readonly HashSet<Node> _keys = new HashSet<Node>();
private readonly MultiSet<Node> _keys = new MultiSet<Node>();
private readonly StringBuilder _log = new StringBuilder();
private readonly OneToManyDictionary<Node, Node> _itemToKey = new OneToManyDictionary<Node, Node>();

Expand Down Expand Up @@ -49,12 +50,14 @@ public Route Find(Graph input)
private void DoSubgraph(IEnumerable<Node> start)
{
_visited.Clear();
_keys.Clear();
_start.Clear();
_start.AddRange(start);
foreach (var n in start)
{
var deps = GetHardDependencies(n);
_visited.UnionWith(deps);
_keys.AddRange(deps.Where(x => x.Kind == NodeKind.Key));
_visited.UnionWith(deps.Where(x => x.Kind != NodeKind.Key));
_next.Add(n);
}
while (DoPass() || Fulfill())
Expand All @@ -74,28 +77,24 @@ private bool DoPass()

private bool Fulfill()
{
var nextKeys = _next
.SelectMany(x => GetRequiredKeys(x))
.ToArray();
_keys.AddRange(nextKeys);

var keys = Shuffle(_keys);
foreach (var key in keys)
var checklist = GetChecklist();
var requiredKeys = Shuffle(checklist.SelectMany(x => x.Need).Distinct());
foreach (var key in requiredKeys)
{
// Find an item for this key
var available = Shuffle(_availableForKey.Where(x => x.Group == key.Group));
var available = Shuffle(_spareItems.Where(x => x.Group == key.Group));
if (available.Length != 0)
{
var rIndex = Rng(0, available.Length);
var item = available[rIndex];

_availableForKey.Remove(item);
_spareItems.Remove(item);
_itemToKey.Add(item, key);

Log($"Place {key} at {item}");

_keys.Remove(key);
VisitNode(key);
_keys.Add(key);
// VisitNode(key);
return true;
}
}
Expand Down Expand Up @@ -127,7 +126,7 @@ private void VisitNode(Node node)
// Add edges
_next.AddRange(_input.GetEdges(node));

_availableForKey.Add(node);
_spareItems.Add(node);
}

Log($"Satisfied node: {node}");
Expand Down Expand Up @@ -163,6 +162,53 @@ void Recurse(Node node)
}
}

private ImmutableArray<ChecklistItem> GetChecklist()
{
return _next.Select(GetChecklistItem).ToImmutableArray();
}

private ChecklistItem GetChecklistItem(Node node)
{
var haveList = new List<Node>();
var missingList = new List<Node>();
var requiredKeys = GetRequiredKeys(node)
.GroupBy(x => x)
.Select(x => (x.Key, x.Count()))
.ToArray();

foreach (var (key, need) in requiredKeys)
{
var have = _keys.GetCount(key);

var missing = Math.Max(0, need - have);
for (var i = 0; i < missing; i++)
missingList.Add(key);

var progress = Math.Min(have, need);
for (var i = 0; i < progress; i++)
haveList.Add(key);
}

return new ChecklistItem(node, haveList.ToImmutableArray(), missingList.ToImmutableArray());
}

private sealed class ChecklistItem
{
public Node Destination { get; }
public ImmutableArray<Node> Have { get; }
public ImmutableArray<Node> Need { get; }

public ChecklistItem(Node destination, ImmutableArray<Node> have, ImmutableArray<Node> need)
{
Destination = destination;
Have = have;
Need = need;
}

public override string ToString() => string.Format("{0} Have = {{{1}}} Need = {{{2}}}",
Destination, string.Join(", ", Have), string.Join(", ", Need));
}

private int Rng(int min, int max) => _rng.Next(min, max);
private T[] Shuffle<T>(IEnumerable<T> items)
{
Expand Down Expand Up @@ -191,7 +237,13 @@ private bool IsSatisfied(Node node)
}
else
{
return node.Requires.All(x => _visited.Contains(x));
var checklistItem = GetChecklistItem(node);
if (checklistItem.Need.Length > 0)
return false;

return node.Requires
.Where(x => x.Kind != NodeKind.Key)
.All(x => _visited.Contains(x));
}
}

Expand Down

0 comments on commit 7ccab11

Please sign in to comment.