diff --git a/src/hu/openig/mechanics/DefaultAIControls.java b/src/hu/openig/mechanics/DefaultAIControls.java index 748be002..e6a6bbd7 100644 --- a/src/hu/openig/mechanics/DefaultAIControls.java +++ b/src/hu/openig/mechanics/DefaultAIControls.java @@ -8,6 +8,7 @@ package hu.openig.mechanics; +import hu.openig.core.Location; import hu.openig.model.AIAttackMode; import hu.openig.model.AIControls; import hu.openig.model.AIResult; @@ -27,6 +28,8 @@ import hu.openig.model.World; import java.awt.Point; +import java.util.ArrayList; +import java.util.Random; /** * The default AI controls. @@ -223,9 +226,16 @@ public AIResult actionPlaceBuilding(Planet planet, BuildingType buildingType) { if (!planet.canBuild(buildingType)) { log(p, "PlaceBuilding, Planet = %s, Type = %s, FAIL = not supported or no colony hub", planet.id, buildingType.id); return AIResult.NO_AVAIL; - } else - if (p.money() >= buildingType.cost) { - Point pt = planet.surface.placement.findLocation(planet.getPlacementDimensions(buildingType)); + } else if (p.money() >= buildingType.cost) { + Point pt; + if (buildingType.kind.equals("Gun") || buildingType.kind.equals("Shield")) { + Location loc = findLocationForPlanetaryDefenseBuilding(planet); + System.out.printf("PlaceBuilding Defensive Building, Planet = %s, Type = %s Loc: %s \n", planet.id, buildingType.id, loc); + pt = planet.surface.placement.findLocation(planet.getPlacementDimensions(buildingType), loc); + System.out.println(pt); + } else { + pt = planet.surface.placement.findLocation(planet.getPlacementDimensions(buildingType)); + } if (pt != null) { AutoBuilder.construct(w, planet, buildingType, pt); // log("PlaceBuilding, Planet = %s, Type = %s", planet.id, buildingType.id); @@ -238,6 +248,22 @@ public AIResult actionPlaceBuilding(Planet planet, BuildingType buildingType) { return AIResult.NO_MONEY; } } + + Location findLocationForPlanetaryDefenseBuilding(Planet planet) { + for (Building b : planet.surface.buildings.findByKind("Gun")) { + return b.location(); + } + for (Building b : planet.surface.buildings.findByKind("Shield")) { + return b.location(); + } + ArrayList corners = new ArrayList<>(); + corners.add(Location.of(0,0)); + corners.add(Location.of(-planet.surface.height + 1,-planet.surface.height + 1)); + corners.add(Location.of(planet.surface.width - planet.surface.height + 1, - planet.surface.height - planet.surface.width + 1)); + corners.add(Location.of(planet.surface.width - 1, -planet.surface.width + 1)); + return corners.get((new Random()).nextInt(4)); + } + @Override public void actionDemolishBuilding(Planet planet, Building b) { planet.demolish(b); diff --git a/src/hu/openig/model/PlanetSurface.java b/src/hu/openig/model/PlanetSurface.java index 3472ef98..bd80893e 100644 --- a/src/hu/openig/model/PlanetSurface.java +++ b/src/hu/openig/model/PlanetSurface.java @@ -645,6 +645,17 @@ public boolean canPlaceBuilding(int x, int y) { public Point findLocation(Dimension dim) { return findLocation(dim.width, dim.height); } + + /** + * Find a location for the given dimensions, starting from a specific point on the surface. + *

Note: the dimensions should incorporate 1+1 road on both axis.

+ * @param dim the dimensions + * @param preferredLocation the point from which the location search starts from + * @return the location or null if not found + */ + public Point findLocation(Dimension dim, Location preferredLocation) { + return findLocation(dim.width, dim.height, preferredLocation); + } /** * Find a location on the surface which can support a building (and surrounding roads) * with the given size. The location search starts of from the center of the map @@ -656,11 +667,26 @@ public Point findLocation(Dimension dim) { public Point findLocation(int width, int height) { int cx = this.width() / 2 - this.height() / 2 - width / 2; int cy = -this.width() / 2 - this.height() / 2 + height / 2; + return findLocation(width, height, Location.of(cx, cy)); + } - int rx1 = Math.abs(this.width() - cx); - int rx2 = Math.abs(-this.height() - cx); - int ry1 = Math.abs(this.width() + this.height() + cy); - int ry2 = Math.abs(cy); + /** + * Find a location on the surface which can support a building (and surrounding roads) + * with the given size. The location search starts from the specified point on the surface. + * @param width should be the building tile width + 2 + * @param height should be the building tile height + 2 + * @param preferredLocation the point from which the location search starts from + * @return the top-left point where this building could be built, null indicates that + * no suitable location is present + */ + public Point findLocation(int width, int height, Location preferredLocation) { + int startX = preferredLocation.x; + int startY = preferredLocation.y; + + int rx1 = Math.abs(this.width() - startX); + int rx2 = Math.abs(-this.height() - startX); + int ry1 = Math.abs(this.width() + this.height() + startY); + int ry2 = Math.abs(startY); int maxr = Math.max(Math.max(rx1, rx2), Math.max(ry1, ry2)); // the square size List candidates = new ArrayList<>(); @@ -671,10 +697,10 @@ public Point findLocation(int width, int height) { int[] ys = new int[size]; clockwise(xs, ys, len); for (int k = 0; k < size; k++) { - int x0 = cx + xs[k] - i; - int y0 = cy - ys[k] + i; + int x0 = startX + xs[k] - i; + int y0 = startY - ys[k] + i; if (canPlaceBuilding(x0, y0, width, height)) { - int d = (cx - x0) * (cx - x0) + (cy - y0) * (cy - y0); + int d = (startX - x0) * (startX - x0) + (startY - y0) * (startY - y0); PlaceCandidate pc = createCandidate(x0, y0, width, height, d); if (pc != null) { candidates.add(pc);