I have a very simple function which takes in a matching bitfield, a grid, and a square. It used to use a delegate but I did a lot of recoding and ended up with a bitfield &
operation to avoid the delegate while still being able to perform matching within reason. Basically, the challenge is to find all contiguous elements within a grid which match the match
bitfield, starting from a specific "leader" square.
Square is somewhat small (but not tiny) class. Any tips on how to push this to be even faster? Note that the grid itself is pretty small (500 elements in this test).
Edit: It's worth noting that this function is called over 200,000 times per second. In truth, in the long run my goal will be to call it less often, but that's really tough, considering that my end goal is to make the grouping system be handled with scripts rather than being hardcoded. That said, this function is always going to be called more than any other function.
Edit: To clarify, the function does not check if leader
matches the bitfield, by design. The intention is that the leader is not required to match the bitfield (though in some cases it will).
Things tried unsuccessfully:
- Initializing the dictionary and stack with a capacity.
- Casting the int to an enum to avoid a cast.
- Moving the dictionary and stack outside the function and clearing them each time they are needed. This makes things slower!
Things tried successfully:
- Writing a hashcode function instead of using the default: Hashcodes are precomputed and are equal to
x + y * parent.Width
. Thanks for the reminder, Jim Mischel. - mquander's Technique: See
GetGroupMquander
below. Further Optimization: Once I switched to HashSets, I got rid of the
Contains
test and replaced it with anAdd
test. BothContains
andAdd
are forced to seek a key, so just checking if an add succeeds is more efficient than adding if aContains
fails check fails. That is,if (RetVal.Add(s)) curStack.Push(s);
public static List<Square> GetGroup(int match, Model grid, Square leader) { Stack<Square> curStack = new Stack<Square>(); Dictionary<Square, bool> Retval = new Dictionary<Square, bool>(); curStack.Push(leader); while (curStack.Count != 0) { Square curItem = curStack.Pop(); if (Retval.ContainsKey(curItem)) continue; Retval.Add(curItem, true); foreach (Square s in curItem.Neighbors) { if (0 != ((int)(s.RoomType) & match)) { curStack.Push(s); } } } return new List<Square>(Retval.Keys); }
=====
public static List<Square> GetGroupMquander(int match, Model grid, Square leader)
{
Stack<Square> curStack = new Stack<Square>();
Dictionary<Square, bool> Retval = new Dictionary<Square, bool>();
Retval.Add(leader, true);
curStack.Push(leader);
while (curStack.Count != 0)
{
Square curItem = curStack.Pop();
foreach (Square s in curItem.Neighbors)
{
if (0 != ((int)(s.RoomType) & match))
{
if (!Retval.ContainsKey(s))
{
curStack.Push(s);
Retval.Add(curItem, true);
}
}
}
}
return new List<Square>(Retval.Keys);
}