private static boolean hasANeighborNotIn(Coord c, Collection<Coord> others) { for (Direction dir : Direction.OUTWARDS) { if (!others.contains(c.translate(dir))) return true; } return false; }
/** * Get a list of Coords, each randomly positioned around the given center out to the given radius (measured with * Euclidean distance, so a true circle), but with the given minimum distance from any other Coord in the list. * The parameters maxX and maxY should typically correspond to the width and height of the map; no points will have * positions with x equal to or greater than maxX and the same for y and maxY; similarly, no points will have * negative x or y. * @param center the center of the circle to spray Coords into * @param radius the radius of the circle to spray Coords into * @param minimumDistance the minimum distance between Coords, in Euclidean distance as a float. * @param maxX one more than the highest x that can be assigned; typically an array length * @param maxY one more than the highest y that can be assigned; typically an array length * @param pointsPerIteration with small radii, this can be around 5; with larger ones, 30 is reasonable * @param rng an IRNG to use for all random sampling. * @return an ArrayList of Coord that satisfy the minimum distance; the length of the array can vary */ public static OrderedSet<Coord> sampleCircle(Coord center, float radius, float minimumDistance, int maxX, int maxY, int pointsPerIteration, IRNG rng) { int radius2 = Math.round(radius); return sample(center.translate(-radius2, -radius2), center.translate(radius2, radius2), radius, minimumDistance, maxX, maxY, pointsPerIteration, rng); }
@Override public Zone translate(int x, int y) { return new Impl(bottomLeft.translate(x, y), width, height); }
@Override public Rectangle extend() { return new Rectangle.Impl(bottomLeft.translate(Direction.DOWN_LEFT), width + 2, height + 2); }
/** * Internal use. Marks a circle of points centered on pos, extending out to radius in Euclidean measurement. Marks * all cells in the circle as room floors. * @param pos center position to mark * @param radius radius to extend in all directions from center * @return null if no points in the circle were blocked by walls, otherwise a Coord blocked by a wall */ private Coord markCircle(Coord pos, int radius) { Coord block = null; int high; radius = Math.max(1, Math.round(radius * Math.min(roomWidth, roomHeight))); for (int dx = -radius; dx <= radius; ++dx) { high = (int)Math.floor(Math.sqrt(radius * radius - dx * dx)); for (int dy = -high; dy <= high; ++dy) { if(mark(pos.x + dx, pos.y + dy)) block = pos.translate(dx, dy); else markEnvironmentRoom(pos.x + dx, pos.y + dy); } } return block; } /**
/** * Removes a circle from {@code zone}, by taking the circle's center in * {@code zone} 's border: {@code border}. * * @param border * {@code result}'s border. */ private void inebriate0(IRNG rng, List<Coord> zone, List<Coord> border, int nb) { assert !border.isEmpty(); assert !zone.isEmpty(); final int width = rng.nextInt(nb) + 1; final int height = rng.nextInt(nb) + 1; final int radius = Math.max(1, Math.round(nb * Math.min(width, height))); final Coord center = rng.getRandomElement(border); zone.remove(center); for (int dx = -radius; dx <= radius; ++dx) { final int high = (int) Math.floor(Math.sqrt(radius * radius - dx * dx)); for (int dy = -high; dy <= high; ++dy) { final Coord c = center.translate(dx, dy); zone.remove(c); if (zone.isEmpty()) return; } } }
assert !result.contains(current); result.add(current); current = current.translate(Direction.RIGHT); assert !result.contains(current); result.add(current); current = current.translate(Direction.RIGHT); result.add(current); current = current.translate(Direction.UP); result.add(current); current = current.translate(Direction.UP);
/** * Draws a line from (startX, startY) to (endX, endY) using the Drunkard's Walk algorithm. Returns a List of Coord * in order. * @param startX x of starting point * @param startY y of starting point * @param endX x of ending point * @param endY y of ending point * @param width maximum map width * @param height maximum map height * @param weight between 0.5 and 1.0, usually. 0.6 makes very random walks, 0.9 is almost a straight line. * @param rng the random number generator to use * @return List of Coord, including (startX, startY) and (endX, endY) and all points walked between */ public static List<Coord> line(int startX, int startY, int endX, int endY, int width, int height, double weight, IRNG rng) { List<Coord> pts = new ArrayList<>(); Coord start = Coord.get(startX, startY); Direction dir; do { pts.add(start); dir = stepWobbly(start.x, start.y, endX, endY, weight, width, height, rng); start = start.translate(dir); if(start.x < 1 || start.y < 1 || start.x >= width - 1 || start.y >= height - 1) break; }while (dir != Direction.NONE); return pts; }
/** * Creates a new Rectangle that is smaller than r by 1 cell from each of r's edges, to a minimum of a 1x1 cell. * @param r a Rectangle to shrink * @return the shrunken Rectangle, newly-allocated */ public static Rectangle shrink(Rectangle r) { return new Rectangle.Impl(r.getBottomLeft().translate(1, 1), Math.max(1, r.getWidth() - 2), Math.max(1, r.getHeight() - 2)); }
@Override /* Convenience implementation, feel free to override. */ public Collection<Coord> getExternalBorder() { final int sz = size(); final List<Coord> result = new ArrayList<Coord>(sz); final List<Coord> internalBorder = sz <= 1 ? getAll() : Helper.border(getAll(), null); final int ibsz = internalBorder.size(); for (int i = 0; i < ibsz; i++) { final Coord b = internalBorder.get(i); for (Direction dir : Direction.OUTWARDS) { final Coord borderNeighbor = b.translate(dir); if (!contains(borderNeighbor)) result.add(borderNeighbor); } } return result; }
"Unexpected direction in " + getClass().getSimpleName() + "::extendRoomOnce: " + d); case DOWN: first = bl.translate(Direction.DOWN); way = Direction.RIGHT; steps = r.getWidth(); break; case LEFT: first = bl.translate(Direction.LEFT); way = Direction.UP; steps = r.getHeight(); break; case RIGHT: first = bl.translate(r.getWidth() - 1, 0).translate(Direction.RIGHT); way = Direction.UP; steps = r.getHeight(); break; case UP: first = bl.translate(0, -r.getHeight() + 1).translate(Direction.UP); way = Direction.RIGHT; steps = r.getWidth(); current = current.translate(way); steps--;
return new ArrayList<>(path); currentPos = currentPos.translate(dirs[choice].deltaX, dirs[choice].deltaY); if (gradientMap[currentPos.x][currentPos.y] == 0) break;
/** * @param d A direction. * @return {@code r} extended to {@code d} by one row and/or column. */ public static Rectangle extend(Rectangle r, Direction d) { final Coord bl = r.getBottomLeft(); final int width = r.getWidth(); final int height = r.getHeight(); switch (d) { case DOWN_LEFT: return new Rectangle.Impl(bl.translate(Direction.DOWN_LEFT), width + 1, height + 1); case DOWN_RIGHT: return new Rectangle.Impl(bl.translate(Direction.DOWN), width + 1, height + 1); case NONE: return r; case UP_LEFT: return new Rectangle.Impl(bl.translate(Direction.LEFT), width + 1, height + 1); case UP_RIGHT: return new Rectangle.Impl(bl, width + 1, height + 1); case DOWN: return new Rectangle.Impl(bl.translate(Direction.DOWN), width, height + 1); case LEFT: return new Rectangle.Impl(bl.translate(Direction.LEFT), width + 1, height); case RIGHT: return new Rectangle.Impl(bl, width + 1, height); case UP: return new Rectangle.Impl(bl, width, height + 1); } throw new IllegalStateException("Unmatched direction in Rectangle.Utils::extend: " + d); }
Coord adj = cell.translate(dirs[d].deltaX, dirs[d].deltaY); if(!adj.isWithin(width, height)) continue;
Coord tl, tr, twl, twr, wl = null, wr = null; for (Coord l : left.rightDoors) { tl = twl = l.translate(leftX, leftY); if (tl.x > 0 && tl.x < width - 1 && map[tl.x - 1][tl.y] != '#') tl = Coord.get(tl.x + 1, tl.y); tr = twr = r.translate(rightX, rightY); if (tr.x > 0 && tr.x < width - 1 && map[tr.x - 1][tr.y] != '#') tr = Coord.get(tr.x + 1, tr.y);
spillMap[cell.x][cell.y] = true; for (int d = 0; d < dirs.length; d++) { Coord adj = cell.translate(dirs[d].deltaX, dirs[d].deltaY); double h = heuristic(dirs[d]); if (physicalMap[adj.x][adj.y] && !spillMap[adj.x][adj.y] && !impassable.contains(adj) && rng.nextDouble() <= 1.0 / h) {
for (int i = 0; i < len; i++) { result.add(now); now = now.translate(dir);
/** * @param r * @param dir * @return The coord at the corner identified by {@code dir} in * {@code r}. */ public static Coord getCorner(Rectangle r, Direction dir) { switch (dir) { case DOWN_LEFT: return r.getBottomLeft(); case DOWN_RIGHT: return r.getBottomLeft().translate(r.getWidth() - 1, 0); case UP_LEFT: /* -y because in SquidLib higher y is smaller */ return r.getBottomLeft().translate(0, -(r.getHeight() - 1)); case UP_RIGHT: /* -y because in SquidLib higher y is smaller */ return r.getBottomLeft().translate(r.getWidth() - 1, -(r.getHeight() - 1)); case NONE: return r.getCenter(); case DOWN: case LEFT: case RIGHT: case UP: final Coord c1 = getCorner(r, dir.clockwise()); final Coord c2 = getCorner(r, dir.counterClockwise()); return Coord.get((c1.x + c2.x) / 2, (c1.y + c2.y) / 2); } throw new IllegalStateException("Unmatched direction in Rectangle.Utils::getCorner: " + dir); }
influenced[cell.x][cell.y] = true; for (int d = 0; d < dirs.length; d++) { Coord adj = cell.translate(dirs[d].deltaX, dirs[d].deltaY); if (adj.x < 0 || adj.y < 0 || width <= adj.x || height <= adj.y)
influenced.insert(cell); for (int d = 0; d < dirs.length; d++) { Coord adj = cell.translate(dirs[d].deltaX, dirs[d].deltaY); if (adj.x < 0 || adj.y < 0 || width <= adj.x || height <= adj.y)