📄 randommapgenerator.java
字号:
return 675; } else if ("large".equals(boardSize)) { return 850; } else if ("huge".equals(boardSize)) { return 1000; } return 750; }public static int getHeightForSize(String boardSize) { if ("tiny".equals(boardSize)) { return 266; } else if ("small".equals(boardSize)) { return 366; } else if ("large".equals(boardSize)) { return 566; } else if ("huge".equals(boardSize)) { return 666; } return 466; }// gives the approximate wrapped distance between shapes i and jprivate double wrappedDistance( int i, int j) { int lower, higher; // one shape will be near the left and onr near the right side of the board if (shapeBounds[i].getX() < shapeBounds[j].getX()) { lower = i; higher = j; } else { lower = j; higher = i; } // wrap a point on the bounds of the low shape to a position higher than the edge of the board Point2D mapHigherPoint = new Point2D.Double(shapeBounds[lower].getX()+topx, shapeBounds[lower].getY()); Point2D highPoint = new Point2D.Double(shapeBounds[higher].getX()+shapeBounds[higher].getWidth(), shapeBounds[higher].getY()); return mapHigherPoint.distance(highPoint); }// initialize must ONLY be called after numCountries has been setprivate void initialize() { shapeCount = 0; // we set up a variety of data structures here shapes = new GeneralPath[numCountries]; shapeBounds = new Rectangle2D[numCountries]; points = new Vector[numCountries]; // each shape also gets a vector of Point's that it is made of allPoints = new Hashtable(); countries = new Country[numCountries]; lines = new Vector(); // it holds ExtraLines distanceMemory = new int[numCountries][numCountries]; // distanceMemory[][] is our memory of computed distances // it shouldn't be used until all the shapes are finished for (int i = 0; i<numCountries; i++) { points[i] = new Vector(); countries[i] = new Country(i, -1, this); // they have no continentCode yet for (int j = 0; j < numCountries; j++) distanceMemory[i][j] = -1; } }// connects any shapes whose distance < <level>private void connectShapesAt(int level) { for (int i = 0; i < numCountries; i++) for (int j = 0; j < numCountries; j++) { if (i != j && !countries[i].canGoto(countries[j]) && distanceBetween(i,j) < level) { makeCountriesTouch(i, j); addLineBetweenShapes(i, j); } } }/** Connects any shapes that are in different continents and whose distance is below 'level'. */private void connectContinentsAt(int level) { for (int i = 0; i < numCountries; i++) for (int j = 0; j < numCountries; j++) { if (i != j && !countries[i].canGoto(countries[j]) && countries[i].getContinent() != countries[j].getContinent() && distanceBetween(i,j) < level && lineCanExistBetween(i,j)) { makeCountriesTouch(i, j); addLineBetweenShapes(i, j); } } }/** Generates a couple shapes close together. */private void generateNugget() { // pick a random point: double x = 30 + rand.nextInt(topx-60); double y = 30 + rand.nextInt(topy-60); if (! createShapeAt( x, y )) { // bad shape. restart the nugget somewhere else generateNugget(); return; } //debug("generateNugget put first shape at ("+x+", "+y+")"); // Otherwise a shape was created. // now make some other shapes near to this nugget... int nuggetBase = shapeCount-1; Vector nuggetShapeIndexes = new Vector(); nuggetShapeIndexes.add(new Integer(nuggetBase)); int desiredContSize = 2 + rand.nextInt(8); for (int tries = 0; nuggetShapeIndexes.size() < desiredContSize && tries < 30 && shapeCount < numCountries; tries++) { // to start with, we try shapes close to the first shape int closeToShape = nuggetBase; Point2D randPoint = (Point2D)points[closeToShape].get( rand.nextInt(points[closeToShape].size()) ); if (shapes[closeToShape].contains( randPoint.getX()-5, randPoint.getY() ) ) { x = randPoint.getX()+(minRadius*2); y = randPoint.getY(); } else { x = randPoint.getX()-(minRadius*2); y = randPoint.getY(); } // we have the new point. try a shape there: if (createShapeAt( x, y )) { // good shape nuggetShapeIndexes.add(new Integer(shapeCount-1)); } } //debug(" -> placed "+(shapeCount-nuggetBase)+" shapes total in this nugget"); }private boolean createShapeAt( double x, double y ) { generateNextShapeAroundPoint(x, y); if (shapes[shapeCount] != null) shapeBounds[shapeCount] = shapes[shapeCount].getBounds2D(); // keep it if a shape was drawn around this point and it is not too small and not too big if (shapes[shapeCount] != null && shapeBounds[shapeCount].getWidth() > 40 && shapeBounds[shapeCount].getHeight() > 40 && shapeBounds[shapeCount].getWidth() < topx/3 && shapeBounds[shapeCount].getHeight() < topy/3) { // because generateShapeAroundPoint() only sets up adjoingingLists one-way, we must add the reverse connections here: addReverseLinks(countries[shapeCount]); // Add the shapes point to the allPoints hashtable for (int p = 0; p < points[shapeCount].size(); p++) { Object key = allPoints.get(points[shapeCount].get(p)); if (key == null) allPoints.put(points[shapeCount].get(p), new Integer(1)); else { allPoints.put(points[shapeCount].get(p), new Integer( ((Integer)key).intValue() + 1 )); } } shapeCount++; loader.setLoadText("creating board. shapeCount -> "+shapeCount+"/"+numCountries); return true; } else { // we are ditching the shape, so clear the adjoingList: countries[shapeCount].clearAdjoiningList(this); points[shapeCount] = new Vector(); return false; } }/** Generate the next country shape around the given point. It will fill in shapes[shapeCount] - possibly with null if it fails to make a shape. */public void generateNextShapeAroundPoint( double pointx, double pointy ) { Point2D shapeOrigin = new Point2D.Double(pointx, pointy); if ( isInShapes( shapeOrigin ) != -1) { //debug(" abort -> started in another shape"); shapes[shapeCount] = null; return; // we don't want to start inside another shape } //debug("generateNextShapeAroundPoint called. shape="+shapeCount+", shapeOrigin="+shapeOrigin); // We will return <shape>. create it here: shapes[shapeCount] = new GeneralPath(); GeneralPath shape = shapes[shapeCount]; // The first point in the shape is a special case double theta = 0.001; double radius = 35 + rand.nextInt(30); // between 35 and 65 Point2D p = pointFromPolar(shapeOrigin, theta, radius); // Make sure that putting the first point there won't jump over another shape Point2D mid = getMiddlePoint(shapeOrigin, p); if ( isInShapes(mid) != -1 ) { p = mid; radius = shapeOrigin.distance( p ); } // Bring it closer until there is no conflict. while ( radius >= minRadius && isInShapes(p) != -1 ) { radius -= 5; p = pointFromPolar(shapeOrigin, theta, radius); } if (radius < minRadius) { shapes[shapeCount] = null; return; } if (! validPoint(p) ) { shapes[shapeCount] = null; return; } // So now we have a good first point points[shapeCount].add(p); shape.moveTo((float)p.getX(), (float)p.getY()); // used for radius convergence double initialRadius = radius; // Start drawing the circle... while (theta < 6.2 && theta != 0) // this is close to 2 pi { // Set the radius and theta to the correct values for the last point added radius = shapeOrigin.distance( shape.getCurrentPoint() ); if (radius < minRadius) { //debug("ABORT -> radius was smaller than min"); // then we just placed a point with an invalid radius. abort shapes[shapeCount] = null; return; } theta = calcTheta(shapeOrigin, shape.getCurrentPoint()); if (theta == -1) { //debug(" abort -> calcTheta returned -1 (at start of circle loop)"); shapes[shapeCount] = null; return; } // and get the next point to add theta += thetaStep; radius = Math.max( nearNumber(radius), minRadius); // a slightly random radius, above the minimum if (theta > fullCircle-thetaStep || theta == 0) { // then we are done going around the circle. break out of the loop break; } if (theta > 4.712) // 4.712 ~= to PI*1.5 { // then we are in the last quarter of the circle shape. // ensure that the radius eventually converges to what it was for the first point. // The maximum difference is limited to 1 per 2 degrees away from the start // (ie when theta is 270 degrees, it is 90 degrees away from the start and the max difference is 45) double maxDifference = (double)(((fullCircle-theta)*360)/(2*fullCircle)); maxDifference = Math.abs(maxDifference); if (initialRadius - radius > maxDifference) { //debug("converging radius1 from "+radius+" to "+(initialRadius - maxDifference)); //debug("-> theta="+theta+", maxDifference="+maxDifference+", initialRadius="+initialRadius); radius = initialRadius - maxDifference; } else if (radius - initialRadius > maxDifference) { //debug("converging radius2 from "+radius+" to "+(initialRadius + maxDifference)); radius = initialRadius + maxDifference; } } p = pointFromPolar(shapeOrigin, theta, radius); // Test to see if the new point conflicts with other shapes. int conflict = isInShapes(p); if (conflict == -1) { // then there was no conflict with the point itself. // but drawing the line to the point could still cause overlap. test for that here. mid = getMiddlePoint(shape.getCurrentPoint(), p); conflict = isInShapes(mid); } if ( conflict == -1 ) { if (! validPoint(p) ) { shapes[shapeCount] = null; return; }//debug(" drawing the shape. adding a point with radius="+radius+", theta="+theta); // there was no intersection with a shape. thus p is a valid point. Add it to the shape. points[shapeCount].add(p); shape.lineTo((float)p.getX(), (float)p.getY()); } else { // Then there was a conflict. Now the fun really begins // Since the point p has hit inside a shape, these two shapes will touch: countries[shapeCount].addToAdjoiningList( countries[conflict], this ); // Make this shape follow the outline of the conflict shape for a bit. // We start by finding the border-point closest to shape's last point: int borderPoint = getClosestBorderNotInShape(shape.getCurrentPoint(), conflict, shapeCount); if (borderPoint == -1) { //debug("getClosestBorderNotInShape returned -1. abort the shape"); shapes[shapeCount] = null; return; } // make p be the same point as the closest borderPoint and add it to the shape p = (Point2D)points[conflict].get(borderPoint); points[shapeCount].add(p); shape.lineTo((float)p.getX(), (float)p.getY());//debug(" --> CONFLICT with shape "+conflict+", shifting to borderPoint "+borderPoint); // So we have matched up one border point. // continue to follow the border until we hit an exit condition // Note: within the loop we need to know the radius and theta of the last point. // Set the initial values here double lastRadius = shapeOrigin.distance(p); double lastTheta = calcTheta(shapeOrigin, p ); if (lastTheta == -1) {//debug(" abort -> calcTheta returned -1"); shapes[shapeCount] = null; return; } boolean keepFollowingBorder = true; while ( keepFollowingBorder && theta < fullCircle-thetaStep && theta != 0 ) { borderPoint--; // this will make us choose the previous border point. if (borderPoint == -1) { borderPoint = points[conflict].size()-1; //debug("wrapping to first border point"); } p = (Point2D)points[conflict].get(borderPoint); // But we don't want to follow the border too far. // We only allow theta to backtrack if the radius also gets smaller // calculate the radius and theta: radius = shapeOrigin.distance(p); theta = calcTheta(shapeOrigin, p); if (theta == -1) { //debug(" abort -> calcTheta returned -1 (in 2nd place)"); shapes[shapeCount] = null; return; } if (theta < lastTheta && lastRadius < radius) { // then theta is backtracking while the radius gets bigger. // this is an exit condition for following the border // NOTE: we don't even bother to add this point keepFollowingBorder = false;//debug("exit condition 1"); } else { // add it to the shape lastTheta = theta; lastRadius = radius; points[shapeCount].add(p); shape.lineTo((float)p.getX(), (float)p.getY());//debug(" ---> keepFollowingBorder tick. borderPoint="+borderPoint); // If the point we just added is also in 2 or more other shapes then // stop following this border Object key = allPoints.get(p); if (key != null && ((Integer)key).intValue() > 1) { //debug("exit condition 2"); keepFollowingBorder = false; } } } // end of keepFollowingBorder loop // So we are done following that shape for now. // We will continue drawing the circle now. } // end of dealing with conflict point } // end of stepTheta for-loop // So now we are done drawing our circle-ish shape. // the only thing left to do is close it. shape.closePath(); // check if we swallowed an entire country // check against a box that is slightly bigger then the new shape Rectangle2D eatCheck = shape.getBounds2D(); eatCheck = new Rectangle2D.Double(eatCheck.getX()-2, eatCheck.getY()-2, eatCheck.getWidth()+4, eatCheck.getHeight()+4); for (int i = 0; i < shapeCount; i++) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -