思路:一开始计划手工划分,后来实在受不了了,就用程序写了一个 ,剩下的再慢慢完善,大致思路为:

1.首先地图存储关键城市,港口,建筑信息,设定这些为核心,以他们扩展,并在扩展时给予一定约束

2.对未扩展的区块进行分割,计算面积,随机出来新的核心,然后再以这些核心扩展

3.对生成的地图进行检验,合并过小的区块,检查生成是否正确等

代码如下

package com.zhfy.game.model.content;

import java.io.BufferedInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.lang.reflect.Field;
import java.lang.reflect.Type;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.Pixmap;
import com.zhfy.game.framework.ComUtil;
import com.zhfy.game.framework.GameMap;
import com.zhfy.game.framework.GameUtil;
import com.zhfy.game.model.content.btl.BtlModule1;
import com.zhfy.game.model.content.def.DefMap;
import com.zhfy.game.model.content.def.DefTerrainimg;
import com.zhfy.game.model.framework.Coord;

public class MapBinDAO {
    
    public int mapVersion;// 2-地图版本
    public int mapWidth;// 4-长
    public int mapHeight;// 4-宽
    public List<MapBin> MapBin;// 
    
    //写死了
    public MapBinDAO(BTLDAO btlDao){
        if(btlDao!=null) {
            mapVersion=1;
            mapWidth=Integer.parseInt(btlDao.getBm0().getBm0_13());
            mapHeight=Integer.parseInt(btlDao.getBm0().getBm0_14());
            MapBin=new ArrayList<MapBin>();
            MapBin mapBin;
            for(BtlModule1 bm1:btlDao.getBm1()) {
                mapBin=new MapBin();
                mapBin.setBlockType(Integer.parseInt(bm1.getBm1_1()));
                mapBin.setBackTile(Integer.parseInt(bm1.getBm1_2()));
                mapBin.setBackIdx(Integer.parseInt(bm1.getBm1_3()));
                mapBin.setBackRefX(Integer.parseInt(bm1.getBm1_4()));
                mapBin.setBackRefY(Integer.parseInt(bm1.getBm1_5()));
                mapBin.setWaterPass(Integer.parseInt(bm1.getBm1_6()));
                mapBin.setLandPass(Integer.parseInt(bm1.getBm1_7()));
                mapBin.setRegionId(Integer.parseInt(bm1.getBm1_8()));
                mapBin.setClimateId(Integer.parseInt(bm1.getBm1_9()));
                mapBin.setBuildId(Integer.parseInt(bm1.getBm1_10()));
                mapBin.setBuildLv(Integer.parseInt(bm1.getBm1_11()));
                mapBin.setFacility(Integer.parseInt(bm1.getBm1_12()));
                mapBin.setAreaId(Integer.parseInt(bm1.getBm1_13()));
                MapBin.add(mapBin);
            }
        }
    }
    
    public int getMapVersion() {
        return mapVersion;
    }
    
    public void setMapVersion(int mapVersion) {
        this.mapVersion = mapVersion;
    }
    
    public int getMapWidth() {
        return mapWidth;
    }
    
    public void setMapWidth(int mapWidth) {
        this.mapWidth = mapWidth;
    }
    
    public int getMapHeight() {
        return mapHeight;
    }
    
    public void setMapHeight(int mapHeight) {
        this.mapHeight = mapHeight;
    }
    
    public List<MapBin> getMapbin() {
        return MapBin;
    }
    
    public void setMapbin(List<MapBin> MapBin) {
        this.MapBin = MapBin;
    }
    
    public void initRegionId() {
        int i, iMax;
        iMax = MapBin.size();
        for (i = 0; i < iMax; i++) {
            MapBin.get(i).setRegionId(i);
        }
    }
    
    //随机装饰(除特殊装饰,以及ref有值的外)  
    public void randomAllDecoration() {
        Random rand = new Random();
        //储存地块最高范围
        Map map = GameMap.getDecorateRandMaxMap(); //Map(id_type+"_min",idx_min) Map(id_type+"_max",idx_max)
        //循环遍历所有地块
        int i;
        int iLength = MapBin.size();
        int vMin, vMax;
        for (i = 0; i < iLength; i++) {
            /*
             * if(MapBin.get(i).getBackTile()==5) { Gdx.app.log("MapBin.i:",
             * "imin:"+(MapBin.get(i).getBackTile()+"_"+MapBin.get(i).
             * getBlockType()+"_min")+" imax:"+(MapBin.get(i).getBackTile()+"_"+
             * MapBin.get(i).getBlockType()+"_max")); }
             */
            if (map.containsKey(MapBin.get(i).getBackTile() + "_" + MapBin.get(i).getBlockType() + "_min") && map.containsKey(MapBin.get(i).getBackTile() + "_" + MapBin.get(i).getBlockType() + "_max") && MapBin.get(i).getBackRefX() == 0 && MapBin.get(i).getBackRefY() == 0) {
                
                vMin = (Integer) map.get(MapBin.get(i).getBackTile() + "_" + MapBin.get(i).getBlockType() + "_min");
                vMax = (Integer) map.get(MapBin.get(i).getBackTile() + "_" + MapBin.get(i).getBlockType() + "_max");
                //Gdx.app.log("", " backTile:"+MapBin.get(i).getBackTile()+" type:"+MapBin.get(i).getBackTile()+" max:"+map.get(MapBin.get(i).getBackTile()+"_"+MapBin.get(i).getBlockType()+"_max")+" min:"+map.get(MapBin.get(i).getBackTile()+"_"+MapBin.get(i).getBlockType()+"_min")+" backIdx:"+backIdx);
                MapBin.get(i).setBackIdx(rand.nextInt(vMax - vMin + 1) + vMin);
            }
            if (map.containsKey(MapBin.get(i).getForeTile() + "_" + MapBin.get(i).getBlockType() + "_min") && map.containsKey(MapBin.get(i).getForeTile() + "_" + MapBin.get(i).getBlockType() + "_max") && MapBin.get(i).getForeRefX() == 0 && MapBin.get(i).getForeRefY() == 0) {
                vMin = (Integer) map.get(MapBin.get(i).getForeTile() + "_" + MapBin.get(i).getBlockType() + "_min");
                vMax = (Integer) map.get(MapBin.get(i).getForeTile() + "_" + MapBin.get(i).getBlockType() + "_max");
                //Gdx.app.log("", " backTile:"+MapBin.get(i).getBackTile()+" type:"+MapBin.get(i).getBackTile()+" max:"+map.get(MapBin.get(i).getBackTile()+"_"+MapBin.get(i).getBlockType()+"_max")+" min:"+map.get(MapBin.get(i).getBackTile()+"_"+MapBin.get(i).getBlockType()+"_min")+" backIdx:"+backIdx);
                MapBin.get(i).setForeIdx(rand.nextInt(vMax - vMin + 1) + vMin);
            }
        }
    }
    
    //随机增加2层装饰
    public void randomForeDecoration() {
        int foreId, vMin, vMax;
        Random rand = new Random();
        //储存地块最高范围
        Map map = GameMap.getDecorateRandMaxMap();
        //循环遍历所有地块
        int i;
        int iLength = MapBin.size();
        Object o1;
        
        for (i = 0; i < iLength; i++) {
            //配对规则
            //4丘陵 4 5 6
            //5山地 4 5 6
            //6森林 4 5 6
            if (rand.nextInt(100) < 31 && map.containsKey(MapBin.get(i).getBackTile() + "_" + MapBin.get(i).getBlockType() + "_min") && map.containsKey(MapBin.get(i).getBackTile() + "_" + MapBin.get(i).getBlockType() + "_max") && MapBin.get(i).getBackTile() > 3 && MapBin.get(i).getBackTile() < 7) {
                foreId = 4 + rand.nextInt(3);
                MapBin.get(i).setForeTile(foreId);
                o1 = map.get(foreId + "_" + MapBin.get(i).getBlockType() + "_min");
                if (o1 != null && MapBin.get(i).getForeRefX() == 0 && MapBin.get(i).getForeRefY() == 0) {
                    vMin = (Integer) map.get(foreId + "_" + MapBin.get(i).getBlockType() + "_min");
                    vMax = (Integer) map.get(foreId + "_" + MapBin.get(i).getBlockType() + "_max");
                    //Gdx.app.log("", " backTile:"+MapBin.get(i).getBackTile()+" type:"+MapBin.get(i).getBackTile()+" max:"+map.get(MapBin.get(i).getBackTile()+"_"+MapBin.get(i).getBlockType()+"_max")+" min:"+map.get(MapBin.get(i).getBackTile()+"_"+MapBin.get(i).getBlockType()+"_min")+" backIdx:"+backIdx);
                    MapBin.get(i).setForeIdx(rand.nextInt(vMax - vMin + 1) + vMin);
                }
            } else {
                MapBin.get(i).setForeTile(0);
                MapBin.get(i).setForeIdx(0);
            }
        }
    }
    
    //规则 有建筑或有地名的区块=id 否则为0
    public void resetRegionId() {
        int i;
        int iMax = MapBin.size();
        for (i = 0; i < iMax; i++) {
            if (MapBin.get(i).getAreaId() == 0 && MapBin.get(i).getBuildId() == 0) {
                MapBin.get(i).setRegionId(0);
            } else {
                MapBin.get(i).setRegionId(i);
            }
        }
    }
    
    //根据纬度生成随机气候 TODO
    public void randomClimate() {
        
    }
    
    //随机海岸河流 TODO
    public void randomCoastRever() {
        
    }
    
    //完全随机地图 TODO
    public void randomAll(int i) {
        
    }
    
    //重新切割省区 TODO
    public void cutRegion() {
        Random rand = new Random();
        int tempId, exct = 0, i = 0, iMax = 0, j, jMax, rsct, riSize;
        List<Integer> regions = null;
        List<Integer> temps = null;
        Map regionCountMap = new HashMap();
        Boolean ifSea =false;
        
        for (j = 0; j < 5; j++) {
            exct=0;
            regions = getRegions(j);
            Gdx.app.log("阶段1", "核心地块数" + regions.size()+"获得地块类:"+j); //循环 挨个对核心地块进行循环 
            while (exct < 20-j && regions.size() != 0) {
                for (i = regions.size() - 1; i >= 0; i--) {
                    tempId = getRegionId(regions.get(i));
                    if(!ifSea){//判断海洋,移除
                        if(tempId>=0&&MapBin.get(tempId).getBlockType()==1){
                            tempId=-1;
                        }
                    }
                    if (tempId >= 0) {
                        riSize = getIdByRegion(tempId).size();
                        if (riSize > (13 + Math.random() * 5)) {
                            regions.remove(i);
                        } else {
                            MapBin.get(tempId).setRegionId(regions.get(i));
                        }
                    } else {
                        regions.remove(i);
                    }
                }
                Gdx.app.log("阶段2", "核心地块数" + regions.size() + " 循环次数:" + exct);
                exct++;
            }
        }
        //循环2 自定义随机地块 // 随机一定条件取核心值
        //循环挨个核心地块循环 //如果核心地块周围有非核心地块的空地且面积不超过一定值,则染色(条件可放宽),否则移除,直到移除全部地块
        {
            regions = getRegionIdsByChance((int) 5,ifSea);
            rsct = getRegionForIdIs0();
            Gdx.app.log("阶段3", "剩余绘制数" + rsct);
            for (Integer rg : regions) {
                if(!ifSea&&MapBin.get(rg).getBlockType()==1){

                }else{
                    MapBin.get(rg).setRegionId(rg);
                }

            }
        }



        int rgc = 0;//可用地块
        while (rsct > 0) {//空白地块不能等于0
            jMax = regions.size();
            if(jMax==0) {
                break;
            }
            for (j = jMax - 1; j >= 0; j--) {//regions.get(j)为当前地块值
                //定义当前地块为特定地块 //循环填充周围地块
                iMax=(int)(10 + Math.random() * 10);
                for (i = 0; i < iMax; i++) {
                    rgc = getRegionId(regions.get(j));
                    if (rgc == -1) {
                        regions.remove(regions.get(j));
                        break;
                    } else {
                        MapBin.get(rgc).setRegionId(regions.get(j));
                    }
                }
            }
            rsct = getRegionForIdIs0();
            Gdx.app.log("阶段3", "剩余绘制数" + rsct + " 核心地块数:" + regions.size());
        }

        /* 自检,合并不规范地块 */
        {
            //0查看所有region为0的地块并合并到周围地块
            {
                regions = getIdsForBlankRegion();
                for (Integer region : regions) {//rsCoords.size()  rand.nextInt(
                    temps = getAroundIdById(region, 9);
                    if (temps.size() != 0) {
                        MapBin.get(region).setRegionId(temps.get(rand.nextInt(temps.size())));
                    } else {
                        //此时剩下的应该是碎小的岛屿或水洞
                        temps = getAroundIdById(region, 0);
                        if (temps.size() != 0) {
                            MapBin.get(region).setRegionId(temps.get(rand.nextInt(temps.size())));
                        } else {
                            Gdx.app.log("警告:有空白地块无法合并到周围地块:", region + "");
                        }

                    }
                }
            }
            //对所有region数量进行检查
            //Map.Entry entry;
            int rgct, argId;
            List<Integer> argIds, regionCounts;
            {
                checkRegion();

                regionCountMap = getRegionCountMap();
                regionCounts = ComUtil.getKeyByMap(regionCountMap);
                for (Integer rgId : regionCounts) {
                    if (regionCountMap.containsKey(rgId) && regionCountMap.get(rgId) != null) {
                        rgct = Integer.parseInt(regionCountMap.get(rgId).toString());
                        if (rgct < 7) {
                            if (MapBin.get(rgId).getBuildId() == 1) {
                                //0:低于5的城市合并周围的最低地块普通或建筑地块(小于5)
                                argIds = getAroundRegionId(rgId);//获取周围地块
                                for (Integer tarId : argIds) {
                                    if (Integer.parseInt(regionCountMap.get(tarId).toString()) < 6 && MapBin.get(tarId).getBuildId() != 1 && MapBin.get(tarId).getBlockType() != 1) {
                                        updateRegionIds(rgId, tarId);
                                        regionCountMap.put(rgId, (Integer.parseInt(regionCountMap.get(tarId).toString()) + Integer.parseInt(regionCountMap.get(rgId).toString())));
                                        regionCountMap.remove(tarId);
                                        break;
                                    }
                                }
                            } else if (MapBin.get(rgId).getBuildId() == 4) {
                                if(ifSea) {//如果容许海洋,则合并
                                    //1:低于5的海港合并周围的最低海洋地块(小于5)
                                    argIds = getAroundRegionId(rgId);//获取周围地块
                                    for (Integer tarId : argIds) {
                                        if (Integer.parseInt(regionCountMap.get(tarId).toString()) < 6 && MapBin.get(tarId).getBuildId() != 4 && MapBin.get(tarId).getBlockType() == 1) {
                                            updateRegionIds(rgId, tarId);
                                            regionCountMap.put(rgId, (Integer.parseInt(regionCountMap.get(tarId).toString()) + Integer.parseInt(regionCountMap.get(rgId).toString())));
                                            regionCountMap.remove(tarId);
                                            break;
                                        }
                                    }
                                }else{
                                    //否则把海港归到最近的地块
                                    updHabourForE();
                                }
                            } else if (MapBin.get(rgId).getBlockType() != 1 && MapBin.get(rgId).getBuildId() == 0) {
                                //2:低于5的陆地地块合并到周围地块数量最低的陆地地块
                                argIds = getAroundRegionId(rgId);//获取周围地块
                                for (Integer tarId : argIds) {
                                    if (Integer.parseInt(regionCountMap.get(tarId).toString()) < 6 && MapBin.get(tarId).getBuildId() != 4 && MapBin.get(tarId).getBlockType() != 1) {
                                        updateRegionIds(rgId, tarId);
                                        regionCountMap.put(rgId, (Integer.parseInt(regionCountMap.get(tarId).toString()) + Integer.parseInt(regionCountMap.get(rgId).toString())));
                                        regionCountMap.remove(tarId);
                                        break;
                                    }
                                }

                            } else if (MapBin.get(rgId).getBlockType() == 1&&ifSea) {
                                //3:低于5的海洋地块合并到周围地块数量最低的海洋地块

                                argIds = getAroundRegionId(rgId);//获取周围地块
                                for (Integer tarId : argIds) {
                                    if (Integer.parseInt(regionCountMap.get(tarId).toString()) < 6 && MapBin.get(tarId).getBuildId() != 4 && MapBin.get(tarId).getBlockType() == 1) {
                                        updateRegionIds(rgId, tarId);
                                        regionCountMap.put(rgId, (Integer.parseInt(regionCountMap.get(tarId).toString()) + Integer.parseInt(regionCountMap.get(rgId).toString())));
                                        regionCountMap.remove(tarId);
                                        break;
                                    }
                                }
                            } else if (MapBin.get(rgId).getBlockType() != 1 && MapBin.get(rgId).getBuildId() != 1) {
                                //4:低于5的非城市建筑陆地地块合并到最近的城市地块

                                argIds = getAroundRegionId(rgId);//获取周围地块
                                for (Integer tarId : argIds) {
                                    if (Integer.parseInt(regionCountMap.get(tarId).toString()) < 6 && MapBin.get(tarId).getBuildId() != 4 && MapBin.get(tarId).getBlockType() != 1) {
                                        updateRegionIds(rgId, tarId);
                                        regionCountMap.put(rgId, (Integer.parseInt(regionCountMap.get(tarId).toString()) + Integer.parseInt(regionCountMap.get(rgId).toString())));
                                        regionCountMap.remove(tarId);
                                        break;
                                    }
                                }

                            } else {
                                Gdx.app.log("警告:未检测到的地块:", rgId + "");
                            }
                        }
                    }
                }
            }



            //0查看所有孤岛类地块并合并到周围地块
            {
                //自动合并孤岛类地块
                mergeIslandGridByRegion();
                regions = getIdsForBlankRegion();
                for (Integer region : regions) {//rsCoords.size()  rand.nextInt(
                    if (MapBin.get(region).getBlockType() == 1) {
                        temps = getAroundIdById(region, 3);
                    } else {
                        temps = getAroundIdById(region, 4);
                    }
                    if (temps.size() != 0) {
                        MapBin.get(region).setRegionId(temps.get(rand.nextInt(temps.size())));
                    } else {
                        Gdx.app.log("警告:有空白地块无法合并到周围地块:", region + "");
                    }
                }
            }
            {//如果不需要海则清除
                if(!ifSea){
                    for(MapBin mapbin:MapBin){
                        if(mapbin.getBlockType()==1&&mapbin.getBuildId()!=4){
                            mapbin.setRegionId(0);
                        }
                    }
                }
            }
            Gdx.app.log("执行完成", "");
        }
    }
    

    //重新切割省区 
      public void cutRegionForE(int maxC) {
          Random rand = new Random();
          int tempId, exct = 0, i = 0, iMax = 0, j, jMax, rsct, riSize;
          List<Integer> regions = null;
          List<Integer> temps = null;
          Map regionCountMap = new HashMap();
          
         {
              exct=0;
              regions = getRegions(1);
              Gdx.app.log("阶段1", "核心地块数" + regions.size()+"获得地块类:"+1); //循环 挨个对核心地块进行循环 
              while (exct < maxC && regions.size() != 0) {
                  for (i = regions.size() - 1; i >= 0; i--) {
                      tempId = getRegionIdForE(regions.get(i));
                      if (tempId >= 0) {
                          MapBin.get(tempId).setRegionId(regions.get(i));
                      } else {
                          regions.remove(i);
                      }
                  }
                  Gdx.app.log("阶段2", "核心地块数" + regions.size() + " 循环次数:" + exct);
                  exct++;
              }
          }


         
         
         
         //打印空白陆地地块和海洋有港口的地块
            // logBlankGrid();
      }
    
    //把region是target的修改为 rgId
    private void updateRegionIds(Integer rgId, Integer targetId) {
        //交换前检查合不合法
        if(MapBin.get(MapBin.get(rgId).getRegionId()).getRegionId()!=MapBin.get(rgId).getRegionId()) {
            Gdx.app.log("警告:不合法,修正前", "rgId:"+rgId+" targetId:"+targetId);
            rgId=MapBin.get(MapBin.get(rgId).getRegionId()).getRegionId();
            Gdx.app.log("警告:不合法,修正后", "rgId:"+rgId+" targetId:"+targetId);
        }
        for (MapBin mapBin : MapBin) {
            if (mapBin.getRegionId() == targetId) {
                mapBin.setRegionId(rgId);
            }
        }
        
    }
    
    public List<Integer> getAroundRegionId(int rgId) {
        List<Integer> regions = new ArrayList<Integer>();
        List<Integer> tempId;
        int i, iMax = MapBin.size();
        int blockType = MapBin.get(rgId).getBlockType();
        for (i = 0; i < iMax; i++) {
            if (MapBin.get(i).getRegionId() == rgId) {
                if (blockType != 1) {
                    //陆地
                    tempId = getAroundIdById(i, 4);
                } else {
                    //海洋
                    tempId = getAroundIdById(i, 3);
                }
                for (Integer id : tempId) {
                    if (MapBin.get(id).getRegionId() != rgId) {
                        regions.add(MapBin.get(id).getRegionId());
                    }
                }
            }
        }
        tempId = new ArrayList<Integer>();//去重
        for (Integer in : regions) {
            if (!tempId.contains(in)) {
                tempId.add(in);
            }
        }
        return tempId;
    }
    
    //根据条件获得核心地块
    private List<Integer> getRegions(int i) {
        
        //0 全部核心地块 只限城市和海港
        //1 只限于陆地的核心地块 只限城市
        //2 只限于陆地的核心地块 只限工厂且未被覆盖
        //3 只限于陆地的核心地块 只限机场且未被覆盖
        //4 只限于陆地的核心地块 只限油库且未被覆盖
        //5 只限于海洋的核心地块 只限海港
        //6 全部核心地块,不限类型
        int m;
        int mMax = MapBin.size();
        List<Integer> regions = new ArrayList<Integer>();
        if (i == 0) {
            for (m = 0; m < mMax; m++) {
                if (MapBin.get(m).getAreaId() != 0 || (MapBin.get(m).getBuildId() == 1 || MapBin.get(m).getBuildId() == 4)) {
                    regions.add(m);
                }
            }
        } else if (i == 1) {
            for (m = 0; m < mMax; m++) {
                if (MapBin.get(m).getBlockType() != 1 && (MapBin.get(m).getAreaId() != 0 || (MapBin.get(m).getBuildId() == 1))) {
                    regions.add(m);
                }
            }
        } else if (i == 2) {
            for (m = 0; m < mMax; m++) {
                if (MapBin.get(m).getBlockType() != 1 && (MapBin.get(m).getRegionId() == m || MapBin.get(m).getRegionId() == 0) && (MapBin.get(m).getAreaId() != 0 || (MapBin.get(m).getBuildId() == 2))) {
                    regions.add(m);
                }
            }
        } else if (i == 3) {
            for (m = 0; m < mMax; m++) {
                if (MapBin.get(m).getBlockType() != 1 && (MapBin.get(m).getRegionId() == m || MapBin.get(m).getRegionId() == 0) && (MapBin.get(m).getAreaId() != 0 || (MapBin.get(m).getBuildId() == 3))) {
                    regions.add(m);
                }
            }
        } else if (i == 4) {
            for (m = 0; m < mMax; m++) {
                if (MapBin.get(m).getBlockType() != 1 && (MapBin.get(m).getRegionId() == m || MapBin.get(m).getRegionId() == 0) && (MapBin.get(m).getAreaId() != 0 || (MapBin.get(m).getBuildId() == 5))) {
                    regions.add(m);
                }
            }
        } else if (i == 5) {
            for (m = 0; m < mMax; m++) {
                if (MapBin.get(m).getBlockType() == 1 && (MapBin.get(m).getAreaId() != 0 || (MapBin.get(m).getBuildId() == 4))) {
                    regions.add(m);
                }
            }
        } else if (i == 6) {
            for (m = 0; m < mMax; m++) {
                if(!regions.contains(MapBin.get(m).getRegionId())) {
                    regions.add(m);
                }
            }
        }
        return regions;
    }
    
    //根据id获得周围6边的地块id
    /*
     * type 0全部 1获取region为0的地块 3获取周围的有region的海洋地块 4获取周围的有region的陆地地块
     * 5只获取region为0的海洋地块 6只获取region为0的陆地地块 7只获取region为0的陆地平原地块
     * 8只获取region为0的陆地非平原地块 9根据id区分海洋陆地,获取region为0的地块
     * 10 获取周围是陆地的地块 11获取周围是海洋的地块
     * 12获取沿海陆地地块
     */
    public List<Integer> getAroundIdById(int id, int type) {
        List<Integer> ids = new ArrayList<Integer>();
        List<Integer> rsIds = new ArrayList<Integer>();
        boolean top = false;
        boolean foot = false;
        boolean left = false;
        boolean right = false;
        //判断处于哪个边
        int y = (int) id / mapWidth;
        int x = id - y * mapWidth;
        int t1, t2, t3, t4, t5, t6;
        
        if ((x&1) == 1) {
            t1 = id - 1;
            t2 = id - mapWidth;
            t3 = id + 1;
            t4 = id + mapWidth - 1;
            t5 = id + mapWidth;
            t6 = id + mapWidth + 1;
        } else {
            t1 = id - mapWidth - 1;
            t2 = id - mapWidth;
            t3 = id - mapWidth + 1;
            t4 = id - 1;
            t5 = id + mapWidth;
            t6 = id + 1;
        }
        if (x == 0) {
            left = true;
        }
        if (x == mapWidth - 1) {
            right = true;
        }
        if (y == 0) {
            top = true;
        }
        if (y == mapHeight - 1) {
            foot = true;
        }
        
        if (!top && !left) {
            ids.add(t1);
        }
        if (!top) {
            ids.add(t2);
        }
        if (!top && !right) {
            ids.add(t3);
        }
        if (!foot && !left) {
            ids.add(t4);
        }
        if (!foot) {
            ids.add(t5);
        }
        if (!foot && !right) {
            ids.add(t6);
        }
        
        //type 0全部 1只读取region为0的值  5只获取region为0的海洋地块 6只获取region为0的陆地地块
        //7只获取region为0的陆地平原地块  8只获取region为0的陆地非平原地块  
        //10 获取周围是陆地的地块 11获取周围是海洋的地块
        if (type == 0) {
            return ids;
        } else {
            for (Integer id2 : ids) {
                if (type == 1 && MapBin.get(id2).getRegionId() == 0) {
                    rsIds.add(id2);
                } else if (type == 6 && MapBin.get(id2).getRegionId() == 0 && MapBin.get(id2).getBlockType() != 1) {
                    rsIds.add(id2);
                } else if (type == 5 && MapBin.get(id2).getRegionId() == 0 && (MapBin.get(id2).getBlockType() == 1 || MapBin.get(id2).getBackTile() == 1)) {
                    rsIds.add(id2);
                } else if (type == 7 && MapBin.get(id2).getRegionId() == 0 && MapBin.get(id2).getBlockType() != 1 && MapBin.get(id2).getBackTile() == 0) {
                    rsIds.add(id2);
                } else if (type == 8 && MapBin.get(id2).getRegionId() == 0 && MapBin.get(id2).getBlockType() != 1 && MapBin.get(id2).getBackTile() != 0) {
                    rsIds.add(id2);
                } else if (type == 3 && MapBin.get(id2).getRegionId() != 0 && (MapBin.get(id2).getBlockType() == 1)) {
                    rsIds.add(id2);
                } else if (type == 4 && MapBin.get(id2).getRegionId() != 0 && (MapBin.get(id2).getBlockType() != 1)) {
                    rsIds.add(id2);
                } else if (type == 9 && ((MapBin.get(id).getBlockType()!=1) ==(MapBin.get(id2).getBlockType() != 1))) {
                    rsIds.add(id2);
                }  else if (type == 10 && (MapBin.get(id2).getBlockType() != 1)) {
                    rsIds.add(id2);
                }  else if (type == 11 && (MapBin.get(id2).getBlockType() == 1)) {
                    rsIds.add(id2);
                }else if (type == 12 && (MapBin.get(id2).getBlockType() == 1)&& (MapBin.get(id).getBlockType() != 1)) {
                    rsIds.add(id2);
                }
            }
            return rsIds;
        }
    }
    
    public List<Integer> getAroundIdByIds(List<Integer> ids, int type) {
        List<Integer> rss = new ArrayList<Integer>();
        for (Integer id : ids) {
            List<Integer> rs = getAroundIdById(id, type);
            rss.addAll(rs);
        }
        return rss;
    }
    
    private List<Integer> getIdByRegion(int regionId) {
        int m;
        int mMax = MapBin.size();
        List<Integer> rs = new ArrayList<Integer>();
        
        for (m = 0; m < mMax; m++) {
            if (MapBin.get(m).getRegionId() == regionId) {
                int s=m;
                rs.add(s);
            }
        }
        return rs;
    }
    
    //-1找不到
    //获得要扩展的id
    public int getRegionId(int r) {
        List<Integer> rsIds;
        //1判断自身是海洋还是陆地
        if (MapBin.get(r).getBlockType() == 1) {////获取周边的海洋地块
            rsIds = getAroundIdById(r, 5);
            if (rsIds.size() == 0) {
                rsIds = getAroundIdByIds(getIdByRegion(r), 5);
                if (rsIds == null || rsIds.size() == 0) {
                    //如果周围没有空余地块,则使用相邻的相邻地块判断
                    return -1;
                }
            }
            //根据条件随机获取其中一个地块id
            //return(rsIds.get(rand.nextInt(rsIds.size())));
            return getShortAroundId(rsIds,  MapBin.get(r).getRegionId());
        } else {////获取周边陆地地块
            rsIds = getAroundIdById(r, 7);
            if (rsIds.size() != 0&&ComUtil.ifGet(30)) {
                return getShortAroundId(rsIds,  MapBin.get(r).getRegionId());
            } else {
                rsIds = getAroundIdById(r, 8);
                if (rsIds.size() != 0&&ComUtil.ifGet(30)) {
                    return getShortAroundId(rsIds,  MapBin.get(r).getRegionId());
                } else {
                    rsIds = getAroundIdById(r, 6);
                    if (rsIds.size() != 0&&ComUtil.ifGet(30)) {
                        return getShortAroundId(rsIds,  MapBin.get(r).getRegionId());
                    } else {
                        rsIds = getAroundIdByIds(getIdByRegion(r), 6);
                        if (rsIds != null && rsIds.size() == 0&&ComUtil.ifGet(50)) {
                            //如果周围没有空余地块,则使用相邻的相邻地块判断
                            rsIds = getAroundIdByIds(getIdByRegion(r), 7);
                            if (rsIds != null && rsIds.size() == 0) {
                                //如果周围没有空余地块,则使用相邻的相邻地块判断
                                rsIds = getAroundIdByIds(getIdByRegion(r), 8);
                                if (rsIds != null && rsIds.size() == 0) {
                                            return -1;
                                }
                            }
                        }
                        if (rsIds == null) {
                            return -1;
                        }
                        return getShortAroundId(rsIds,  MapBin.get(r).getRegionId());
                    }
                }
            }
        }
    }
    
    
    
  //-1找不到
    //获得要扩展的id
    public int getRegionIdForE(int r) {
        List<Integer> rsIds;
        List<Integer> tempIds;
        //1判断自身是海洋还是陆地
        if (MapBin.get(r).getBlockType() == 1) {////获取周边的海洋地块
            rsIds = getAroundIdById(r, 5);
            if (rsIds.size() == 0) {
                rsIds = getAroundIdByIds(getIdByRegion(r), 5);
                if (rsIds == null || rsIds.size() == 0) {
                    //如果周围没有空余地块,则使用相邻的相邻地块判断
                    return -1;
                }
            }
            //根据条件随机获取其中一个地块id
            //return(rsIds.get(rand.nextInt(rsIds.size())));
            return getShortAroundId(rsIds,  MapBin.get(r).getRegionId());
        } else {////获取周边陆地地块
            rsIds = getAroundIdById(r, 6);
            if (rsIds.size() == 0) {
                tempIds= getIdByRegion(r);
                rsIds = getAroundIdByIds(tempIds, 6);
                if (rsIds == null || rsIds.size() <3) {
                    //如果周围没有空余地块,则使用相邻的相邻地块判断
                    //Gdx.app.log("清除核心", r+"");
                    return -1;
                }
            }
            int id= getShortAroundId(rsIds, MapBin.get(r).getRegionId());
             return id;
        }
    }



    //chance 最高获取概率,最低默认为10 如果不容许有海洋地块,则多抽0.1
    private List<Integer> getRegionIdsByChance(int chance,boolean ifSea) {
        if(!ifSea){
            chance= (int) (chance*1.2);
        }


        int cutSide = 5;
        Random rand = new Random();
        
        int i, j, m,rsMax,rpMax;
        int mMax = MapBin.size();//chance<(int)(Math.random()*(100)
        List<Integer> rs = new ArrayList<Integer>();
        List<Integer> result = new ArrayList<Integer>();
        //获取全部为空的地块
        for (m = 0; m < mMax; m++) {
            if (MapBin.get(m).getRegionId() == 0) {
                if(ifSea){
                    rs.add(m);
                }else if(!ifSea&&MapBin.get(m).getBlockType()!=1){
                    rs.add(m);
                }
            }
        }
        if (rs.size() == 0) {
            return rs;
        }
        rsMax=rs.size();
        rpMax=rsMax*chance/100;
        /*List<Coord> coords = converCoords(rs);
        List<Coord> rsCoords = new ArrayList<Coord>();
        rs = new ArrayList<Integer>();
        for (i = mapWidth; i >= 0; i = i - cutSide) {
            for (j = mapHeight; j >= 0; j = j - cutSide) {
                for (m = coords.size() - 1; m >= 0; m--) {
                    if (coords.get(m).getX() > i && coords.get(m).getY() > j) {
                        rsCoords.add(coords.get(m));
                        coords.remove(m);
                    }
                    if (rsCoords.size()>0) {
                        rs.add(rsCoords.get(rand.nextInt(rsCoords.size())).getId());
                        rsCoords.clear();
                        rs=ComUtil.getNewList(rs);
                    }
                    if(rs.size()>rsMax*chance/100){
                        break;
                    }
                    if (coords.size() == 0) {
                        break;
                    }
                }
            }
        }*/
        int tempId;
        for(i = 0;i<rpMax;i++){
            //显示数字并将其从列表中删除,从而实现不重复.
            tempId=new Random().nextInt(rs.size());
            rs.remove(tempId);
            result.add(tempId);
            }


        Gdx.app.log("获得随机核心", rsMax+":"+result.size());
        return result;
    }
    
    //获取空白值
    private int getRegionForIdIs0() {
        int ct = 0, m, mMax = MapBin.size();
        for (m = 0; m < mMax; m++) {
            if (MapBin.get(m).getRegionId() == 0) {
                ct++;
            }
        }
        return ct;
    }
    
    //获得空白地块
    private List<Integer> getIdsForBlankRegion() {
        int m;
        int mMax = MapBin.size();
        List<Integer> rs = new ArrayList<Integer>();
        for (m = 0; m < mMax; m++) {
            if (MapBin.get(m).getRegionId() == 0) {
                rs.add(m);
            }
        }
        return rs;
    }
    
    //将id转为coord(x,y,id,regionId) 
    private Coord converCoord(int id) {
        int y = (int) id / mapWidth;
        int x = id - y * mapWidth;
        return new Coord(x, y, id, MapBin.get(id).getRegionId());
    }
    
    //将id转为coord
    private List<Coord> converCoords(List<Integer> ids) {
        int m;
        int mMax = ids.size();
        List<Coord> rsIds = new ArrayList<Coord>();
        for (m = 0; m < mMax; m++) {
            int s=m;
            rsIds.add(converCoord(ids.get(s)));
        }
        return rsIds;
    }
    
    //获得最近的地块
    public int getShortAroundId(List<Integer> ids, int regionId) {
       // Gdx.app.log("求最近的地块,regionId", regionId+"");
        List<Coord> coords = converCoords(ids);
        int i, j, iMax = coords.size(), tempId = -1;double jl,jl2;
        Coord coord = converCoord(regionId);
        for (i = 0; i < iMax; i++) {
            for (j = 0; j < iMax; j++) {
                 jl=Math.pow((coords.get(i).getX() - coord.getX()),2) + Math.pow((coords.get(i).getY() - coord.getY()),2);
                 jl2=(Math.pow((coords.get(j).getX() - coord.getX()),2) + Math.pow((coords.get(j).getY() - coord.getY()),2));
                //Gdx.app.log("求最近的地块,交换前", "i:"+coords.get(i).getId()+" 距离系数:"+jl);
               // Gdx.app.log("求最近的地块,交换前", "j:"+coords.get(i).getId()+" 距离系数:"+jl2);
                
                if (jl<jl2) { // 交换两数的位置   
                    //Gdx.app.log("求最近的地块,交换前", "i:"+coords.get(i).getId()+" j:"+coords.get(j).getId());
                    ComUtil.swap(coords, i, j);
                    //Gdx.app.log("求最近的地块,交换后", "i:"+coords.get(i).getId()+" j:"+coords.get(j).getId());
                }
            }
        }
        //Gdx.app.log("求最近的地块,最前", coords.get(0).getId()+"");
        //Gdx.app.log("求最近的地块,最后", coords.get(coords.size()-1).getId()+"");
        Random rand = new Random();
        {//去除非同一势力 TODO
            for (i = coords.size() - 1; i >= 0; i--) {
                if(!ifComLegion(coords.get(i).getId(),coord.getId())) {
                    coords.remove(i);
                }
            }
        }
        
        
        if (coords.size() > 2) {
            tempId = coords.get(rand.nextInt(2)).getId();
        } else if (coords.size() == 0) {
            return -1;
        } else {
            tempId = coords.get(0).getId();
        }
        // 1.8的写法  取出List中的对象的属性值
        //List<Integer> xs = coords.stream().map(Coord::getX).collect(Collectors.toList());
        //List<Integer> ys = coords.stream().map(Coord::getY).collect(Collectors.toList());

        List<Integer> xs=new ArrayList<Integer>();
        List<Integer> ys=new ArrayList<Integer>();

        for(Coord cd:coords){
            xs.add(cd.getX());
            ys.add(cd.getY());
        }

        int maxX=Collections.max(xs);
        int minX=Collections.min(xs);
        int maxY=Collections.max(ys);
        int minY=Collections.min(ys);
        
        if((maxX-minX)>3||(maxY-minY)>3) {
            if((maxY-minY)!=0&&(maxX-minX)!=0&&((maxX-minX)/(maxY-minY)>2||(maxY-minY)/(maxX-minX)>2)||getRegionCountByRegionId(regionId)<((maxX-minX)*(maxY-minY)/3)) {
                return -1;
            }
        }
        /*if(getRegionCountByRegionId(regionId)>(10 + Math.random() * 5)) {
            return -1;
        }*/
        return tempId;
    }
    
    //获取各region的数量记录为map
    private Map getRegionCountMap() {
        Map rsMap = new HashMap();
        for (MapBin mapBin : MapBin) {
            if (!rsMap.containsKey(mapBin.getRegionId())) {
                rsMap.put(mapBin.getRegionId(), 1);
            } else {
                rsMap.put(mapBin.getRegionId(), Integer.parseInt(rsMap.get(mapBin.getRegionId()).toString()) + 1);
            }
        }
        return rsMap;
    }
    
    //获取通过region获取region的数量
    private int getRegionCountByRegionId(int regionId) {
        int c=0;
        for (MapBin mapBin : MapBin) {
            if (mapBin.getRegionId()==regionId) {
                c++;
            }
        }
        return c;
    }
    
    //通过region获取ids
    public List<Integer> getIdsByRegionId(int regionId){
        List<Integer> rs= new ArrayList<Integer>();
        int c=0;
        for (MapBin mapBin : MapBin) {
            if (mapBin.getRegionId()==regionId) {
                rs.add(c);
            }
            c++;
        }
        return rs;
    }
    //获取所有region
    public List<Integer> getAllRegionIds(){
        List<Integer> rs = new ArrayList<Integer>();
        for (MapBin mapBin : MapBin) {
            if (mapBin.getRegionId()!=0&&!rs.contains(mapBin.getRegionId())) {
                rs.add(mapBin.getRegionId());
            }
        }
        return rs;
    }
    
    //合并孤岛类地块
    private void mergeIslandGridByRegion() {
        int i,iMax=MapBin.size(),rsI=0;
        String rz;
        List<Integer> rs;
        int tempRegionId;
        for (i=0;i<iMax;i++) {
            //获得结果值
            rs= getAroundIdById(i,9);
            Collections.sort(rs);
            rsI=0;
            //判断是否是孤岛
            for(Integer id:rs) {
                if(MapBin.get(id).getRegionId()!=MapBin.get(i).getRegionId()) {
                    rsI++;
                }
            }
            if(rsI>4) {
                rz= ComUtil.getListMostRepeatData(rs);
                //updateRegionIds(MapBin.get(Integer.parseInt(rz)).getRegionId(),i);
                MapBin.get(i).setRegionId(MapBin.get(Integer.parseInt(rz)).getRegionId());
            }
            
        }
    }
    
    
    
    public static void main(String[] args) {
        int i;
        
        for (i = 0; i < 30; i++) {
            System.out.println("sj:" + (int) (10 + Math.random() * 15));
        }
        
    }
    
    //检查所属的区块是不是合法的region,如果不是给周围的地块 TODO测试
    private void checkRegion() {
        int i,iMax=MapBin.size();String rsI;
        List<Integer> rs;
        for (i=0;i<iMax;i++) {
            //获得结果值
            rs= getAroundIdById(i,9);
            Collections.sort(rs);
            if(MapBin.get(MapBin.get(i).getRegionId()).getRegionId()!=MapBin.get(i).getRegionId()) {
                rsI=ComUtil.getListMostRepeatData(rs);
                if(rsI!=null&&rsI!="") {
                    //Gdx.app.log("所属区域region不合法:", "i:"+i);
                    updateRegionIds(MapBin.get(Integer.parseInt(rsI)).getRegionId(),MapBin.get(i).getRegionId());
                }
            }
        }
    }
    
  //打印空白的非海洋地块(包括港口)
    private  void logBlankGrid() {
       int i=0;
        for (MapBin mapBin : MapBin) {
            if (mapBin.getRegionId()==0&&(mapBin.getBackTile()!=1&&mapBin.getBackTile()!=2)) {
                Gdx.app.log("空白地块", i+"");
            }
            i++;
        }
    }
    
  //验证势力是否一致   r源id  i目标id
   private boolean ifComLegion(int r,int i) {
       int sourceLegion=MapBin.get(r).getFacility();
       int regionLegion=MapBin.get(i).getFacility();
       if(sourceLegion==regionLegion) {
           return true;
       }else if(sourceLegion==255) {
           return true;
       }else {
           return false;
       }
       
   }
    
   //将海港城市归为最近的陆地城市
    private void updHabourRegionForE() {
        List<Integer> habour= getRegions(5);
        List<Integer> rsIds,tempIds;int id;
        Random rand = new Random();
        for(Integer r:habour) {
            rsIds = getAroundIdById(r, 4);
            if (rsIds.size() == 0) {
               Gdx.app.log("警告", r+":海港周围为空");
            }else {
                id= rsIds.get(rand.nextInt(rsIds.size()));
                if(id!=-1&&MapBin.get(r).getRegionId()==r) {
                    MapBin.get(r).setRegionId(MapBin.get(id).getRegionId());
                }
            }
        }
    }
    
    public void updHabourForE() {
        updHabourRegionForE();
        logBlankGrid();
    }

    //替换当前的地区的所有相同区块为一个id的所在区块
    public void replaceRegionIdById(int id){
        int regionId=MapBin.get(id).getRegionId();
        for (MapBin mapBin : MapBin) {
            if(mapBin.getRegionId()==regionId){
                mapBin.setRegionId(id);
            }
        }
    }


    //替换当前空白的地块以及与其相邻的地块的region
    public void replaceRegionIdForFFArea(int id,int regionId){
        //替换不穿海,只替换该区域的
        List<Integer> rs= new ArrayList<Integer>();
        List<Integer> tempI;
        if(MapBin.get(id).getRegionId()!=0){
            return;
        }else{
            List<Integer> tempIds=getAroundIdById(id, 6);
            rs.addAll(tempIds);
            int n=0;
            do{
                tempIds= (List<Integer>) ((ArrayList<Integer>) rs).clone();
                for(int i:tempIds){
                    tempI=getAroundIdById(i, 6);
                    rs.removeAll(tempI);
                    rs.addAll(tempI);
                }
                n=n+1;
                if(n>5){
                    break;
                }
            }while(ComUtil.ifListContainListByInteger(rs,tempIds));


            for(int i:rs){
                MapBin.get(i).setRegionId(regionId);
            }
        }
    }

    //批量获取符合某种条件的地块,条件参看getAroundIdById
    public List<Integer> getIdsByAround(int type){
        List<Integer> rsGrid=new ArrayList<Integer>();
        List<Integer> rs;
        int id=0;
        for (MapBin mapBin : MapBin) {
            rs = getAroundIdById(id, type);
            if(rs.size()>0){
                rsGrid.add(id);
            }
            id=id+1;
        }
        return rsGrid;
    }

}
MapBinDAO

效果如下:(原点为核心,同颜色为一个省区)

posted on 2019-05-15 23:45  黑狱  阅读(526)  评论(0编辑  收藏  举报