-
-
Save Hadyn/7436c4a693554724bfd1 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import org.dreambot.api.methods.filter.Filter; | |
import org.dreambot.api.methods.map.Tile; | |
import org.dreambot.api.methods.skills.Skill; | |
import org.dreambot.api.methods.skills.Skills; | |
import org.dreambot.api.methods.walking.path.impl.LocalPath; | |
import org.dreambot.api.script.AbstractScript; | |
import org.dreambot.api.script.Category; | |
import org.dreambot.api.script.ScriptManifest; | |
import org.dreambot.api.wrappers.interactive.GameObject; | |
import java.util.*; | |
import java.util.function.Predicate; | |
import java.util.stream.Collectors; | |
import java.util.stream.Stream; | |
/** | |
* @author Hadyn Fitzgerald | |
*/ | |
@ScriptManifest(category = Category.WOODCUTTING, name = "eveWoodcutting", description = "", author = "sini", version = 1.0D) | |
public class EveWoodcutting extends AbstractScript { | |
/** | |
* The amount of frames drawn per second. This calculation always holds true for the logic of the game. | |
* However if the game experiences lag then this number will be lower for the amount of times the | |
* picture is drawn to the screen. | |
*/ | |
private static final int FPS = 50; | |
/** | |
* The names of all the tools. | |
*/ | |
private List<String> TOOL_NAMES = Arrays.asList("Bronze axe", "Iron axe", "Mithril axe", "Adamante axe", "Rune axe", "Dragon axe"); | |
/** | |
* The bank booth filter, the bank booth must obviously have the banking option and be on the same player plane. | |
*/ | |
private Filter<GameObject> bankBoothFilter = obj -> obj.getName().equals("Bank booth") && | |
obj.hasAction("Bank") && obj.getPlane() == getLocalPlayer().getZ(); | |
enum Tool { | |
BRONZE("Bronze axe", 1, 1), | |
IRON("Iron axe", 6, 5), | |
BLACK("Black axe", 11, 10), | |
MITHRIL("Mithril axe", 21, 20), | |
ADAMANTE("Adamate axe", 31, 30); | |
private String name; | |
private int woodcuttingLevel; | |
private int attackLevel; | |
Tool(String name, int woodcuttingLevel, int attackLevel) { | |
this.name = name; | |
this.woodcuttingLevel = woodcuttingLevel; | |
this.attackLevel = attackLevel; | |
} | |
/** | |
* Gets the name. | |
* | |
* @return the name. | |
*/ | |
public String getName() { | |
return name; | |
} | |
/** | |
* Gets the woodcutting level. | |
* | |
* @return the woodcutting level. | |
*/ | |
public int getWoodcuttingLevel() { | |
return woodcuttingLevel; | |
} | |
/** | |
* Gets the attack level. | |
* | |
* @return the attack level. | |
*/ | |
public int getAttackLevel() { | |
return attackLevel; | |
} | |
/** | |
* Gets the item name of all the tools. | |
* | |
* @return the names. | |
*/ | |
public static List<String> getNames() { | |
return Stream.of(values()).map(tool -> tool.getName()).collect(Collectors.toList()); | |
} | |
/** | |
* | |
* @param skills | |
* @return | |
*/ | |
public static List<Tool> getValidTools(Skills skills) { | |
return Stream.of(values()).filter(tool -> skills.getRealLevel(Skill.WOODCUTTING) >= tool.getWoodcuttingLevel()).collect(Collectors.toList()); | |
} | |
} | |
enum Tree { | |
WILLOW("Willow"); | |
/** | |
* | |
*/ | |
private String name; | |
/** | |
* | |
* @param name | |
*/ | |
Tree(String name) { | |
this.name = name; | |
} | |
/** | |
* | |
* @return | |
*/ | |
public String getName() { | |
return name; | |
} | |
} | |
/** | |
* A point cluster. | |
*/ | |
class Cluster { | |
/** | |
* The tiles in the cluster. | |
*/ | |
private List<Tile> points = new ArrayList<>(); | |
/** | |
* Adds a point to the cluster. | |
* | |
* @param point the point to add. | |
*/ | |
public void add(Tile point) { | |
points.add(point); | |
} | |
/** | |
* Gets the center of all of the points. | |
* | |
* @return the center. | |
*/ | |
public Tile getCenter() { | |
return new Tile(getWidth() / 2 + getMinimumX(), getLength() / 2 + getMinimumY()); | |
} | |
/** | |
* Gets the surface density of the points. | |
* | |
* @return the density. | |
*/ | |
public double getDensity() { | |
int area = getWidth() * getLength(); | |
return (double) size() / (double) area; | |
} | |
/** | |
* Gets the minimum x coordinate. | |
* | |
* @return the minimum x coordinate. | |
*/ | |
public int getMinimumX() { | |
return points.stream().mapToInt(obj -> obj.getX()).min().orElse(-1); | |
} | |
/** | |
* Gets the minimum y coordinate. | |
* | |
* @return the minimum y coordinate. | |
*/ | |
public int getMinimumY() { | |
return points.stream().mapToInt(obj -> obj.getY()).min().orElse(-1); | |
} | |
/** | |
* Gets the maximum x coordinate. | |
* | |
* @return the maximum x coordinate. | |
*/ | |
public int getMaximumX() { | |
return points.stream().mapToInt(obj -> obj.getX()).max().orElse(-1); | |
} | |
/** | |
* Gets the maximum y coordinate. | |
* | |
* @return the maximum y coordinate. | |
*/ | |
public int getMaximumY() { | |
return points.stream().mapToInt(obj -> obj.getY()).max().orElse(-1); | |
} | |
/** | |
* Gets the rectangular width of the cluster. | |
* | |
* @return the width. | |
*/ | |
public int getWidth() { | |
return (getMaximumX() - getMinimumX()) + 1; | |
} | |
/** | |
* Gets the rectangular length of the cluster. | |
* | |
* @return the length. | |
*/ | |
public int getLength() { | |
return (getMaximumY() - getMinimumY()) + 1; | |
} | |
/** | |
* Gets the points. | |
* | |
* @return the points. | |
*/ | |
public List<Tile> getPoints() { | |
return points; | |
} | |
/** | |
* Gets the size of the cluster. | |
* | |
* @return the size. | |
*/ | |
public int size() { | |
return points.size(); | |
} | |
} | |
/** | |
* An action. | |
*/ | |
interface Action { | |
/** | |
* Calls the action. | |
* | |
* @return if the action has completed. | |
*/ | |
boolean call(); | |
} | |
/** | |
* The current route to harvest materials. | |
*/ | |
class Route { | |
/** | |
* | |
*/ | |
Tree target; | |
/** | |
* The cluster of bank booths. | |
*/ | |
Cluster bankBoothCluster; | |
/** | |
* The resource clusters. | |
*/ | |
List<Cluster> resourceClusters; | |
/** | |
* | |
* @param bankBoothCluster | |
* @param resourceClusters | |
*/ | |
Route(Tree target, Cluster bankBoothCluster, List<Cluster> resourceClusters) { | |
this.target = target; | |
this.bankBoothCluster = bankBoothCluster; | |
this.resourceClusters = resourceClusters; | |
} | |
/** | |
* Gets if the player is nearby any of the bank booths. | |
* | |
* @param distance the distance to consider the player as nearby. | |
* @return if the player is nearby the bank booths. | |
*/ | |
public boolean isNearbyBankBooths(int distance) { | |
for(Tile tile : bankBoothCluster.getPoints()) { | |
if(getDistance(tile, getLocalPlayer().getTile()) < distance) { | |
return true; | |
} | |
} | |
return false; | |
} | |
/** | |
* Gets the closest available resource to the player. | |
* | |
* @return the closest available resource. | |
*/ | |
public Tile getClosestAvailableResource() { | |
// Select the closest point in the clusters | |
Tile point = resourceClusters.stream() | |
.flatMap(l -> l.getPoints().stream()) | |
.filter(p -> !hasObjectAtTile(p, obj -> obj.getName().equals("Tree Stump"))) | |
.min((tile, compare) -> Integer.compare(getDistance(getLocalPlayer().getTile(), tile), | |
getDistance(getLocalPlayer().getTile(), compare))).orElseGet(null); | |
return point; | |
} | |
/** | |
* Gets the closest path to the resource clusters. | |
* | |
* @return the path. | |
*/ | |
public LocalPath<Tile> getClosestPathToClusters() { | |
// Select the closest point in the clusters | |
Tile point = resourceClusters.stream().flatMap(l -> l.getPoints().stream()).min((tile, compare) -> | |
Integer.compare(getDistance(getLocalPlayer().getTile(), tile), | |
getDistance(getLocalPlayer().getTile(), compare))).get(); | |
// Calculate a path from the players current position to the closest cluster point | |
LocalPath<Tile> path = getWalking() | |
.getAStarPathFinder() | |
.calculate(getLocalPlayer().getTile(), point); | |
return path; | |
} | |
/** | |
* Gets a path to the bank booth. Selects a random bank booth to walk to. | |
* | |
* @return the path. | |
*/ | |
public LocalPath<Tile> getClosestPathToBankBooth() { | |
// Select the closest point in the cluster | |
List<Tile> points = bankBoothCluster.getPoints(); | |
Tile point = points.stream().min((tile, compare) -> | |
Integer.compare(getDistance(getLocalPlayer().getTile(), tile), | |
getDistance(getLocalPlayer().getTile(), compare))).get(); | |
// Calculate a path from the players current position to the bank booth | |
LocalPath<Tile> path = getWalking() | |
.getAStarPathFinder() | |
.calculate(getLocalPlayer().getTile(), point); | |
return path; | |
} | |
/** | |
* Gets a path to the bank booth. Selects a random bank booth to walk to. | |
* | |
* @return the path. | |
*/ | |
public LocalPath<Tile> getRandomPathToBankBooth() { | |
// Select a random point from the cluster | |
List<Tile> points = bankBoothCluster.getPoints(); | |
int index = (int) (Math.random() * points.size()); | |
Tile point = points.get(index); | |
// Calculate a path from the players current position to the bank booth | |
LocalPath<Tile> path = getWalking() | |
.getAStarPathFinder() | |
.calculate(getLocalPlayer().getTile(), point); | |
return path; | |
} | |
/** | |
* | |
* @return | |
*/ | |
public String getResourceTargetName() { | |
return target.getName(); | |
} | |
} | |
/** | |
* Walk a path. | |
*/ | |
class WalkPathAction implements Action { | |
/** | |
* The distance threshold to queue the next step. | |
*/ | |
static final int NEXT_STEP_THRESHOLD = 3; | |
/** | |
* The distance threshold to find the next step, however we should randomize this a bit. The mini-map | |
* shows tiles visible up to 32 tiles, 16 from the player, away. This however of course is circular, | |
* so the rectangular edges aren't visible. Should do a better case of this. | |
*/ | |
static final int MINI_MAP_THRESHOLD = 8; | |
/** | |
* The path to walk. | |
*/ | |
LocalPath<Tile> path; | |
/** | |
* The current step in the path. | |
*/ | |
int currentStep = -1; | |
/** | |
* Constructs a new {@link WalkPathAction}; | |
* | |
* @param path the path to walk. | |
*/ | |
WalkPathAction(LocalPath<Tile> path) { | |
this.path = path; | |
} | |
@Override | |
public boolean call() { | |
// If we reached the destination then we are done! | |
if(reachedDestination()) { | |
return true; | |
} | |
// Check if we need to walk the next step in the route | |
if(currentStep == -1 || currentStep != path.size() - 1 && getDistance(path.get(currentStep), getLocalPlayer().getTile()) < NEXT_STEP_THRESHOLD) { | |
currentStep = selectNextTile(currentStep, MINI_MAP_THRESHOLD); | |
// Walk the next step if we need to, if we cannot click the tile on the minimap then we can't really do | |
// much this is more or less a logic error. | |
if(!getWalking().clickTileOnMinimap(path.get(currentStep))) { | |
throw new IllegalStateException("Could not click next tile on minimap! PANIC"); | |
} | |
} | |
return false; | |
} | |
/** | |
* Gets the next tile in the path closest to the limit. | |
* | |
* @param current the current step. | |
* @param limit the distance limit in tiles. | |
* @return the index of the tile. | |
*/ | |
private int selectNextTile(int current, int limit) { | |
for(int i = path.size() - 1; i >= current; i--) { | |
if(getDistance(getLocalPlayer().getTile(), path.get(i)) < limit) { | |
return i; | |
} | |
} | |
throw new IllegalStateException("Panic! Could not find a valid tile"); | |
} | |
/** | |
* Gets if we reached the destination. | |
* | |
* @return if we reached the destination. | |
*/ | |
private boolean reachedDestination() { | |
if(path.size() < 1) return true; | |
Tile destination = path.get(path.size() - 1); | |
return getDistance(getLocalPlayer().getTile(), destination) <= 1; | |
} | |
} | |
/** | |
* Determines the best route to harvest local materials. | |
*/ | |
class DetermineRouteAction implements Action { | |
/** | |
* The target tree name. | |
*/ | |
Tree target; | |
/** | |
* Constructs a new {@link DetermineRouteAction} | |
* | |
* @param tree the target tree. | |
*/ | |
DetermineRouteAction(Tree tree) { | |
this.target = tree; | |
} | |
@Override | |
public boolean call() { | |
// Find all of the bank booths within the scene | |
log("Detecting any nearby bank booths"); | |
List<GameObject> bankBooths = getGameObjects().all(bankBoothFilter); | |
// Check if we found any valid bank booths | |
if(bankBooths.size() < 1) { | |
log("Fatal exception when attempting to determine route! Cannot find any nearby bank booths"); | |
stop(); | |
return false; | |
} | |
// Find clusters of bank booths, however this will be rare to find more than one | |
List<Cluster> bankBoothClusters = getClusters(bankBooths, 3, 20); | |
// Find all the nearby trees | |
log("Detecting nearby trees [target=" + target + "]"); | |
List<GameObject> trees = getTrees(target.getName()); | |
// Check to see if we have any nearby trees | |
if(trees.size() < 1) { | |
log("Fatal exception when attempting to determine route! Cannot find any nearby target trees"); | |
stop(); | |
return false; | |
} | |
// Find clusters of trees | |
List<Cluster> treeClusters = getClusters(trees, 5, 30); | |
// Find the closest bank and tree cluster | |
int suitableBankClusterId = -1, suitableTreeClusterId = -1; | |
// f(...) = len - (density * size) * coeff | |
double lowestScore = Double.MAX_VALUE; | |
for(int i = 0; i < bankBoothClusters.size(); i++) { | |
Cluster bankBoothCluster = bankBoothClusters.get(i); | |
for(int j = 0; j < treeClusters.size(); j++) { | |
Cluster treeCluster = treeClusters.get(j); | |
int distance = getDistance(treeCluster.getCenter(), bankBoothCluster.getCenter()); | |
double score = (double) distance - (treeCluster.getDensity() * treeCluster.size()) * 1.0D; | |
if(score < lowestScore) { | |
suitableBankClusterId = i; | |
suitableTreeClusterId = j; | |
lowestScore = score; | |
} | |
} | |
} | |
// This case shouldn't happen but just as a precaution | |
if(suitableBankClusterId == -1 || suitableTreeClusterId == -1) { | |
throw new IllegalStateException("No suitable tree or bank cluster found, panic!"); | |
} | |
Cluster bankBoothCluster = bankBoothClusters.get(suitableBankClusterId); | |
Cluster treeCluster = treeClusters.get(suitableTreeClusterId); | |
// Find any nearby clusters to the original cluster, up to a certain distance | |
List<Cluster> suitableTreeClusters = new ArrayList<>(); | |
suitableTreeClusters.add(treeCluster); | |
for(int i = 0; i < treeClusters.size(); i++) { | |
// Skip over the suitable tree cluster | |
if(i == suitableTreeClusterId) { | |
continue; | |
} | |
Cluster cluster = treeClusters.get(i); | |
for(Tile tile : cluster.getPoints()) { | |
for(Tile compare : treeCluster.getPoints()) { | |
// If the distance between one of the points in the cluster is less | |
// than the limit we can safely assume that we can also use that cluster to chop trees from | |
if (getDistance(tile, compare) < 10) { | |
suitableTreeClusters.add(cluster); | |
break; | |
} | |
} | |
} | |
} | |
route = new Route(target, bankBoothCluster, suitableTreeClusters); | |
queueAction(startAction); | |
return true; | |
} | |
} | |
/** | |
* Equips a tool. | |
*/ | |
class EquipToolAction implements Action { | |
/** | |
* The tool to equip. | |
*/ | |
Tool tool; | |
EquipToolAction(Tool tool) { | |
this.tool = tool; | |
} | |
@Override | |
public boolean call() { | |
// Check if the tool is the inventory, if so then equip it | |
if(getInventory().contains(tool.getName())) { | |
getInventory().interact(tool.getName(), "Wield"); | |
} | |
return getEquipment().contains(tool.getName()); | |
} | |
} | |
/** | |
* Grabs the optimal tool from the bank. | |
*/ | |
class GrabToolAction implements Action { | |
/** | |
* The tool to grab from the bank. | |
*/ | |
Tool tool; | |
@Override | |
public boolean call() { | |
// Open the bank | |
getBank().open(); | |
if(tool == null) { | |
// Check if the bank has any of the valid tools for the players woodcutting level | |
List<Tool> validTools = Tool.getValidTools(getSkills()); | |
List<String> toolNames = validTools.stream().map(tool -> tool.getName()).collect(Collectors.toList()); | |
boolean validTool = getBank().contains(item -> toolNames.contains(item.getName())); | |
if (!validTool) { | |
log("You do not have a valid tool which we can withdraw from the bank! Either your level is too low, or you do not have any"); | |
stop(); | |
return false; | |
} | |
// Sort tools by their descending level and if they exist in the bank | |
PriorityQueue<Tool> priority = new PriorityQueue<>((first, second) -> Integer.compare(first.getWoodcuttingLevel(), second.getWoodcuttingLevel())); | |
priority.addAll(validTools.stream().filter(tool -> getBank().contains(tool.getName())).collect(Collectors.toList())); | |
tool = priority.poll(); | |
// Edge case, should not happen but just in case | |
if (tool == null) { | |
throw new IllegalArgumentException("Panic! Could not find tool"); | |
} | |
} | |
// Attempt to deposit all the items in the inventory | |
if (!getInventory().isEmpty()) { | |
getBank().depositAllItems(); | |
} | |
// Withdraw the tool from the bank, first scroll to it however | |
if(!getBank().isSlotVisible(getBank().get(tool.getName()))) { | |
getBank().scroll(tool.getName()); | |
} | |
// Withdraw the tool from the bank | |
getBank().withdraw(tool.getName()); | |
// We are done once the inventory contains the tool | |
if (!getInventory().contains(tool.getName())) { | |
return false; | |
} | |
// Close the bank | |
getBank().close(); | |
queueAction(startAction); | |
return true; | |
} | |
} | |
class SearchClustersAction implements Action { | |
@Override | |
public boolean call() { | |
// Search for the closest available resource | |
Tile tile = route.getClosestAvailableResource(); | |
if(tile == null) return false; | |
// Get the game object at the tile for the route target | |
GameObject gameObject = getObjectAtTile(tile, obj -> obj.getName().equals(route.getResourceTargetName())); | |
if(gameObject == null) return false; | |
// Calculate a path to the target if its out of our range | |
if(getDistance(getLocalPlayer().getTile(), tile) > 5) { | |
queueAction(new WalkPathAction(getWalking() | |
.getAStarPathFinder() | |
.calculate(getLocalPlayer().getTile(), tile))); | |
} | |
queueAction(new CollectFromResourceAction(gameObject)); | |
return true; | |
} | |
} | |
class CollectFromResourceAction implements Action { | |
private GameObject resource; | |
CollectFromResourceAction(GameObject resource) { | |
this.resource = resource; | |
} | |
@Override | |
public boolean call() { | |
if(getInventory().isFull()) { | |
queueAction(new WalkPathAction(route.getRandomPathToBankBooth())); | |
queueAction(new DepositItemsAction()); | |
queueAction(startAction); | |
return true; | |
} | |
if(hasObjectAtTile(resource.getTile(), obj -> obj.getName().equals("Tree Stump"))) { | |
queueAction(new SearchClustersAction()); | |
return true; | |
} | |
// Just assume that since the player isn't animated that we need to interact with the resource x) | |
if(!getLocalPlayer().isAnimating()) { | |
getCamera().rotateToEntity(resource); | |
resource.interact("Chop down"); | |
} | |
return false; | |
} | |
} | |
class DepositItemsAction implements Action { | |
@Override | |
public boolean call() { | |
// Open the bank | |
getBank().open(); | |
// Deposit all of the items except for the tools we may be using | |
List<String> toolNames = Tool.getNames(); | |
getBank().depositAllExcept(item -> toolNames.contains(item.getName())); | |
// Close the bank | |
getBank().close(); | |
return true; | |
} | |
} | |
/** | |
* The action queue. | |
*/ | |
private Queue<Action> actionQueue = new ArrayDeque<>(); | |
/** | |
* The delay in ticks for the next action to be called. | |
*/ | |
private int delay = -1; | |
/** | |
* The current loop cycle. | |
*/ | |
private int loopCycle = 0; | |
/** | |
* The current route. | |
*/ | |
private Route route; | |
/** | |
* The starting action. Performs the check to see if the player has the required tool to continue, | |
* if not then queues actions to grab the tool and move to the closest area to start collecting resources. | |
*/ | |
Action startAction = () -> { | |
if(!hasValidTool()) { | |
log("Your character does not have the required tool to start this script, routing to nearest bank booth"); | |
// Check if the player is nearby the bank booths, if not then we can just assume to route to the closest bank booth | |
if(!route.isNearbyBankBooths(5)) { | |
queueAction(new WalkPathAction(route.getClosestPathToBankBooth())); | |
} | |
queueAction(new GrabToolAction()); | |
return true; | |
} | |
// Equip the optimal tool if possible | |
Tool tool = getOptimalTool(); | |
if(tool != null) { | |
// Check if we can equip the item | |
if (getSkills().getRealLevel(Skill.ATTACK) >= tool.getAttackLevel()) { | |
queueAction(new EquipToolAction(tool)); | |
} | |
} | |
// Walk the closest path to the clusters | |
queueAction(new WalkPathAction(route.getClosestPathToClusters())); | |
queueAction(new SearchClustersAction()); | |
return true; | |
}; | |
@Override | |
public void onStart() { | |
// Queue the action to determine the route | |
queueAction(new DetermineRouteAction(Tree.WILLOW)); | |
} | |
@Override | |
public int onLoop() { | |
loopCycle++; | |
// Execute every tick, or what we'd consider a tick its in the time frame of a tick | |
if((loopCycle % 30) == 0) { | |
if (delay <= 0) { | |
if(!actionQueue.isEmpty()) { | |
do { | |
// Call the current action in the action queue, if the action | |
// is finished poll it from the queue | |
Action action = actionQueue.peek(); | |
if (action.call()) actionQueue.poll(); | |
else break; | |
} while(true); | |
} else { | |
log("Panic! There are currently no pending actions"); | |
} | |
} else { | |
delay--; | |
} | |
} | |
// Wait the amount of time between loop cycles | |
int delta = 1000 / FPS; | |
return delta; | |
} | |
/*** | |
* Queues an action for execution. | |
* | |
* @param action the action. | |
*/ | |
private void queueAction(Action action) { | |
actionQueue.add(action); | |
} | |
/** | |
* Gets the optimal tool to use from the inventory. | |
* | |
* @return the optimal tool. | |
*/ | |
private Tool getOptimalTool() { | |
List<Tool> validTools = Tool.getValidTools(getSkills()); | |
// Sort tools by their descending level and if they exist in the equipment or inventory | |
PriorityQueue<Tool> priority = new PriorityQueue<>((first, second) -> Integer.compare(first.getWoodcuttingLevel(), second.getWoodcuttingLevel())); | |
priority.addAll(validTools.stream().filter(tool -> getInventory().contains(tool.getName()) || getEquipment().contains(tool.getName())).collect(Collectors.toList())); | |
return priority.poll(); | |
} | |
/** | |
* Gets if the player has a valid tool fir their level. | |
* | |
* @return if the player has a valid tool in either their equipment or inventory. | |
*/ | |
private boolean hasValidTool() { | |
List<Tool> validTools = Tool.getValidTools(getSkills()); | |
List<String> toolNames = validTools.stream().map(tool -> tool.getName()).collect(Collectors.toList()); | |
return getEquipment().contains(item -> toolNames.contains(item.getName())) || getInventory().contains(item -> toolNames.contains(item.getName())); | |
} | |
/** | |
* Gets all the trees by a certain name. | |
* | |
* @param name the name of the tree. | |
* @return the list of trees. | |
*/ | |
private List<GameObject> getTrees(String name) { | |
return getGameObjects().all(obj -> name.equals(obj.getName()) && obj.hasAction("Chop down")); | |
} | |
/** | |
* Gets if an object exists at a tile with the specified filter. | |
* | |
* @param tile the tile. | |
* @param predicate the game object predicate. | |
* @return if the object exists at the tile for the specified filter. | |
*/ | |
private boolean hasObjectAtTile(Tile tile, Predicate<GameObject> predicate) { | |
return Stream.of(getGameObjects().getObjectsOnTile(tile)).anyMatch(obj -> predicate.test(obj)); | |
} | |
/** | |
* | |
* @param tile | |
* @param predicate | |
* @return | |
*/ | |
private GameObject getObjectAtTile(Tile tile, Predicate<GameObject> predicate) { | |
return Stream.of(getGameObjects().getObjectsOnTile(tile)).filter(obj -> predicate.test(obj)).findFirst().orElse(null); | |
} | |
/** | |
* Gets the amount of accessible trees for a cluster. | |
* | |
* @param cluster the cluster of points to check. | |
* @return the number of accessable trees. | |
*/ | |
private int getAccessibleTrees(Cluster cluster) { | |
return (int) cluster.getPoints().stream().map(point -> !hasObjectAtTile(point, obj -> obj.getName().equals("Tree Stump"))).count(); | |
} | |
/** | |
* Gets the rectangular distance between two tiles. | |
* | |
* @param first the first tile. | |
* @param second the second tile. | |
* @return the distance in tiles. | |
*/ | |
private int getDistance(Tile first, Tile second) { | |
return getDistance(first.getX(), first.getY(), second.getX(), second.getY()); | |
} | |
/** | |
* Gets the rectangular distance between two points. | |
* | |
* @param x0 the first x coordinate. | |
* @param y0 the first y coordinate. | |
* @param x1 the second x coordinate. | |
* @param y1 the second y coordinate. | |
* @return the distance in tiles. | |
*/ | |
private int getDistance(int x0, int y0, int x1, int y1) { | |
return Math.max(Math.abs(x1 - x0), Math.abs(y1 - y0)); | |
} | |
/** | |
* Creates a list of point clusters from game objects. | |
* | |
* @param objects the objects to create the clusters from. | |
* @param distanceLimit the distance limit of each cluster. | |
* @param sizeLimit the size limit of each cluster. | |
* @return the clusters. | |
*/ | |
private List<Cluster> getClusters(List<GameObject> objects, int distanceLimit, int sizeLimit) { | |
List<Cluster> clusters = new ArrayList<>(); | |
List<GameObject> copy = new ArrayList<>(objects); | |
while (!copy.isEmpty()) { | |
// Remove the first element of the list to create a new cluster from | |
Cluster cluster = new Cluster(); | |
GameObject first = copy.remove(0); | |
cluster.add(first.getTile()); | |
Iterator<GameObject> iterator = copy.iterator(); | |
while (iterator.hasNext()) { | |
GameObject object = iterator.next(); | |
for(Tile compare : cluster.getPoints()) { | |
// Check to see if the object is within the threshold distance | |
int distance = getDistance(compare.getX(), compare.getY(), object.getX(), object.getY()); | |
if(distance <= distanceLimit) { | |
cluster.add(object.getTile()); | |
iterator.remove(); | |
break; | |
} | |
} | |
// If we pass the threshold size then move on to start a new cluster | |
if(cluster.size() >= sizeLimit) { | |
break; | |
} | |
} | |
clusters.add(cluster); | |
} | |
return clusters; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment