Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p>Fun question, with many varied solutions. I've been thinking about it this afternoon and I would go for something like flood-fill with a priority queue (min-heap, perhaps). Let's call it the <code>fence</code>.</p> <p>You'll also want to keep track of which items have been visited. Mark all items as unvisited, initially.</p> <p>Start off by adding all points around the perimeter of your grid to the <code>fence</code>.</p> <p>Now you loop like so:</p> <p>Pop the front item from the <code>fence</code>. You have selected one of the lowest points on the perimeter.</p> <ul> <li>If the item has been visited, discard it and loop again.</li> <li>If it's unvisited, its height becomes your new water level only if it is greater than the current water level.</li> </ul> <p>You now do a flood-fill from that point. You can do this recursively (depth-first), but I will discuss this using an unordered queue (breadth-first). Let's call this queue the <code>flood</code>. You start by pushing the item onto <code>flood</code>.</p> <p>Flooding then goes like this: Loop until there are no items remaining in <code>flood</code>...</p> <ul> <li>Pop an item from <code>flood</code></li> <li>If it is already visited, ignore it and loop again.</li> <li>If the item height is less than or equal to the current water level, compute the height difference and add that to your total volume. Mark the item as visited, then add all unvisited neighbours to <code>flood</code>.</li> <li>If the item height is greater than the current water level, just add it to <code>fence</code>. You'll want to have a way to tell whether the item is already in <code>fence</code> - you don't want to add it again. Maybe you can extend your 'visited' flags to cope with this.</li> </ul> <p>And that's it. Admittedly it was just a thought experiment while I lay around feeling hungover and seedy, but I reckon it's good.</p> <hr> <p>As you requested... Some pseudocode.</p> <p>Initial setup:</p> <pre><code>## Clear flags. Note I've added a 'flooding' flag for each item in map item.visited &lt;- false # true means item has had its water depth added item.fenced &lt;- false # true means item is in the fence queue item.flooding &lt;- false # true means item is in the flooding queue end ## Set up perimeter for each item on edge of map (top, left, right, bottom) push item onto fence end waterlevel &lt;- 0 total &lt;- 0 </code></pre> <p>Now the main chunk of the algorithm</p> <pre><code>while fence has items item &lt;- pop item from fence if item.visited = true then loop again ## Update water level if item.height &gt; waterlevel then waterlevel = item.height ## Flood-fill item using current water level push item onto flood item.flooding &lt;- true while flood has items item &lt;- pop item from flood depth &lt;- waterlevel - item.height if depth &gt;= 0 then # Item is at or below water level. Add its depth to total. total &lt;- total + depth item.visited &lt;- true # Consider all immediate neighbours of item. for each neighbour of item if neighbour.visited = false then if neighbour.flooding = false then push neighbour onto flood neighbour.flooding &lt;- true end end end else # Item is above water item.flooding &lt;- false if item.fenced = false then push item onto fence item.fenced &lt;- true end end end end </code></pre>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload