Advertisement
Guest User

ProvinceRationalizer7.pde

a guest
Nov 12th, 2016
91
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Java 12.01 KB | None | 0 0
  1. //Run this program in Processing (http://processing.org).
  2.  
  3. //This program has three objectives:
  4. //1. Make provinces round and compact rather than skinny and snake-like;
  5. //2. Don't make any province more fragmented than it already is; and
  6. //3. Preserve all existing adjacencies between provinces.
  7. //When you feed it a map (data/input.png), it spits out a progressively-better version
  8. //of that map (output/*.png) every thirty seconds until you tell it to stop.
  9.  
  10. boolean mapIsCylinder=false;//Make this "true" if the map is a cylinder (wraps around at the east and west edges).
  11. //color colorWater=color(68,107,163);//EU4
  12. //color colorWasteland=color(94,94,94);//EU4
  13.  
  14. PImage image;//Input and output
  15. Map map;
  16.  
  17. int timeMark;
  18. boolean aMatchWasFound;
  19. int successfulFlips=0;
  20.  
  21. void setup(){
  22.   frameRate(999999);
  23.   timeMark=millis();
  24.   print("Loading image...");
  25.   colorMode(RGB,255);//Default
  26.   image=loadImage("input.png");//Actually "data/input.png"
  27.   image.loadPixels();
  28.   print(" Done in "+(millis()-timeMark)/1000+" seconds.\nDoing preliminary stuff...");
  29.   map=new Map();
  30.   map.analyze();
  31.   print(" Done in "+(millis()-timeMark)/1000+" seconds.\nDoing flips...");
  32.   timeMark=millis();
  33. }
  34. void draw(){
  35.   map.attemptFlip();
  36.   if(millis()-timeMark>30000){
  37.     map.export();
  38.     timeMark=millis();
  39.   }
  40.   //exit();
  41. }
  42.  
  43. class Map{
  44.   Pxl[] pxls;
  45.   Province[] provinces;
  46.   float[] xOriginal;
  47.   float[] yOriginal;
  48.   Map(){
  49.     //Pxls
  50.     pxls=new Pxl[image.pixels.length];
  51.     for(int pxl=0;pxl<pxls.length;pxl++){
  52.       pxls[pxl]=new Pxl(pxl);
  53.     }
  54.     println("Count of pixels: "+pxls.length);
  55.   }
  56.   void analyze(){
  57.     for(Pxl pxl:pxls){
  58.       pxl.province=-1;
  59.     }
  60.     //Provinces
  61.     provinces=new Province[0];
  62.     int provinceCount=0;
  63.     for(Pxl pxl:pxls){
  64.       if(pxl.province==-1){
  65.         if(provinceCount==provinces.length){
  66.           provinces=(Province[])expand(provinces);
  67.         }
  68.         provinces[provinceCount]=new Province(provinceCount,pxl);
  69.         provinceCount++;
  70.       }
  71.     }
  72.     provinces=(Province[])subset(provinces,0,provinceCount);
  73.     //Section count, neighbors, pxl radii
  74.     xOriginal=new float[provinces.length];
  75.     yOriginal=new float[provinces.length];
  76.     for(Province province:provinces){
  77.       province.analyze();
  78.       xOriginal[province.num]=province.x;
  79.       yOriginal[province.num]=province.y;
  80.     }
  81.     println("Count of provinces: "+provinces.length);
  82.    
  83.   }
  84.   void attemptFlip(){
  85.     boolean thisAttemptHasFailed=false;
  86.     //Choose two random pxls in different provinces
  87.     int pxl0,pxl1,province0,province1;
  88.     /*do{
  89.       pxl0=int(random(pxls.length));
  90.       pxl1=int(random(pxls[pxl0].neighbors.length));
  91.       pxl1=pxls[pxl0].neighbors[pxl1];
  92.       province0=pxls[pxl0].province;
  93.       province1=pxls[pxl1].province;
  94.     }while(province0==province1);*/
  95.     do{
  96.       province0=int(random(provinces.length));
  97.       province1=int(random(provinces[province0].neighbors.length));
  98.       province1=provinces[province0].neighbors[province1];
  99.     }while(1==0/*provinces[province0].clr==colorWater||provinces[province0].clr==colorWasteland*/);
  100.     do{
  101.       pxl0=int(random(provinces[province0].pxls.length));
  102.       pxl0=provinces[province0].pxls[pxl0];
  103.       pxl1=int(random(provinces[province1].pxls.length));
  104.       pxl1=provinces[province1].pxls[pxl1];
  105.       aMatchWasFound=false;
  106.       for(int neighbor:pxls[pxl0].neighbors){
  107.         if(pxls[neighbor].province==province1){
  108.           aMatchWasFound=true;
  109.           break;
  110.         }
  111.       }
  112.       if(aMatchWasFound){
  113.         aMatchWasFound=false;
  114.         for(int neighbor:pxls[pxl1].neighbors){
  115.           if(pxls[neighbor].province==province0){
  116.             aMatchWasFound=true;
  117.             break;
  118.           }
  119.         }
  120.       }
  121.     }while(!aMatchWasFound);//Both pixels must be on the border between the chosen provinces
  122.     //Would executing this flip increase the sum of radii?
  123.     //if(pxls[pxl0].r<dist(pxls[pxl0].x,pxls[pxl0].y,provinces[province1].x,provinces[province1].y)||pxls[pxl1].r<dist(pxls[pxl1].x,pxls[pxl1].y,provinces[province0].x,provinces[province0].y)){
  124.     if(pxls[pxl0].r+pxls[pxl1].r<dist(pxls[pxl0].x,pxls[pxl0].y,provinces[province1].x,provinces[province1].y)+dist(pxls[pxl1].x,pxls[pxl1].y,provinces[province0].x,provinces[province0].y)){
  125.       thisAttemptHasFailed=true;
  126.     }
  127.     //Would executing this flip increase the number of sections in either province, or create a new adjacency?
  128.     /*if(!thisAttemptHasFailed){
  129.       int neighborProvince;
  130.       boolean flipWillMakeNewSection=true;
  131.       boolean flipWillMakeNewAdjacency=false;
  132.       //Flipping pxl0 to pxl1's position
  133.       for(int neighborPxl:pxls[pxl1].neighbors){
  134.         neighborProvince=pxls[neighborPxl].province;
  135.         if(neighborProvince==province0){
  136.           flipWillMakeNewSection=false;
  137.         }else{
  138.           aMatchWasFound=false;
  139.           for(int neighbor:provinces[province0].neighbors){
  140.             if(neighborProvince==neighbor){
  141.               aMatchWasFound=true;
  142.               break;
  143.             }
  144.           }
  145.           if(!aMatchWasFound){
  146.             flipWillMakeNewAdjacency=true;
  147.             break;
  148.           }
  149.         }
  150.       }
  151.       if(flipWillMakeNewSection||flipWillMakeNewAdjacency){
  152.         thisAttemptHasFailed=true;
  153.       }else{
  154.         flipWillMakeNewSection=true;flipWillMakeNewAdjacency=false;
  155.         //Flipping pxl1 to pxl0's position
  156.         for(int neighborPxl:pxls[pxl0].neighbors){
  157.           neighborProvince=pxls[neighborPxl].province;
  158.           if(neighborProvince==province1){
  159.             flipWillMakeNewSection=false;
  160.           }else{
  161.             aMatchWasFound=false;
  162.             for(int neighbor:provinces[province1].neighbors){
  163.               if(neighborProvince==neighbor){
  164.                 aMatchWasFound=true;
  165.                 break;
  166.               }
  167.             }
  168.             if(!aMatchWasFound){
  169.               flipWillMakeNewAdjacency=true;
  170.               break;
  171.             }
  172.           }
  173.         }
  174.         if(flipWillMakeNewSection||flipWillMakeNewAdjacency){
  175.           thisAttemptHasFailed=true;
  176.         }
  177.       }
  178.     }*/
  179.     //Conclusion
  180.     if(!thisAttemptHasFailed){
  181.       color tempColor=pxls[pxl0].clr;
  182.       pxls[pxl0].clr=pxls[pxl1].clr;
  183.       pxls[pxl1].clr=tempColor;
  184.       //analyze();
  185.       int sectionCount0Old=provinces[province0].sectionCount;
  186.       int sectionCount1Old=provinces[province1].sectionCount;
  187.       int[] neighbors0Old=provinces[province0].neighbors;
  188.       int[] neighbors1Old=provinces[province1].neighbors;
  189.       provinces[province0]=new Province(province0,pxls[pxl1]);
  190.       provinces[province1]=new Province(province1,pxls[pxl0]);
  191.       provinces[province0].analyze();
  192.       provinces[province1].analyze();
  193.       //Ensure that adjacencies haven't changed
  194.       //Ensure that section count has remained stable or has fallen
  195.       if(!thisAttemptHasFailed&&(provinces[province0].sectionCount>sectionCount0Old||provinces[province1].sectionCount>sectionCount1Old)){
  196.         thisAttemptHasFailed=true;
  197.       }
  198.       if(!thisAttemptHasFailed){
  199.         if(neighbors0Old.length!=provinces[province0].neighbors.length||neighbors1Old.length!=provinces[province1].neighbors.length){
  200.           thisAttemptHasFailed=true;
  201.         }else{
  202.           for(int neighbor=0;neighbor<neighbors0Old.length;neighbor++){
  203.             if(neighbors0Old[neighbor]!=provinces[province0].neighbors[neighbor]){
  204.               thisAttemptHasFailed=true;
  205.               break;
  206.             }
  207.           }
  208.           if(!thisAttemptHasFailed){
  209.             for(int neighbor=0;neighbor<neighbors1Old.length;neighbor++){
  210.               if(neighbors1Old[neighbor]!=provinces[province1].neighbors[neighbor]){
  211.                 thisAttemptHasFailed=true;
  212.                 break;
  213.               }
  214.             }
  215.           }
  216.         }
  217.       }
  218.       if(!thisAttemptHasFailed){
  219.         successfulFlips++;
  220.       }else{
  221.         tempColor=pxls[pxl0].clr;
  222.         pxls[pxl0].clr=pxls[pxl1].clr;
  223.         pxls[pxl1].clr=tempColor;
  224.         provinces[province0]=new Province(province0,pxls[pxl0]);
  225.         provinces[province1]=new Province(province1,pxls[pxl1]);
  226.         provinces[province0].analyze();
  227.         provinces[province1].analyze();
  228.       }
  229.     }
  230.   }
  231.   void export(){
  232.     image.loadPixels();
  233.     for(Pxl pxl:pxls){
  234.       image.pixels[pxl.num]=pxl.clr;
  235.     }
  236.     image.updatePixels();
  237.     image.save("output/"+millis()/1000+" seconds, "+frameCount+" attempts, "+successfulFlips+" successes.png");
  238.   }
  239. }
  240. class Pxl{
  241.   int num;//Unique
  242.   color clr;
  243.   int x,y;//Location (from NW toward SE)
  244.   int[] neighbors;
  245.   int province;
  246.   float r;
  247.   boolean hasBeenSectioned;
  248.   Pxl(int input){
  249.     num=input;
  250.     clr=image.pixels[num];
  251.     x=num%image.width;
  252.     y=num/image.width;
  253.     neighbors=new int[4];
  254.     int neighborCount=0;
  255.     if(x<image.width-1){
  256.       neighbors[neighborCount]=num+1;
  257.       neighborCount++;
  258.     }else if(mapIsCylinder){
  259.       neighbors[neighborCount]=num+1-image.width;
  260.       neighborCount++;
  261.     }
  262.     if(y>0){
  263.       neighbors[neighborCount]=num-image.width;
  264.       neighborCount++;
  265.     }
  266.     if(x>0){
  267.       neighbors[neighborCount]=num-1;
  268.       neighborCount++;
  269.     }else if(mapIsCylinder){
  270.       neighbors[neighborCount]=num-1+image.width;
  271.       neighborCount++;
  272.     }
  273.     if(y<image.height-1){
  274.       neighbors[neighborCount]=num+image.width;
  275.       neighborCount++;
  276.     }
  277.     neighbors=subset(neighbors,0,neighborCount);
  278.     province=-1;
  279.   }
  280. }
  281. class Province{
  282.   int num;
  283.   color clr;
  284.   int[] pxls;
  285.   float x,y;
  286.   int[] neighbors;
  287.   int sectionCount;
  288.   Province(int input0,Pxl input1){
  289.     num=input0;
  290.     clr=input1.clr;
  291.     pxls=new int[0];
  292.     int pxlCount=0;
  293.     if(frameCount==0){
  294.       x=0;
  295.       y=0;
  296.     }else{
  297.       x=map.xOriginal[num];
  298.       y=map.yOriginal[num];
  299.     }
  300.     for(Pxl pxl:map.pxls){
  301.       if(pxl.clr==clr){
  302.         if(pxlCount==pxls.length){
  303.           pxls=expand(pxls);
  304.         }
  305.         pxls[pxlCount]=pxl.num;
  306.         if(frameCount==0){
  307.           x+=float(pxl.x);
  308.           y+=float(pxl.y);
  309.         }
  310.         pxlCount++;
  311.         pxl.province=num;
  312.       }
  313.     }
  314.     pxls=subset(pxls,0,pxlCount);
  315.     if(frameCount==0){
  316.       x/=float(pxls.length);
  317.       y/=float(pxls.length);
  318.     }
  319.     //println("Province "+num+" has "+pxls.length+" pxls.");
  320.   }
  321.   void analyze(){
  322.     //Section count, neighbors, pxl radii
  323.     neighbors=new int[0];
  324.     int neighborCount=0;
  325.     for(int pxl:pxls){
  326.       map.pxls[pxl].r=dist(x,y,float(map.pxls[pxl].x),float(map.pxls[pxl].y));
  327.       map.pxls[pxl].hasBeenSectioned=false;
  328.       for(int neighborPxl:map.pxls[pxl].neighbors){
  329.         if(map.pxls[neighborPxl].province!=num){
  330.           aMatchWasFound=false;
  331.           for(int neighborProvince:neighbors){
  332.             if(map.pxls[neighborPxl].province==neighborProvince){
  333.               aMatchWasFound=true;
  334.               break;
  335.             }
  336.           }
  337.           if(!aMatchWasFound){
  338.             if(neighborCount==neighbors.length){
  339.               neighbors=expand(neighbors);
  340.             }
  341.             neighbors[neighborCount]=map.pxls[neighborPxl].province;
  342.             neighborCount++;
  343.           }
  344.         }
  345.       }
  346.     }
  347.     neighbors=sort(subset(neighbors,0,neighborCount));
  348.     //println("Count of provinces neighboring province "+num+": "+neighbors.length);
  349.     sectionCount=0;
  350.     for(int pxl:pxls){
  351.       if(!map.pxls[pxl].hasBeenSectioned){
  352.         map.pxls[pxl].hasBeenSectioned=true;
  353.         sectionCount++;
  354.         do{
  355.           aMatchWasFound=false;
  356.           for(int pxl2:pxls){
  357.             if(!map.pxls[pxl2].hasBeenSectioned){
  358.               for(int neighbor:map.pxls[pxl2].neighbors){
  359.                 if(map.pxls[neighbor].province==num&&map.pxls[neighbor].hasBeenSectioned){
  360.                   aMatchWasFound=true;
  361.                   map.pxls[pxl2].hasBeenSectioned=true;
  362.                   break;
  363.                 }
  364.               }
  365.             }
  366.           }
  367.         }while(aMatchWasFound);
  368.       }
  369.     }
  370.     //println("Count of sections in province "+num+": "+sectionCount);
  371.   }
  372. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement