Tips on finding the volume of water in a 3d chess board

前端 未结 5 1664
栀梦
栀梦 2021-02-10 07:48

So I have an assignment where I have to recreate a 3d chessboard that is a RxC grid of squares each being a different height. If the chessboard is water tight, and someone pours

5条回答
  •  悲哀的现实
    2021-02-10 08:22

    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 fence.

    You'll also want to keep track of which items have been visited. Mark all items as unvisited, initially.

    Start off by adding all points around the perimeter of your grid to the fence.

    Now you loop like so:

    Pop the front item from the fence. You have selected one of the lowest points on the perimeter.

    • If the item has been visited, discard it and loop again.
    • If it's unvisited, its height becomes your new water level only if it is greater than the current water level.

    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 flood. You start by pushing the item onto flood.

    Flooding then goes like this: Loop until there are no items remaining in flood...

    • Pop an item from flood
    • If it is already visited, ignore it and loop again.
    • 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 flood.
    • If the item height is greater than the current water level, just add it to fence. You'll want to have a way to tell whether the item is already in fence - you don't want to add it again. Maybe you can extend your 'visited' flags to cope with this.

    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.


    As you requested... Some pseudocode.

    Initial setup:

    ## Clear flags.  Note I've added a 'flooding' flag
    for each item in map
        item.visited <- false     # true means item has had its water depth added
        item.fenced <- false      # true means item is in the fence queue
        item.flooding <- 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 <- 0
    total <- 0
    

    Now the main chunk of the algorithm

    while fence has items
        item <- pop item from fence
        if item.visited = true then loop again
    
        ## Update water level
        if item.height > waterlevel then waterlevel = item.height
    
        ## Flood-fill item using current water level
        push item onto flood
        item.flooding <- true
    
        while flood has items
            item <- pop item from flood
            depth <- waterlevel - item.height
    
            if depth >= 0 then
                # Item is at or below water level.  Add its depth to total.
                total <- total + depth
                item.visited <- 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 <- true
                        end
                    end
                end
            else
                # Item is above water
                item.flooding <- false
                if item.fenced = false then
                    push item onto fence
                    item.fenced <- true
                end
            end
    
        end
    end
    

提交回复
热议问题