สร้างแผนที่จริง


25

ฉันวาดแผนที่ของภูมิภาคของคำจินตนาการในไม่กี่นาทีใน MS Paint:

แผนที่ของฉัน

ฉันคิดว่าการสร้างแผนที่แบบนี้โดยทางโปรแกรมจะเจ๋งจริงๆ

ท้าทาย

เขียนโปรแกรมที่ใช้ในจำนวนเต็มบวกWและและชุดที่ไม่ว่างเปล่าของจำนวนเต็มบวกHS

สร้างภาพสีมาตรฐานที่มีWความกว้างHพิกเซลสูงพิกเซล

สำหรับแต่ละจำนวนเต็มiในSวาดภูมิภาคระนาบในภาพที่มีพื้นที่พิกเซลเป็นสัดส่วนกับiการใช้สีที่แตกต่างจากภูมิภาคใกล้เคียงใด ๆ โดยเฉพาะจำนวนพิกเซลในภูมิภาคควรจะW * H * i / sum(S)ปัดขึ้นหรือลงเพื่อให้มั่นใจว่าพิกเซลในภาพเป็นของภูมิภาค

พื้นที่ภาพถ่ายเป็นชุดของพิกเซลที่มีคุณสมบัติที่พิกเซลใด ๆ ในภูมิภาคสามารถเข้าถึงได้จากที่อื่นโดยอยู่ภายในภูมิภาคและเคลื่อนที่แบบ orthogonally เท่านั้น (ไม่ใช่แนวทแยงมุม) แผนที่ของฉันด้านบนมีพื้นที่ระนาบ 10 ส่วน

พิกเซลทั้งหมดในพื้นที่ภาพถ่ายจะต้องมีสีเดียวกันซึ่งจะต้องแตกต่างจากสีของพื้นที่ใกล้เคียง ภูมิภาคอาจมีสีเดียวกันหากพวกเขาไม่ใช่เพื่อนบ้าน

มิฉะนั้นจะไม่มีข้อ จำกัด ในการกำหนดตำแหน่งหรือสีภูมิภาคของคุณ นี่คือการประกวดความนิยม เป้าหมายคือการสร้างโปรแกรมที่สร้างแผนที่ความเป็นจริงของโลกจินตภาพทางกายภาพหรือทางการเมืองด้วยภูมิศาสตร์ทุกระดับ

โปรดแสดงภาพที่ดีที่สุดของคุณไม่ใช่แค่รหัสของคุณ

รายละเอียด

  • รับอินพุตจากไฟล์บรรทัดคำสั่ง stdin หรือที่คล้ายกัน บันทึกภาพในรูปแบบมาตรฐานหรือแสดงเป็นหน้าจอ
  • โปรแกรมของคุณควรถูกกำหนดไว้สำหรับอินพุตที่เหมือนกัน นั่นคือภาพออกควรจะเหมือนกันสำหรับบางคนโดยเฉพาะอย่างยิ่งH, และW S(โปรดทราบว่าSเป็นชุดไม่ใช่รายการดังนั้นการสั่งซื้อจึงไม่สำคัญ) มิฉะนั้นคุณอาจใช้การสุ่มตามที่ต้องการแม้ว่าคุณจะไม่จำเป็นต้องใช้ (แต่ฉันขอแนะนำอย่างยิ่ง)
  • ภูมิศาสตร์รูปภาพผลลัพธ์ไม่จำเป็นต้อง "ปรับ" สำหรับค่าที่แตกต่างกันของWหรือH(แม้ว่าจะทำได้) มันอาจจะแตกต่างอย่างสิ้นเชิง
  • คุณอาจกำหนดสีแบบสุ่มโดยไม่คำนึงถึงกฎสีเพื่อนบ้านตราบใดที่มีความเป็นไปได้ของสีแบบสุ่มอย่างน้อย 32 อันเนื่องจากมันไม่น่าเป็นไปได้ที่เพื่อนบ้านทั้งสองจะได้สีเดียวกัน
  • ภูมิภาคหยุดที่ขอบเขตภาพ ไม่มีเป็นรอบห่อ
  • ภูมิภาคอาจมีศูนย์พิกเซล (และทำให้ไม่มีอยู่) ดังเช่นในกรณีที่มีพื้นที่มากกว่าพิกเซล

ตัวอย่างการป้อนข้อมูล

การส่งที่ถูกต้องอาจสร้างแผนที่ของฉันด้านบนด้วยพารามิเตอร์:

W = 380
H = 260
S = {233, 420, 1300, 3511, 4772, 5089, 9507, 22107, 25117, 26744}

Sค่าเหล่านี้เป็นค่าที่แน่นอนเหมือนกับจำนวนพิกเซลในแต่ละภูมิภาค แต่ไม่จำเป็นต้องเป็นกรณี โปรดจำไว้ว่าSเป็นชุดดังนั้นจึงไม่จำเป็นต้องเรียงลำดับเสมอ

คำตอบ:


15

ฉันเห็นด้วยกับคนอื่น ๆ นี่เป็นความท้าทายที่ยากอย่างน่าประหลาดใจ ส่วนหนึ่งเป็นเพราะความต้องการที่จะมีพิกเซลเชื่อมต่อติดกันในประเภทภูมิภาคเดียวกัน แต่ยังเกิดจากความท้าทายด้านสุนทรียภาพในการทำให้ภูมิภาคดูเหมือนแผนที่ของประเทศต่างๆ

นี่คือความพยายามของฉัน ... มันไม่มีประสิทธิภาพอย่างน่ากลัว แต่ดูเหมือนว่าจะสร้างผลลัพธ์ที่สมเหตุสมผล ดำเนินการต่อแนวโน้มของการใช้อินพุตทั่วไปเพื่อวัตถุประสงค์ในการเปรียบเทียบ:

พารามิเตอร์: 380 260 233 420 1300 3511 4772 5089 9507 22107 25117 26744

ป้อนคำอธิบายรูปภาพที่นี่

พารามิเตอร์: 380 260 8 5 6 7 8 4 5 6 7 9 4 6 9 5 8 7 5

ป้อนคำอธิบายรูปภาพที่นี่

Dark Age of Camelot 213 307 1 1 1

ป้อนคำอธิบายรูปภาพที่นี่

ตัวอย่างที่ใหญ่กว่าของฉัน: (640 480 6 1 7 2 9 3 4 5 6 1 9 8 7 44 3 1 9 4 5 6 7 2 3 4 9 3 4 5 9 8 7 5 6 1 2 1 2 1 2 6 7 8 9 9 63 3)

ป้อนคำอธิบายรูปภาพที่นี่

ตัวอย่างกับประเทศอื่น ๆ : 640 480 6 1 7 2 9 3 4 5 6 1 9 8 7 44 3 1 9 4 5 6 7 2 3 4 9 3 4 5 9 8 7 5 6 1 2 1 2 1 2 6 7 8 8 9 63 5 33 11 88 2 7 9 5 6 2 5 7

package GenerateRealisticMaps;

import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.Set;
import javax.imageio.ImageIO;

public class GenerateRealisticMaps
{
    private static final Random rand = new Random(3);
    private static final Color[] paletteizedColours = new Color[100];

    // create colour palette
    static
    {
        paletteizedColours[0] = new Color(0xFF000000);
        for (int i = 1; i < paletteizedColours.length; i++)
        {
            paletteizedColours[i] = Color.getHSBColor(rand.nextFloat(), rand.nextFloat(), 0.5f + rand.nextFloat() * 0.4f);
        }
    }

    /**
     * Represents a pixel that is the boundary of a region
     * @author default
     *
     */
    public static class BoundaryPixel
    {
        public BoundaryPixel(int x, int y, int otherRegionId)
        {
            super();
            this.x = x;
            this.y = y;
            this.otherRegionId = otherRegionId;
        }

        int x;
        int y;
        int otherRegionId;
    }

    /**
     * Group of adjacent pixels that represent a region (i.e. a country in the map)
     * @author default
     *
     */
    public static class Region
    {
        static private int masterId = 0;

        Region(int desiredSize)
        {
            this.desiredSize = desiredSize;
            id = ++masterId;
        }

        int desiredSize;
        int size = 0;
        int id;
        List<BoundaryPixel> boundary = new ArrayList<GenerateRealisticMaps.BoundaryPixel>();

    }

    /**
     * Container of regions
     * @author default
     *
     */
    public static class Regions
    {
        List<Region> regionList = new ArrayList<GenerateRealisticMaps.Region>();
        Map<Integer, Region> regionMap = new HashMap<Integer, GenerateRealisticMaps.Region>();
    }

    public static void main(String[] args) throws IOException
    {
        int width = Integer.parseInt(args[0]);
        int height = Integer.parseInt(args[1]);
        int[] s = new int[args.length - 2];

        // read in the region weights
        int sum = 0;
        for (int i = 0; i < args.length - 2; i++)
        {
            sum += s[i] = Integer.parseInt(args[i + 2]);
        }

        int totalPixels = width * height;

        double multiplier = ((double) totalPixels) / sum;

        // convert region weights to pixel counts
        int runningCount = 0;
        for (int i = 0; i < s.length - 1; i++)
        {
            runningCount += s[i] = (int) (multiplier * s[i]);
        }
        s[s.length - 1] = totalPixels - runningCount;

        Regions regions = new Regions();
        int[][] map = new int[width][height];

        // initialise region starting pixels
        for (int v : s)
        {
            Region region = new Region(v);
            regions.regionList.add(region);
            regions.regionMap.put(region.id, region);

            int x;
            int y;
            do
            {
                x = rand.nextInt(width);
                y = rand.nextInt(height);
            } while (map[x][y] != 0);

            map[x][y] = region.id;
            region.size++;

        }

        // initialise a "height" map that provides cost to claim a unclaimed region. This allows for more natural shaped countries
        int[][] heightMap = new int[width][height];
        for (int i = 0; i < width; i++)
        {
            for (int j = 0; j < height; j++)
            {
                heightMap[i][j] = rand.nextInt(50);
            }
        }

        boolean equal = false;

        // main loop
        do
        {
            growRegions(map, heightMap, width, height, regions);

            // determine whether regions have reached their desired size
            equal = true;
            for (Region region : regions.regionList)
            {
                equal = equal && region.size == region.desiredSize;
            }

            if (equal)
            {
                HashMap<Integer, Set<Integer>> commonIsolatedRegions = new HashMap<Integer, Set<Integer>>();
                int isolatedRegionId = 0;
                int[][] isolatedRegions = new int[width][height];
                List<Integer> isolatedRegionSize = new ArrayList<Integer>();
                isolatedRegionSize.add(-1); // add dummy entry at index 0 since region ids start at 1

                // go though each pixel and attempt to identify an isolated region from that point if it as not
                // yet been identified... i.e. an enclosed area.
                for (int i = 0; i < width; i++)
                {
                    for (int j = 0; j < height; j++)
                    {
                        if (isolatedRegions[i][j] == 0)
                        {
                            isolatedRegionId++;

                            Point point = new Point(i, j);
                            int size = identifyEnclosedArea(map, isolatedRegions, width, height, point, isolatedRegionId);

                            // add this isolated region id to the group of isolated regions associated with the region at this pixel
                            Set<Integer> isolatedRegionSet = commonIsolatedRegions.get(map[i][j]);
                            if (isolatedRegionSet == null)
                            {
                                isolatedRegionSet = new HashSet<Integer>();
                                commonIsolatedRegions.put(map[i][j], isolatedRegionSet);
                            }
                            isolatedRegionSet.add(isolatedRegionId);
                            isolatedRegionSize.add(size);
                        }
                    }
                }

                // only keep the largest isolated region in each group. Mark the other members in the group areas as unclaimed.
                for (Region region : regions.regionList)
                {
                    Set<Integer> isolatedRegionSet = commonIsolatedRegions.get(region.id);

                    // find the largest isolatedRegion mapped to this region
                    int largestIsolatedRegionId = -1;
                    int largestIsolatedRegionSize = -1;
                    for (Integer isolatedRegionIdentifier : isolatedRegionSet)
                    {
                        if (isolatedRegionSize.get(isolatedRegionIdentifier) > largestIsolatedRegionSize)
                        {
                            largestIsolatedRegionSize = isolatedRegionSize.get(isolatedRegionIdentifier);
                            largestIsolatedRegionId = isolatedRegionIdentifier;
                        }
                    }
                    // remove the largest isolated region (i.e. retain those pixels)
                    isolatedRegionSet.remove(largestIsolatedRegionId);

                    if (isolatedRegionSet.size() > 0)
                    {
                        equal = false;

                        // for all remaining isolated regions mapped to this region, convert to unclaimed areas.
                        for (Integer isolatedRegionIdentifier : isolatedRegionSet)
                        {
                            for (int i = 0; i < width; i++)
                            {
                                for (int j = 0; j < height; j++)
                                {
                                    if (isolatedRegions[i][j] == isolatedRegionIdentifier)
                                        map[i][j] = 0;
                                }
                            }
                        }
                    }
                }
            }

        } while (!equal);

        saveOutputImage("out.final.png", map);
    }

