package dev.llan.model.board;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
public class Point implements Cloneable {
private static final int[][] neighborTranslations = {
{1, 0}, {1, -1}, {0, -1}, {-1, -1}, {-1, 0}, {-1, 1}, {0, 1}, {1, 1}
};
private static final double ROOT2 = 1.42;
public static double getDistance(Point a, Point b) {
double squaredSum = Math.pow((a.col - b.col), 2) + Math.pow((a.row - b.row), 2);
return Math.sqrt(squaredSum);
}
public static double getManhattanDistance(Point a, Point b) {
return Math.abs(a.col - b.col) + Math.abs(a.row - b.row);
}
private final int row;
private final int col;
public Point(int row, int col) {
this.row = row;
this.col = col;
}
public int getRow() {
return row;
}
public int getCol() {
return col;
}
public List<Point> findImmediateNeighbors(Grid grid) {
List<Point> neighbors = new ArrayList<>();
for (int[] translation : neighborTranslations) {
Point neighbor = new Point(this.row + translation[0], this.col + translation[1]);
if (grid.validPosition(neighbor)) {
neighbors.add(neighbor);
}
}
return neighbors;
}
public List<Point> findWithin(Grid grid, double radius, boolean includeEntities) {
List<Point> nearby = new ArrayList<>();
int maxDistance = (int) Math.ceil(radius);
for(int row = -maxDistance; row <= maxDistance; row++) {
for(int col = -maxDistance; col <= maxDistance; col++) {
if(row == 0 && col == 0) {
continue;
}
Point neighbor = new Point(this.row + row, this.col + col);
addIfNearbyPoint(grid, nearby, neighbor, radius, includeEntities);
}
}
return nearby;
}
private void addIfNearbyPoint(Grid grid, List<Point> nearby, Point neighbor, double radius, boolean includeEntities) {
boolean shouldAdd;
if(includeEntities) {
shouldAdd = grid.attackablePosition(neighbor);
} else {
shouldAdd = grid.validPosition(neighbor);
}
if(shouldAdd) {
double distance = Point.getDistance(this, neighbor);
if(distance <= radius) {
nearby.add(neighbor);
}
}
}
public List<Point> findClosestVacant(Grid grid) {
double radius = ROOT2;
List<Point> withinRadius = this.findWithin(grid, radius, false);
while (withinRadius.isEmpty()) {
radius += ROOT2;
withinRadius = this.findWithin(grid, radius, false);
}
return withinRadius;
}
public Point translate(int dRow, int dCol) {
return new Point(this.row + dRow, this.col + dCol);
}
@Override
public String toString() {
return "(" + row + "," + col + ")";
}
@Override
public boolean equals(Object o) {
if (o == null || getClass() != o.getClass()) return false;
Point point = (Point) o;
return row == point.row && col == point.col;
}
@Override
public int hashCode() {
return Objects.hash(row, col);
}
@Override
public Point clone() {
Point clone = new Point(this.row, this.col);
return clone;
}
}