I’m just dipping my toes into DOTS so apologies if I’m completely out to sea here.
I’ve implemented an algorithm called priority flood (https://rbarnes.org/sci/2014_depressions.pdf) that fills depressions in a generated terrain to ensure that every point drains to the sea.
It runs in 4 seconds on a 512x512 grid and generates a ton of garbage. I’m sure this code could be optimized and I’m not sure if the priority queue I’m using is working that well, but I figured if I could implement it in DOTS it might help and serve as a learning experience.
My question is: since this algorithm starts with a coastline and fills inland, meaning a point cannot be marked as a depression until the entire frontier has been evaluated, I can’t see a way to break this up into multiple jobs. Does the “performance by default” method of writing code also speed up an expensive algorithm run a single time? Or does it only provide a benefit if you’re running an algorithm hundreds and thousands of times?
non DOTS code below:
public class PriorityFloodSingleThread
{
int[] edge;
int[] dem;
Dictionary<int, bool> closed;
Dictionary<int, float> heights;
SimplePriorityQueue<int> open = new SimplePriorityQueue<int>();
Queue<int> pit = new Queue<int>();
World.MapGen map;
public PriorityFloodSingleThread(int[] dem, int[] edge) {
this.edge = edge;
this.dem = dem;
map = World.MapGen.Instance;
closed = new Dictionary<int, bool>(dem.Length);
heights = new Dictionary<int, float>(dem.Length);
foreach (var index in dem) {
closed[index] = false;
}
foreach (var index in dem) {
heights[index] = map.Height(index);
}
}
public Dictionary<int,float> Flood() {
foreach (var c in edge) {
open.Enqueue(c, map.Height(c));
closed[c] = true;
}
float pitTop = -1f;
while (open.Count > 0 || pit.Count > 0) {
int c;
if((pit.Count > 0 && open.Count > 0) && pit.Peek() == open.First) {
pit.Dequeue();
c = open.Dequeue();
pitTop = -1f;
}
else if(pit.Count > 0) {
c = pit.Dequeue();
if(pitTop == -1f) {
pitTop = map.Height(c);
}
}
else {
c = open.Dequeue();
pitTop = -1f;
}
foreach (var n in map.GetNeighbors(c)) {
if (map.waterMap[n]) {
closed[n] = true;
}
if (closed[n]) continue;
closed[n] = true;
if (heights[n] <= heights[c]) {
heights[n] = heights[c] + .0001f;
pit.Enqueue(n);
}
else {
open.Enqueue(n, heights[n]);
}
}
}
return heights;
}
}