    /**
     * Renders and saves the output image
     * 
     * @param filename
     * @param map
     * @throws IOException
     */
    public static void saveOutputImage(String filename, int[][] map) throws IOException
    {

        final int scale = 1;
        final int width = map.length;
        final int height = map[0].length;
        BufferedImage image = new BufferedImage(width * scale, height * scale, BufferedImage.TYPE_INT_RGB);

        Graphics2D g = (Graphics2D) image.getGraphics();

        for (int j = 0; j < height; j++)
        {
            for (int i = 0; i < width; i++)
            {
                g.setColor(paletteizedColours[map[i][j]]);
                g.fillRect(i * scale, j * scale, scale, scale);
            }
        }

        ImageIO.write(image, "png", new File(filename));
    }

    /**
     * Grows the regions of the world. Firstly by unclaimed cells and then by distributing cells amongst the regions.
     * 
     * @param map
     *            cell to region map
     * @param heightMap
     *            the "height" cost of unclaimed cells. Used to give more natural shapes.
     * @param width
     * @param height
     * @param regions
     */
    public static void growRegions(int[][] map, int[][] heightMap, int width, int height, Regions regions)
    {
        // reset region sizes
        for (Region region : regions.regionList)
        {
            region.size = 0;
            region.boundary.clear();
        }

        // populate corners with adjacent pixel region id... these pixels cannot ever be "grown" into.
        map[0][0] = map[1][0];
        map[width - 1][0] = map[width - 1][5];
        map[width - 1][height - 1] = map[width - 2][height - 1];
        map[0][height - 1] = map[1][height - 1];

        int i, x, y, dx = 0, dy = 0, currHeight, currentId = -1, pixelRegionId;
        Region currRegion = null;
        ;

        // calculate initial region sizes
        for (y = 0; y < height; y++)
        {
            for (x = 0; x < width; x++)
            {
                if (map[x][y] > 0)
                    regions.regionMap.get(map[x][y]).size++;
            }
        }

        // expand regions into surrounding unclaimed pixels.
        // construct a list of region boundary pixels in the process.
        for (y = 1; y < height - 1; y++)
        {
            for (x = 1; x < width - 1; x++)
            {
                int cellId = map[x][y];
                if (cellId > 0)
                {
                    if (cellId != currentId)
                    {

                        currRegion = regions.regionMap.get(map[x][y]);
                        currentId = currRegion.id;
                    }

                    currHeight = heightMap[x][y]++;

                    for (i = 0; i < 4; i++)
                    {
                        switch (i)
                        {
                        case 0:
                            dx = x - 1;
                            dy = y;
                            break;
                        case 1:
                            dx = x + 1;
                            dy = y;
                            break;
                        case 2:
                            dx = x;
                            dy = y - 1;
                            break;
                        case 3:
                            dx = x;
                            dy = y + 1;
                            break;
                        }
                        pixelRegionId = map[dx][dy];
                        switch (pixelRegionId)
                        {
                        // unclaimed cell...
                        case 0:
                            if (heightMap[dx][dy] < currHeight)
                            {
                                map[dx][dy] = currRegion.id;
                                currRegion.size++;
                            }
                            break;
                        // claimed cell...
                        default:
                            if (pixelRegionId != currRegion.id)
                            {
                                currRegion.boundary.add(new BoundaryPixel(dx, dy, pixelRegionId));
                            }
                            break;
                        }
                    }
                }
            }
        }

        HashMap<Integer, List<BoundaryPixel>> neighbourBorders = new HashMap<Integer, List<BoundaryPixel>>();

        // for all regions...
        for (Region region : regions.regionList)
        {
            // that are less than the desired size...
            if (region.size < region.desiredSize)
            {
                neighbourBorders.clear();

                // identify the boundary segment per neighbour of the region
                for (BoundaryPixel boundaryPixel : region.boundary)
                {
                    List<BoundaryPixel> neighbourBorderSegment = neighbourBorders.get(boundaryPixel.otherRegionId);
                    if (neighbourBorderSegment == null)
                    {
                        neighbourBorderSegment = new ArrayList<GenerateRealisticMaps.BoundaryPixel>();
                        neighbourBorders.put(boundaryPixel.otherRegionId, neighbourBorderSegment);
                    }
                    neighbourBorderSegment.add(boundaryPixel);
                }

                out:
                // for each neighbour...
                for (int id : neighbourBorders.keySet())
                {
                    Region neighbourRegion = regions.regionMap.get(id);
                    int surplusPixelCount = neighbourRegion.size - neighbourRegion.desiredSize;
                    // that has surplus pixels...
                    if (surplusPixelCount > 0)
                    {
                        // and convert the border segment pixels to the current region...
                        List<BoundaryPixel> neighbourBorderSegment = neighbourBorders.get(id);
                        int index = 0;
                        while (surplusPixelCount-- > 0 && index < neighbourBorderSegment.size())
                        {
                            BoundaryPixel boundaryPixel = neighbourBorderSegment.get(index++);
                            map[boundaryPixel.x][boundaryPixel.y] = region.id;
                            region.size++;
                            regions.regionMap.get(boundaryPixel.otherRegionId).size--;
                            // until we reach the desired size...
                            if (region.size == region.desiredSize)
                                break out;
                        }
                    }
                }
            }

            // if region contains more pixels than desired...
            else if (region.size > region.desiredSize)
            {
                // and the region has neighbours
                if (region.boundary.size() > 0)
                {
                    // choose a neighbour to off load extra pixels to
                    Region neighbour = regions.regionMap.get(region.boundary.remove(rand.nextInt(region.boundary.size())).otherRegionId);

                    ArrayList<BoundaryPixel> adjustedBoundary = new ArrayList<>();
                    // iterate over the boundary neighbour's boundary pixels...
                    for (BoundaryPixel boundaryPixel : neighbour.boundary)
                    {
                        // and then for those pixels which are of the current region, convert to the neighbour region
                        if (boundaryPixel.otherRegionId == region.id)
                        {
                            map[boundaryPixel.x][boundaryPixel.y] = neighbour.id;
                            neighbour.size++;
                            region.size--;
                            // stop when we reach the region's desired size.
                            if (region.size == region.desiredSize)
                                break;
                        }
                        else
                        {
                            adjustedBoundary.add(boundaryPixel);
                        }
                    }
                    neighbour.boundary = adjustedBoundary;
                }
            }
        }

    }

    /**
     * identifies the area, starting at the given point, in which adjacent pixels are of the same region id.
     * 
     * @param map
     * @param isolatedRegionMap
     *            cells identifying which area that the corresponding map cell belongs
     * @param width
     * @param height
     * @param point
     *            the starting point of the area to be identified
     * @param isolatedRegionId
     *            the id of the region to assign cells with
     * @return the size of the identified area
     */
    private static int identifyEnclosedArea(int[][] map, int[][] isolatedRegionMap, int width, int height, Point point, final int isolatedRegionId)
    {
        ArrayList<Point> stack = new ArrayList<Point>();
        final int EXPECTED_REGION_ID = map[point.x][point.y];
        stack.add(point);
        int size = 0;

        while (stack.size() > 0)
        {
            Point p = stack.remove(stack.size() - 1);
            int x = p.x;
            int y = p.y;
            if (y < 0 || y > height - 1 || x < 0 || x > width - 1 || isolatedRegionMap[x][y] > 0)
                continue;
            int val = map[x][y];
            if (val == EXPECTED_REGION_ID)
            {
                isolatedRegionMap[x][y] = isolatedRegionId;
                size++;
                stack.add(new Point(x + 1, y));
                stack.add(new Point(x - 1, y));
                stack.add(new Point(x, y + 1));
                stack.add(new Point(x, y - 1));
            }
        }

        return size;
    }

}

คำอธิบาย (จากความคิดเห็น)

อัลกอริธึมนั้นค่อนข้างง่าย: เริ่มแรกแผนที่ด้วยน้ำหนักแบบสุ่มเลือกพิกเซลเมล็ดแบบสุ่มสำหรับแต่ละภูมิภาคของประเทศ ประการที่สอง "เติบโต" ในแต่ละภูมิภาคโดยพยายามอ้างสิทธิ์พิกเซลที่อยู่ติดกัน สิ่งนี้เกิดขึ้นเมื่อน้ำหนักของพิกเซลปัจจุบันเกินน้ำหนักที่ไม่มีการอ้างสิทธิ์

แต่ละพิกเซลในภูมิภาคจะเพิ่มน้ำหนักของแต่ละรอบการเติบโต นอกจากนี้หากพื้นที่มีเพื่อนบ้านแล้วหากพื้นที่ปัจจุบันที่พิจารณามีพิกเซลน้อยกว่าที่ต้องการก็จะขโมยพิกเซลจากเพื่อนบ้านหากเพื่อนบ้านมีพิกเซลมากกว่าที่ต้องการ หากภูมิภาคปัจจุบันมีพิกเซลมากกว่าเพื่อนบ้านแล้วสุ่มเลือกเพื่อนบ้านแล้วให้พิกเซลส่วนเกินทั้งหมดกับเพื่อนบ้านนั้น เมื่อทุกภูมิภาคมีขนาดที่ถูกต้องดังนั้นระยะที่สามจะเกิดขึ้นเพื่อระบุและแปลงพื้นที่ใด ๆ ที่ถูกแบ่งและไม่ต่อเนื่องอีกต่อไป

มีการแยกส่วนที่ใหญ่ที่สุดของภูมิภาคไว้เท่านั้นและส่วนอื่น ๆ จะถูกแปลงเป็นพิกเซลที่ไม่มีการอ้างสิทธิ์และเฟสที่สองจะเริ่มขึ้นอีกครั้ง ซึ่งจะทำซ้ำจนกว่าพิกเซลทั้งหมดในพื้นที่จะอยู่ติดกันและภูมิภาคทั้งหมดจะมีขนาดที่ถูกต้อง


เยี่ยมมาก! คุณช่วยอธิบายเล็กน้อยว่าอัลกอริทึมของคุณทำงานอย่างไร
Arnaud

1
ที่ดี! ฉันคิดว่ามีเพียงสีเท่านั้นที่อาจเป็น "Earthy" มากกว่า (สีที่สามนั้นคล้ายกับ Dark Purple Age of Camelot: P) ฉันคิดว่าคุณลืมภาพสำหรับตัวอย่างสุดท้ายของคุณ
งานอดิเรกของ Calvin

@ งานอดิเรกของ Calvin ต้องชอบการเลือกสีแบบสุ่ม ... ดูเหมือนว่าคอมพิวเตอร์ของฉันชอบสีม่วง: P โอ๊ะฉันลืมตัวอย่างที่สาม ... จะสร้างและอัปเดต
Moogie

12

ความท้าทายนี้ยากอย่างน่าประหลาดใจ ฉันเขียนตัวสร้างแผนที่ใน Python โดยใช้ Pygame โปรแกรมขยายพื้นที่สีให้เป็นพื้นที่ว่างและส่งผลให้ภาพที่ดูเหมือนแผนที่ (ถ้าคุณเหล่)

อัลกอริทึมของฉันไม่ได้ทำให้ประเทศเสร็จสมบูรณ์เสมอไปเนื่องจากพื้นที่ที่เหลืออาจมีพื้นที่ไม่เพียงพอ แต่ฉันคิดว่ามันทำให้เกิดผลที่น่าสนใจและฉันจะไม่ใช้เวลาอีกต่อไป แพทช์สีน้ำเงินแปลก ๆ ที่เหลืออาจถือได้ว่าเป็นทะเลสาบขนาดใหญ่และคุณสมบัติสีน้ำเงินที่เป็นจุดด่างดำระหว่างประเทศคือแม่น้ำที่ทำเครื่องหมายชายแดน (เป็นคุณลักษณะไม่ใช่ข้อผิดพลาด!)

เพื่อเปรียบเทียบกับ Super Chafouin ฉันใช้ตัวอย่างพารามิเตอร์ของพวกเขา

พารามิเตอร์: 380 260 233 420 1300 3511 4772 5089 9507 22107 25117 26744

ทดสอบมาตรฐาน

พารามิเตอร์: 380 260 8 5 6 7 8 4 5 6 7 9 4 6 9 5 8 7 5

ตัวอย่างที่ 2

Dark Age of Camelot (213 307 1 1 1)

ตัวอย่างที่ 3

ตัวอย่างที่ใหญ่กว่าของฉัน: (640 480 6 1 7 2 9 3 4 5 6 1 9 8 7 44 3 1 9 4 5 6 7 2 3 4 9 3 4 5 9 8 7 5 6 1 2 1 2 1 2 6 7 8 9 9 63 3)

ตัวอย่างใหญ่ของฉันเกี่ยวกับยุโรปตะวันออก?

ตัวอย่างนี้ดูคล้ายกับยุโรปตะวันออกใช่ไหม

ตัวอย่างกับประเทศอื่น ๆ : 640 480 6 1 7 2 9 3 4 5 6 1 9 8 7 44 3 1 9 4 5 6 7 2 3 4 9 3 4 5 9 8 7 5 6 1 2 1 2 1 2 6 7 8 8 9 63 5 33 11 88 2 7 9 5 6 2 5 7

ประเทศอื่น ๆ ที่มีสีกลมกล่อม

ผมเปลี่ยนเครื่องกำเนิดไฟฟ้าสีด้วยตัวอย่างนี้colors = [(80+ri(100), 80+ri(100), 80+ri(100)) for c in counts]เพื่อให้ได้รับกลมกล่อมมากขึ้น (และแผนที่เหมือน) ช่วง

รหัสหลาม:

from pygame.locals import *
import pygame, sys, random

BACK = (0,0,200)
ORTH = [(-1,0), (1,0), (0,-1), (0,1)]
PI = 3.141592

random.seed(9999)
def ri(n):
    return int(random.random() * n)

args = [int(v) for v in sys.argv[1:]]
W, H = args[:2]
shares = sorted(args[2:])
ratio = float(W*H) / sum(shares)
counts = [int(s*ratio) for s in shares]
for i in range(W*H - sum(counts)):
    counts[i] += 1

colors = [(2+ri(250), 2+ri(250), 2+ri(250)) for c in counts]
countries = range(len(counts))
random.shuffle(countries)

border = ( set((x,y) for x in (0,W-1) for y in range(H)) |
            set((x,y) for x in range(W) for y in (0,H-1)) )

screen = pygame.display.set_mode((W,H))
screen.fill(BACK)
pix = screen.set_at
def look(p):
    if 0 <= p[0] < W and 0 <= p[1] < H:
        return screen.get_at(p)
    else:
        return None

clock = pygame.time.Clock()

while True:
    dt = clock.tick(300)
    pygame.display.flip()

    if countries:
        country = countries.pop()
        color = colors[country]
        if not countries:
            color = (20,20,200)  # last fill color to be water
        count = counts[country]
        frontier = set()
        plotted = 0
        loc = border.pop()
        while plotted < count:
            pix(loc, color)
            if plotted % 50 == 0:
                pygame.display.flip()
            plotted += 1
            direc = [(loc[0]+dx, loc[1]+dy) for dx,dy in ORTH]
            for dloc in direc:
                if look(dloc) == BACK:
                    frontier.add(dloc)
            border |= frontier
            if frontier:
                loc = frontier.pop()
                border.discard(loc)
            else:
                print 'Country %s cover %u of %u' % (
                    shares[country], plotted, count)
                break
        if not countries:
            fn = 'mapper%u.png' % ri(1000)
            pygame.image.save(screen, fn)

    for event in pygame.event.get():
        if event.type == QUIT: sys.exit(0)
        if not hasattr(event, 'key'): continue
        if event.key == K_ESCAPE: sys.exit(0)

"any pixel in the region can be reached from any other by staying within the region and only moving orthogonally"ไม่แน่ใจว่ามันเคารพกฎ ฉันเห็นพิกเซลที่แยกได้หรือไม่
Arnaud

อัลกอริทึมไม่เป็นไปตามกฎความต่อเนื่องที่คุณอ้างถึง แต่ล้มเหลวในด้านอื่น ๆ พิกเซลที่แยกได้เหล่านั้นคือ "หลุม" ในประเทศที่พื้นหลังแสดงผ่าน เนื่องจากเอฟเฟกต์นี้และอื่น ๆ หลายประเทศในการวิ่งแต่ละครั้งจะไม่ได้สร้างพิกเซลทั้งหมด บางประเทศพลาดในที่สุดพิกเซลของพวกเขา ไม่เป็นไปตามกฎทั้งหมดที่ระบุ แต่ฉันคิดว่ามันเป็นผลลัพธ์ที่น่าสนใจ อัลกอริทึมจะต้องมีงานที่สำคัญในการสร้างแผนที่ที่สมบูรณ์แบบ
Logic Knight อัศวิน

เป็นเทคนิคที่ขัดกับกฎ แต่ก็ยังค่อนข้างเท่ห์ ฉันลองทำสิ่งนี้หลังจากทำคำถามและมีปัญหาคล้ายกัน มันยากกว่าที่ฉันคิด!
งานอดิเรกของ Calvin

8

เป็นคนขี้เกียจและปรับคำตอบของฉันจากคำถามนี้ !

  1. อัลกอริทึมคำนวณ "เส้นทางงู" เริ่มต้นจากมุมซ้ายบนที่เติมสี่เหลี่ยมทั้งหมด งูสามารถขึ้น, ลง, ซ้าย, ขวาได้

  2. เส้นทางงูจะถูกติดตามและเต็มไปด้วยสีแรกจากนั้นสีที่สอง ฯลฯ โดยคำนึงถึงเปอร์เซ็นต์สี

  3. อัลกอริทึมนี้สร้างเส้นตรงจำนวนมาก เพื่อปรับปรุงฉันจะตรวจจับและแทนที่ด้วย "คลื่น" ที่มีจำนวนพิกเซลเท่ากัน

พารามิเตอร์: 380 260 233 420 1300 3511 4772 5089 9507 22107 25117 26744

ป้อนคำอธิบายรูปภาพที่นี่

พารามิเตอร์: 380 260 8 5 6 7 8 4 5 6 7 9 4 6 9 5 8 7 5

ป้อนคำอธิบายรูปภาพที่นี่

Dark Age of Camelot (213 307 1 1 1)

ป้อนคำอธิบายรูปภาพที่นี่

รหัส:

package map;

import java.awt.Color;
import java.awt.image.BufferedImage;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Random;

import javax.imageio.ImageIO;


public class GenMap2 {

    private enum State { NO, YES, SHIFT };
    public final static int TOP = 1, BOTTOM = 2, LEFT = 4, RIGHT = 8;
    enum Action { ADD_LINE_TOP, ADD_LINE_LEFT, DOUBLE_SIZE, CREATE};

    public static void main(String[] args) throws IOException {

        int w = Integer.parseInt(args[0]), h = Integer.parseInt(args[1]);
        List<Integer> areas = new ArrayList<Integer>();
        int total = 0;
        for (int i = 2; i < args.length; i++) {
            int area = Integer.parseInt(args[i]);
            areas.add(area);
            total += area;
        }
        Collections.sort(areas);
        Collections.reverse(areas);
        int [][] tab = build(w, h);

        BufferedImage dest = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
        int [] black = {0, 0, 0};
        for (int j = 0; j < dest.getHeight(); j++) {
            for (int i = 0; i < dest.getWidth(); i++) {
                dest.getRaster().setPixel(i, j, black);
            }
        }

        int x = 0, y = -1;
        int go = BOTTOM, previous = BOTTOM;

        List<Color> colors = new ArrayList<Color>();
        Random rand = new Random(0); // prog must be deterministic
        while (colors.size() < areas.size()) {
            Color c = new Color(rand.nextInt(256), rand.nextInt(256), rand.nextInt(256));
            boolean ok = true;
            for (Color existing : colors) {
                if (existing.equals(c)) {
                    ok = false;
                    break;
                }
            }
            if (ok) {
                colors.add(c);
            }
        }

        int [][] map = new int[w][h];
        int cpt = 0;
        while (true) {
            if (go == BOTTOM) y++;
            if (go == TOP) y--;
            if (go == LEFT) x--;
            if (go == RIGHT) x++;

            int tmp = (int)(((long)cpt) * total / (w * h));
            int i = 0;
            for (i = 0; i < areas.size(); i++) {
                int area = areas.get(i);
                if (tmp < area) {
                    break;
                }
                tmp -= area;
            }

            map[x][y] = i;

            previous = go;

            go = -1;
            if ((tab[x][y] & TOP) != 0 && previous != BOTTOM) go = TOP;
            if ((tab[x][y] & BOTTOM) != 0 && previous != TOP) go = BOTTOM;
            if ((tab[x][y] & LEFT) != 0 && previous != RIGHT) go = LEFT;
            if ((tab[x][y] & RIGHT) != 0 && previous != LEFT) go = RIGHT;
            if (go == -1) break;
            cpt++;
        }

        String [] src0 = srcPattern(16);
        String [] repl0 = destPattern(16);
        while (findPattern(map, src0, Arrays.asList(repl0, flip(repl0)))){}
        while (findPattern(map, rotate(src0), Arrays.asList(rotate(repl0), rotate(flip(repl0))))){}
        String [] src1 = srcPattern(8);
        String [] repl1 = destPattern(8);
        while (findPattern(map, src1, Arrays.asList(repl1, flip(repl1)))){}
        while (findPattern(map, rotate(src1), Arrays.asList(rotate(repl1), rotate(flip(repl1))))){}
        String [] src2 = srcPattern(4);
        String [] repl2 = destPattern(4);
        while (findPattern(map, src2, Arrays.asList(repl2, flip(repl2)))){}
        while (findPattern(map, rotate(src2), Arrays.asList(rotate(repl2), rotate(flip(repl2))))){}


        for (y = 0; y < h; y++) {
            for (x = 0; x < w; x++) {
                Color c = colors.get(map[x][y]);
                dest.getRaster().setPixel(x, y, new int[] {c.getRed(), c.getGreen(), c.getBlue()});
            }
        }

        ImageIO.write(dest, "png", new FileOutputStream("map.png"));
    }

    private static Random randPat = new Random(0);


    private static String [] srcPattern(int size) {
        String [] ret = new String[size*2];
        for (int i = 0; i < size*2; i++) {
            ret[i] = "";
            for (int j = 0; j < size*4; j++) {
                ret[i] += i < size ? "1" : "2";
            }
        }
        return ret;
    }

    private static String [] destPattern(int size) {
        String [] ret = new String[size*2];
        for (int i = 0; i < size*2; i++) {
            ret[i] = "";
            for (int j = 0; j < size*2; j++) {
                //int target = (int)((1 + Math.sin(j * Math.PI * .5/ size) * .4) * size);
                int target = (int)((1 + (Math.cos(j * Math.PI/ size) - 1) * .2) * size);
                ret[i] += (i < target)  ? '1' : '2';
            }
        }

        for (int i = 0; i < size*2; i++) {
            for (int j = 0; j < size*2; j++) {
                ret[i] += ret[size*2 - 1 - i].charAt(size*2 - 1 - j) == '1' ? '2' : '1';
            }
        }
        return ret;
    }
    private static String [] flip(String [] pat) {
        String [] ret = new String[pat.length];
        for (int i = 0; i < ret.length; i++) {
            ret[i] = new StringBuilder(pat[i]).reverse().toString();

        }
        return ret;
    }
    private static String [] rotate(String [] pat) {
        String [] ret = new String[pat[0].length()];
        for (int i = 0; i < ret.length; i++) {
            ret[i] = "";
            for (int j = 0; j < pat.length; j++) {
                ret[i] += pat[j].charAt(i);
            }
        }
        return ret;
    }

    private static boolean findPattern(int [][] map, String [] src, List<String []> dest) {
        for (int y = 0; y < map[0].length - src.length; y++) {
            for (int x = 0; x < map.length - src[0].length(); x++) {
                int c1 = -1, c2 = -1;
                boolean wrong = false;
                for (int y1 = 0; y1 < src.length; y1++) {
                    for (int x1 = 0; x1 < src[0].length(); x1++) {
                        if (src[y1].charAt(x1) == '1') {
                            if (c1 == -1) {
                                c1 = map[x+x1][y+y1];
                            } else {
                                if (c1 != map[x+x1][y+y1]) {
                                    wrong = true;
                                }
                            }
                        }
                        if (src[y1].charAt(x1) == '2') {
                            if (c2 == -1) {
                                c2 = map[x+x1][y+y1];
                            } else {
                                if (c2 != map[x+x1][y+y1]) {
                                    wrong = true;
                                }
                            }
                        }
                        if (c1 != -1 && c1 == c2) wrong = true;
                        if (wrong) break;
                    }
                    if (wrong) break;
                }
                if (!wrong) {
                    System.out.println("Found match at " + x + " " + y);
                    String [] repl = dest.get(randPat.nextInt(dest.size()));
                    for (int y1 = 0; y1 < src.length; y1++) {
                        for (int x1 = 0; x1 < src[0].length(); x1++) {
                            map[x+x1][y+y1] = repl[y1].charAt(x1) == '1' ? c1 : c2;

                        }
                    }
                    return true;
                }
            }
        }           
        return false;
    }

