mourning-ember / src / main / java / dev / llan / model / board / Point.java
Point.java
Raw
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;
  }
}