Fixes geographical region intitialization so that native settlements can be placed correctly.

This commit is contained in:
Stian Grenborgen 2024-01-09 19:19:20 +01:00
parent cb44400862
commit 6c9fb07414
1 changed files with 154 additions and 34 deletions

View File

@ -19,13 +19,12 @@
package net.sf.freecol.server.model;
import java.awt.Rectangle;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Queue;
import java.awt.Rectangle;
import net.sf.freecol.common.model.Direction;
import net.sf.freecol.common.model.Game;
import net.sf.freecol.common.model.HistoryEvent;
@ -236,6 +235,86 @@ public class ServerRegion extends Region {
h.setScore(score);
cs.addGlobalHistory(getGame(), h);
}
/**
* Determines how to separate the given map into three
* parts (north, center and south) with equal amount of land tiles
* for each.
*
* @param map The map.
* @return The indexes separating the three parts.
*/
private static int[] findYForThirdsOfLand(Map map) {
final int[] landTiles = new int[map.getHeight() - 1];
long sum = 0;
for (Tile t : map) {
if (t.isLand() && !t.isPolar()) {
landTiles[t.getY()]++;
sum++;
}
}
return findThirdsOfValues(landTiles, sum);
}
/**
* Determines how to separate the given submap into three
* parts (west, center and east) with equal amount of land tiles
* for each.
*
* @param map The map.
* @param startY The starting Y-coordinate for the submap (inclusive).
* @param endY The ending Y-coordinate for the submap (inclusive).
* @return The indexes separating the three parts.
*/
private static int[] findXForThirdsOfLand(Map map, int startY, int endY) {
final List<Tile> subMap = map.subMap(0, startY, map.getWidth() - 1, endY - startY + 1);
final int[] landTiles = new int[map.getWidth() - 1];
long sum = 0;
for (Tile t : subMap) {
if (t.isLand() && !t.isPolar()) {
landTiles[t.getX()]++;
sum++;
}
}
return findThirdsOfValues(landTiles, sum);
}
/**
* Finds the indexes for separating the given array into three parts.
* @param timesTheValue An array containing the number of elements for
* each number (as given by the index).
* @param sum The total sum.
* @return The indexes separating the three parts.
*/
private static int[] findThirdsOfValues(int[] timesTheValue, long sum) {
final int[] result = new int[2];
int accumulatedSum = 0;
boolean needFirst = true;
for (int i=0; i<timesTheValue.length; i++) {
accumulatedSum += timesTheValue[i];
if (needFirst && accumulatedSum >= sum / 3) {
result[0] = i;
needFirst = false;
}
if (accumulatedSum >= (2 * sum) / 3) {
result[1] = i;
break;
}
}
return result;
}
private static Rectangle ensureWithinMap(Map map, Rectangle bounds) {
final int capX = Math.max(0, bounds.x);
final int capY = Math.max(0, bounds.y);
final int capWidth = Math.min(map.getWidth() - 1, bounds.x + Math.min(map.getWidth() - 1, bounds.width)) - capX;
final int capHeight = Math.min(map.getHeight() - 1, bounds.y + Math.min(map.getHeight() - 1, bounds.height)) - capY;
return new Rectangle(capX, capY, capWidth, capHeight);
}
/**
* Make the fixed regions if they do not exist in a given map.
@ -292,90 +371,131 @@ public class ServerRegion extends Region {
// used by the MapGenerator to place Indian Settlements. Note
// that these regions are "virtual", i.e. having a bounding
// box, but contain no tiles directly.
final int thirdWidth = map.getWidth()/3;
final int twoThirdWidth = 2 * thirdWidth;
final int thirdHeight = map.getHeight()/3;
final int twoThirdHeight = 2 * thirdHeight;
final int[] yDelimiterThirds = findYForThirdsOfLand(map);
int[] xDelimiterThirds = findXForThirdsOfLand(map, 0, yDelimiterThirds[0]);
ServerRegion northWest = (ServerRegion)fixed.get("model.region.northWest");
if (northWest == null) {
northWest = new ServerRegion(map, "model.region.northWest",
RegionType.LAND, null);
northWest.bounds.setBounds(new Rectangle(0,0,thirdWidth,thirdHeight));
northWest = new ServerRegion(map, "model.region.northWest", RegionType.LAND, null);
lb.add("+NW");
}
northWest.bounds.setBounds(ensureWithinMap(map, new Rectangle(
0,
0,
xDelimiterThirds[0],
yDelimiterThirds[0]
)));
result.add(northWest);
ServerRegion north = (ServerRegion)fixed.get("model.region.north");
if (north == null) {
north = new ServerRegion(map, "model.region.north",
RegionType.LAND, null);
north.bounds.setBounds(new Rectangle(thirdWidth,0,thirdWidth,thirdHeight));
north = new ServerRegion(map, "model.region.north",RegionType.LAND, null);
lb.add("+N");
}
north.bounds.setBounds(ensureWithinMap(map, new Rectangle(
xDelimiterThirds[0],
0,
xDelimiterThirds[1] - xDelimiterThirds[0],
yDelimiterThirds[0]
)));
result.add(north);
ServerRegion northEast = (ServerRegion)fixed.get("model.region.northEast");
if (northEast == null) {
northEast = new ServerRegion(map, "model.region.northEast",
RegionType.LAND, null);
northEast.bounds.setBounds(new Rectangle(twoThirdWidth,0,thirdWidth,thirdHeight));
northEast = new ServerRegion(map, "model.region.northEast", RegionType.LAND, null);
lb.add("+NE");
}
northEast.bounds.setBounds(ensureWithinMap(map, new Rectangle(
xDelimiterThirds[1],
0,
Integer.MAX_VALUE,
yDelimiterThirds[0]
)));
result.add(northEast);
xDelimiterThirds = findXForThirdsOfLand(map, yDelimiterThirds[0], yDelimiterThirds[1]);
ServerRegion west = (ServerRegion)fixed.get("model.region.west");
if (west == null) {
west = new ServerRegion(map, "model.region.west",
RegionType.LAND, null);
west.bounds.setBounds(new Rectangle(0,thirdHeight,thirdWidth,thirdHeight));
west = new ServerRegion(map, "model.region.west", RegionType.LAND, null);
lb.add("+W");
}
west.bounds.setBounds(ensureWithinMap(map, new Rectangle(
0,
yDelimiterThirds[0],
xDelimiterThirds[0],
yDelimiterThirds[1] - yDelimiterThirds[0]
)));
result.add(west);
ServerRegion center = (ServerRegion)fixed.get("model.region.center");
if (center == null) {
center = new ServerRegion(map, "model.region.center",
RegionType.LAND, null);
center.bounds.setBounds(new Rectangle(thirdWidth,thirdHeight,thirdWidth,thirdHeight));
center = new ServerRegion(map, "model.region.center", RegionType.LAND, null);
lb.add("+center");
}
center.bounds.setBounds(ensureWithinMap(map, new Rectangle(
xDelimiterThirds[0],
yDelimiterThirds[0],
xDelimiterThirds[1] - xDelimiterThirds[0],
yDelimiterThirds[1] - yDelimiterThirds[0]
)));
result.add(center);
ServerRegion east = (ServerRegion)fixed.get("model.region.east");
if (east == null) {
east = new ServerRegion(map, "model.region.east",
RegionType.LAND, null);
east.bounds.setBounds(new Rectangle(twoThirdWidth,thirdHeight,thirdWidth,thirdHeight));
east = new ServerRegion(map, "model.region.east", RegionType.LAND, null);
lb.add("+E");
}
east.bounds.setBounds(ensureWithinMap(map, new Rectangle(
xDelimiterThirds[1],
yDelimiterThirds[0],
Integer.MAX_VALUE,
yDelimiterThirds[1] - yDelimiterThirds[0]
)));
result.add(east);
xDelimiterThirds = findXForThirdsOfLand(map, yDelimiterThirds[1], map.getHeight() - 1);
ServerRegion southWest = (ServerRegion)fixed.get("model.region.southWest");
if (southWest == null) {
southWest = new ServerRegion(map, "model.region.southWest",
RegionType.LAND, null);
southWest.bounds.setBounds(new Rectangle(0,twoThirdHeight,thirdWidth,thirdHeight));
southWest = new ServerRegion(map, "model.region.southWest", RegionType.LAND, null);
lb.add("+SW");
}
southWest.bounds.setBounds(ensureWithinMap(map, new Rectangle(
0,
yDelimiterThirds[1],
xDelimiterThirds[0],
Integer.MAX_VALUE
)));
result.add(southWest);
ServerRegion south = (ServerRegion)fixed.get("model.region.south");
if (south == null) {
south = new ServerRegion(map, "model.region.south",
RegionType.LAND, null);
south.bounds.setBounds(new Rectangle(thirdWidth,twoThirdHeight,thirdWidth,thirdHeight));
south = new ServerRegion(map, "model.region.south", RegionType.LAND, null);
lb.add("+S");
}
south.bounds.setBounds(ensureWithinMap(map, new Rectangle(
xDelimiterThirds[0],
yDelimiterThirds[1],
xDelimiterThirds[1] - xDelimiterThirds[0],
Integer.MAX_VALUE
)));
result.add(south);
ServerRegion southEast = (ServerRegion)fixed.get("model.region.southEast");
if (southEast == null) {
southEast = new ServerRegion(map, "model.region.southEast",
RegionType.LAND, null);
southEast.bounds.setBounds(new Rectangle(twoThirdWidth,twoThirdHeight,thirdWidth,thirdHeight));
southEast = new ServerRegion(map, "model.region.southEast", RegionType.LAND, null);
lb.add("+SE");
}
southEast.bounds.setBounds(ensureWithinMap(map, new Rectangle(
xDelimiterThirds[1],
yDelimiterThirds[1],
Integer.MAX_VALUE,
Integer.MAX_VALUE
)));
result.add(southEast);
boolean allOceans = true;