    public static int [][] build(int width, int height) {
        List<Action> actions = new ArrayList<Action>();
        while (height>1 && width>1) {
            if (height % 2 == 1) {
                height--;
                actions.add(Action.ADD_LINE_TOP);
            }
            if (width % 2 == 1) {
                width--;                
                actions.add(Action.ADD_LINE_LEFT);
            }
            if (height%2 == 0 && width%2 == 0) {
                actions.add(Action.DOUBLE_SIZE);
                height /= 2;
                width /= 2;
            }
        }
        actions.add(Action.CREATE);
        Collections.reverse(actions);
        int [][] tab = null;
        for (Action action : actions) {
            if (action == Action.CREATE) {
                tab = new int[width][height];
                if (height >= width) {
                    for (int i = 0; i < height-1; i++) {
                        tab[0][i] = TOP|BOTTOM;
                    }
                    tab[0][height-1] = TOP;
                } else {
                    tab[0][0] = TOP|RIGHT;
                    for (int i = 1; i < width-1; i++) {
                        tab[i][0] = RIGHT|LEFT;
                    }
                    tab[width-1][0] = LEFT;

                }
            }
            if (action == Action.DOUBLE_SIZE) {
                tab = doubleTab(tab);
            }
            if (action == Action.ADD_LINE_TOP) {
                int [][] tab2 = new int[tab.length][tab[0].length+1];
                for (int i = 0; i < tab.length; i++) {
                    for (int j = 0; j < tab[0].length; j++) {
                        tab2[i][j+1] = tab[i][j];
                    }
                }
                tab2[0][0] = BOTTOM|RIGHT;
                for (int i = 1; i < tab.length-1; i++) {
                    tab2[i][0] = RIGHT|LEFT;
                }
                tab2[tab.length-1][0] = TOP|LEFT;
                mirror(tab2);
                tab = tab2;
            }
            if (action == Action.ADD_LINE_LEFT) {
                int [][] tab2 = new int[tab.length+1][tab[0].length];
                for (int i = 0; i < tab.length; i++) {
                    for (int j = 0; j < tab[0].length; j++) {
                        tab2[i+1][j] = tab[i][j];
                    }
                }
                tab2[0][0] = BOTTOM|RIGHT;
                tab2[1][0] |= LEFT;
                tab2[1][0] -= TOP;
                for (int i = 1; i < tab[0].length-1; i++) {
                    tab2[0][i] = TOP|BOTTOM;
                }
                tab2[0][tab[0].length-1] = TOP|BOTTOM;
                flip(tab2);
                tab = tab2;
            }

        }

        return tab;
    }

    private static void mirror(int [][] tab) {
        for (int i = 0; i < tab.length/2; i++) {
            for (int j = 0; j < tab[0].length; j++) {
                int tmp = tab[tab.length - 1 - i][j];
                tab[tab.length - 1 - i][j] = tab[i][j];
                tab[i][j] = tmp;
            }
        }
        for (int i = 0; i < tab.length; i++) {
            for (int j = 0; j < tab[0].length; j++) {
                if ((tab[i][j] & LEFT)!=0 && (tab[i][j] & RIGHT)==0) {
                    tab[i][j] -= LEFT; tab[i][j] |= RIGHT;
                } else if ((tab[i][j] & RIGHT)!=0 && (tab[i][j] & LEFT)==0) {
                    tab[i][j] -= RIGHT; tab[i][j] |= LEFT;
                }
            }
        }
    }

    private static void flip(int [][] tab) {
        for (int i = 0; i < tab.length; i++) {
            for (int j = 0; j < tab[0].length/2; j++) {
                int tmp = tab[i][tab[0].length - 1 - j];
                tab[i][tab[0].length - 1 - j] = tab[i][j];
                tab[i][j] = tmp;
            }
        }
        for (int i = 0; i < tab.length; i++) {
            for (int j = 0; j < tab[0].length; j++) {
                if ((tab[i][j] & TOP)!=0 && (tab[i][j] & BOTTOM)==0) {
                    tab[i][j] -= TOP; tab[i][j] |= BOTTOM;
                } else if ((tab[i][j] & BOTTOM)!=0 && (tab[i][j] & TOP)==0) {
                    tab[i][j] -= BOTTOM; tab[i][j] |= TOP;
                }
            }
        }
    }


    public static int [][] doubleTab(int [][] tab) {
        boolean [][] shiftTop = new boolean[tab.length][], 
                shiftLeft = new boolean[tab.length][],
                shiftBottom = new boolean[tab.length][],
                shiftRight = new boolean[tab.length][];
        for (int i = 0; i < tab.length; i++) {
            shiftTop[i] = new boolean[tab[i].length];
            shiftLeft[i] = new boolean[tab[i].length];
            shiftBottom[i] = new boolean[tab[i].length];
            shiftRight[i] = new boolean[tab[i].length];
        }

        int x = 0, y = -1;
        for (int i = 0; i < tab.length; i++) {
            if ((tab[i][0] & TOP) != 0) {
                x = i;
            }
        }
        int go = BOTTOM, previous = BOTTOM;
        boolean init = false;
        while (true) {
            if (go == BOTTOM) y++;
            if (go == TOP) y--;
            if (go == LEFT) x--;
            if (go == RIGHT) x++;

            previous = go;

            go = -1;
            if ((tab[x][y] & TOP) != 0 && previous != BOTTOM) go = TOP;
            if ((tab[x][y] & BOTTOM) != 0 && previous != TOP) go = BOTTOM;
            if ((tab[x][y] & LEFT) != 0 && previous != RIGHT) go = LEFT;
            if ((tab[x][y] & RIGHT) != 0 && previous != LEFT) go = RIGHT;
            if (previous == BOTTOM) {
                shiftTop[x][y] = y==0 ? init : shiftBottom[x][y-1];
            }
            if (previous == TOP) {
                shiftBottom[x][y] = shiftTop[x][y+1];
            }
            if (previous == RIGHT) {
                shiftLeft[x][y] = shiftRight[x-1][y];
            }
            if (previous == LEFT) {
                shiftRight[x][y] = shiftLeft[x+1][y];       
            }
            if (go == -1) break;

            if (previous == BOTTOM && go == LEFT) {
                shiftLeft[x][y] = !shiftTop[x][y];
            }
            if (previous == BOTTOM && go == RIGHT) {
                shiftRight[x][y] = shiftTop[x][y];
            }
            if (previous == BOTTOM && go == BOTTOM) {
                shiftBottom[x][y] = shiftTop[x][y];
            }


            if (previous == TOP && go == LEFT) {
                shiftLeft[x][y] = shiftBottom[x][y];
            }
            if (previous == TOP && go == RIGHT) {
                shiftRight[x][y] = !shiftBottom[x][y];
            }
            if (previous == TOP && go == TOP) {
                shiftTop[x][y] = shiftBottom[x][y];
            }

            if (previous == RIGHT && go == TOP) {
                shiftTop[x][y] = !shiftLeft[x][y];
            }
            if (previous == RIGHT && go == BOTTOM) {
                shiftBottom[x][y] = shiftLeft[x][y];
            }
            if (previous == RIGHT && go == RIGHT) {
                shiftRight[x][y] = shiftLeft[x][y];
            }

            if (previous == LEFT && go == TOP) {
                shiftTop[x][y] = shiftRight[x][y];
            }
            if (previous == LEFT && go == BOTTOM) {
                shiftBottom[x][y] = !shiftRight[x][y];
            }
            if (previous == LEFT && go == LEFT) {
                shiftLeft[x][y] = shiftRight[x][y];
            }
        }
        int [][] tab2 = new int[tab.length * 2][];
        for (int i = 0; i < tab2.length; i++) {
            tab2[i] = new int[tab[0].length * 2];
        }

        for (int i = 0; i < tab.length; i++) {
            for (int j = 0; j < tab[0].length; j++) {
                State left = State.NO, right = State.NO, top = State.NO, bottom = State.NO; 
                if ((tab[i][j] & LEFT) != 0) {
                    left = shiftLeft[i][j] ? State.SHIFT : State.YES;
                }
                if ((tab[i][j] & TOP) != 0) {
                    top = shiftTop[i][j] ? State.SHIFT : State.YES;
                }
                if ((tab[i][j] & RIGHT) != 0) {
                    right = shiftRight[i][j] ? State.SHIFT : State.YES;
                }
                if ((tab[i][j] & BOTTOM) != 0) {
                    bottom = shiftBottom[i][j] ? State.SHIFT : State.YES;
                }

                int [] comp = compute(left, top, right, bottom);
                tab2[i*2][j*2] = comp[0];
                tab2[i*2+1][j*2] = comp[1];
                tab2[i*2][j*2+1] = comp[2];
                tab2[i*2+1][j*2+1] = comp[3];
            }
        }
        return tab2;
    }

    private static int [] compute(State left, State top, State right, State bottom) {
        //   |
        // --+
        //
        if (left == State.YES && top == State.SHIFT) {
            return new int[] {LEFT|BOTTOM, TOP|BOTTOM, TOP|RIGHT, TOP|LEFT};// "v^>^";
        }
        if (left == State.SHIFT && top == State.YES) {
            return new int[] {TOP|RIGHT, LEFT|BOTTOM, LEFT|RIGHT, LEFT|TOP}; //"^<>^";
        }
        //   
        // --+
        //   |
        if (left == State.YES && bottom == State.YES) {
            return new int[] {LEFT|RIGHT, LEFT|BOTTOM, RIGHT|BOTTOM, LEFT|TOP}; //">vv<";
        }
        if (left == State.SHIFT && bottom == State.SHIFT) {
            return new int[] {RIGHT|BOTTOM, LEFT|BOTTOM, LEFT|TOP, TOP|BOTTOM}; //">v^v";
        }
        //   |
        //   +--
        //
        if (right == State.SHIFT && top == State.SHIFT) {
            return new int [] {RIGHT|BOTTOM,LEFT|TOP,TOP|RIGHT, LEFT|RIGHT}; //" v<>>";
        }
        if (right == State.YES && top == State.YES) {
            return new int [] {TOP|BOTTOM,RIGHT|BOTTOM,TOP|RIGHT,TOP|LEFT}; //"v>>^";
        }
        //   
        //   +--
        //   |
        if (right == State.YES && bottom == State.SHIFT) {
            return new int [] {RIGHT|BOTTOM, LEFT|RIGHT, TOP|RIGHT, LEFT|BOTTOM}; //"v<>v";
        }
        if (right == State.SHIFT && bottom == State.YES) {
            return new int [] {RIGHT|BOTTOM, LEFT|BOTTOM, TOP|BOTTOM, RIGHT|TOP}; //"v<v^";
        }
        //   
        // --+--
        //   
        if (right == State.YES && left == State.YES) {
            return new int [] {LEFT|BOTTOM, RIGHT|BOTTOM, TOP|RIGHT, LEFT|TOP}; 
        }
        if (right == State.SHIFT && left == State.SHIFT) {
            return new int [] {RIGHT|BOTTOM, LEFT|BOTTOM, LEFT|TOP, RIGHT|TOP}; 
        }
        //   |
        //   +
        //   |
        if (top == State.YES && bottom == State.YES) {
            return new int [] {TOP|RIGHT, LEFT|BOTTOM, BOTTOM|RIGHT, LEFT|TOP}; 
        }
        if (top == State.SHIFT && bottom == State.SHIFT) {
            return new int [] {RIGHT|BOTTOM, LEFT|TOP, RIGHT|TOP, LEFT|BOTTOM}; 
        }
        //
        //   +--
        //
        if (right == State.YES && bottom == State.NO && left == State.NO && top == State.NO) {
            return new int [] {BOTTOM, RIGHT|BOTTOM, TOP|RIGHT, LEFT|TOP}; 
        }
        if (right == State.SHIFT && bottom == State.NO && left == State.NO && top == State.NO) {
            return new int [] {RIGHT|BOTTOM, LEFT|BOTTOM, TOP, RIGHT|TOP}; 
        }

        //   |
        //   +
        //
        if (top == State.YES && bottom == State.NO && left == State.NO && right == State.NO) {
            return new int [] {TOP|RIGHT, LEFT|BOTTOM, RIGHT, LEFT|TOP}; 
        }
        if (top == State.SHIFT && bottom == State.NO && left == State.NO && right == State.NO) {
            return new int [] {BOTTOM|RIGHT, LEFT|TOP, TOP|RIGHT, LEFT}; 
        }
        //   
        //   +
        //   |
        if (bottom == State.YES && top == State.NO && left == State.NO && right == State.NO) {
            return new int [] {RIGHT, LEFT|BOTTOM, BOTTOM|RIGHT, LEFT|TOP}; 
        }
        if (bottom == State.SHIFT && top == State.NO && left == State.NO && right == State.NO) {
            return new int [] {BOTTOM|RIGHT, LEFT, TOP|RIGHT, LEFT|BOTTOM}; 
        }
        //
        // --+
        //
        if (left == State.YES && bottom == State.NO && right == State.NO && top == State.NO) {
            return new int [] {LEFT|BOTTOM, BOTTOM, TOP|RIGHT, LEFT|TOP}; 
        }
        if (left == State.SHIFT && bottom == State.NO && right == State.NO && top == State.NO) {
            return new int [] {BOTTOM|RIGHT, LEFT|BOTTOM, LEFT|TOP, TOP}; 
        }
        return null;
    }
}

1
ในสายตาของฉันสิ่งเหล่านี้ดูไม่เหมือนจริงมาก ส่วนใหญ่เป็นเพราะเส้นตรงจำนวนมาก ...
สลายตัวของเบต้า

2
@BetaDecay เนื่องจาก OP ระบุว่า "ไม่ว่าในระดับใด" ให้จินตนาการว่าเป็นภูมิภาคย่อยของรัฐหรือประเทศ จากนั้นคุณสามารถมีมันยืดออกมากยังมีเหตุผลเหมือนแผนที่เขตเนบราสก้า
Geobits

1
@ ทั้งสองฉันได้เพิ่ม "คลื่น" บางอย่างเพื่อแก้ไขเส้นตรง
Arnaud

@ βετѧΛєҫαγมันดูไม่สมจริง แต่ดูที่พรมแดนระหว่างสหรัฐอเมริกาและแคนาดาส่วนใหญ่ทำจากเส้นตรงไม่กี่เส้นเหมือนกันกับบางพรมแดนระหว่างบางประเทศในแอฟริกา
user902383
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.