|Just another Perl shrine|
Re: Distribute locations evenly on a mapby blokhead (Monsignor)
|on Nov 30, 2009 at 23:48 UTC||Need Help??|
This reminds me of image resizing by seam carving, and I think the solution to your problem could be informed by theirs.
In their setting, they had an image and wanted to "squish" away "unimportant" parts during the resize, while maintaining the remaining image information. Their solution was to find "seams" in the image. A seam is a path between opposite edges of an image, using any combination of straight or diagonal moves (in this way, a seam is a "contiguous" strand of pixels but need not be simply a row or column). Their approach was to use a dynamic programming algorithm to find a seam whose removal would cause the least "disturbance" in an image.
Here, your solution could be even easier. You have an "image" made up of "." and non-"." pixels. You want to find and remove any horizontal or vertical seams made up of entirely "." pixels. This can also be done in a simple dynamic programming way.
It prints out the result after removing successive vertical seams, until no more can be removed.
If you applied the same approach and then went on to remove horizontal seams, you would get
This is because the diagonal dots constitute a seam. From your example, it is possible that you have the following unwritten rule: If two X's do not start out adjacent, then they should not become adjacent as a result of seam removal. To accomplish this, you can simply add a "buffer" around the X's:
I used ":" as the "buffer" -- You only need to add buffer space on the east & south sides of every initial "X", instead of around all sides. Adding buffer around all sides would prevent distant X's from getting squished to within 2 cells of each other. Now removing the horizontal seams as well would result in your example output.
Update: another example:
is squished to:
I didn't put a "south" buffer on, so the middle "island" gets squished to be adjacent to the stuff on the bottom-left.