Make the AI more robust
Signed-off-by: Chris Cromer <chris@cromer.cl>
This commit is contained in:
parent
fb7c7ec227
commit
8c627bda8c
@ -318,7 +318,7 @@ public class Canvas extends java.awt.Canvas implements Constants {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (Key key : keys) {
|
for (Key key : keys) {
|
||||||
player.getAi().addDestination(new State(key.getCell().getX(), key.getCell().getY(), State.Type.KEY, null, 2));
|
player.getAi().addDestination(new State(key.getCell().getX(), key.getCell().getY(), State.Type.KEY, null, 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
player.getAi().sortDestinations();
|
player.getAi().sortDestinations();
|
||||||
|
@ -60,6 +60,7 @@ public class Scene extends JComponent implements Constants {
|
|||||||
* The cells of the game
|
* The cells of the game
|
||||||
*/
|
*/
|
||||||
private final Cell[][] cells;
|
private final Cell[][] cells;
|
||||||
|
//private final CopyOnWriteArrayList<CopyOnWriteArrayList<Cell>> cells;
|
||||||
/**
|
/**
|
||||||
* The logger
|
* The logger
|
||||||
*/
|
*/
|
||||||
|
@ -76,6 +76,17 @@ public class AI implements Runnable {
|
|||||||
throw new AIException("The addDestination method should be run by the child only!");
|
throw new AIException("The addDestination method should be run by the child only!");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove the picked up key from destinations if it is there
|
||||||
|
*
|
||||||
|
* @param x The x coordinate of the key
|
||||||
|
* @param y The y coordinate of the key
|
||||||
|
* @throws AIException Thrown when the parent method is called directly
|
||||||
|
*/
|
||||||
|
public void removeKeyDestination(int x, int y) throws AIException {
|
||||||
|
throw new AIException("The addDestination method should be run by the child only!");
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sort the destinations
|
* Sort the destinations
|
||||||
*
|
*
|
||||||
|
@ -129,10 +129,14 @@ public interface PlayerAI extends Runnable, Constants {
|
|||||||
if (player.getAnimation().getCurrentDirection() != Animation.Direction.UP) {
|
if (player.getAnimation().getCurrentDirection() != Animation.Direction.UP) {
|
||||||
player.keyPressed(KeyEvent.VK_UP);
|
player.keyPressed(KeyEvent.VK_UP);
|
||||||
}
|
}
|
||||||
player.interact();
|
boolean portalWasActive = false;
|
||||||
Portal portal = scene.getCanvas().getPortal();
|
Portal portal = scene.getCanvas().getPortal();
|
||||||
if (portal.getState() == Portal.State.ACTIVE) {
|
if (portal.getState() == Portal.State.ACTIVE) {
|
||||||
addDestination(new State(portal.getCell().getX(), portal.getCell().getY(), State.Type.PORTAL, null, 2));
|
portalWasActive = true;
|
||||||
|
}
|
||||||
|
player.interact();
|
||||||
|
if (!portalWasActive) {
|
||||||
|
addDestination(new State(portal.getCell().getX(), portal.getCell().getY(), State.Type.PORTAL, null, 1));
|
||||||
}
|
}
|
||||||
sortDestinations();
|
sortDestinations();
|
||||||
return true;
|
return true;
|
||||||
@ -213,6 +217,12 @@ public interface PlayerAI extends Runnable, Constants {
|
|||||||
if (player.getCell().getY() < VERTICAL_CELLS - 1 && scene.getCells()[player.getCell().getX()][player.getCell().getY() + 1].getObject() == null) {
|
if (player.getCell().getY() < VERTICAL_CELLS - 1 && scene.getCells()[player.getCell().getX()][player.getCell().getY() + 1].getObject() == null) {
|
||||||
openSpaces.add(State.Type.DOWN);
|
openSpaces.add(State.Type.DOWN);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (openSpaces.size() == 0) {
|
||||||
|
// The player can't move
|
||||||
|
return State.Type.EXIT;
|
||||||
|
}
|
||||||
|
|
||||||
int random = random(0, openSpaces.size() - 1);
|
int random = random(0, openSpaces.size() - 1);
|
||||||
return openSpaces.get(random);
|
return openSpaces.get(random);
|
||||||
}
|
}
|
||||||
|
@ -26,6 +26,7 @@ import java.util.List;
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.PriorityQueue;
|
import java.util.PriorityQueue;
|
||||||
import java.util.Queue;
|
import java.util.Queue;
|
||||||
|
import java.util.concurrent.CopyOnWriteArrayList;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The class implements the A* search AI algorithm for the player
|
* The class implements the A* search AI algorithm for the player
|
||||||
@ -58,7 +59,7 @@ public class PlayerAStarAI extends AI implements PlayerAI, Constants {
|
|||||||
/**
|
/**
|
||||||
* The destinations the player needs to visit
|
* The destinations the player needs to visit
|
||||||
*/
|
*/
|
||||||
private List<State> destinations = new ArrayList<>();
|
private List<State> destinations = new CopyOnWriteArrayList<>();
|
||||||
/**
|
/**
|
||||||
* The objective that was found
|
* The objective that was found
|
||||||
*/
|
*/
|
||||||
@ -95,7 +96,7 @@ public class PlayerAStarAI extends AI implements PlayerAI, Constants {
|
|||||||
cameFrom.put(start, start);
|
cameFrom.put(start, start);
|
||||||
costSoFar.put(start, 0.0);
|
costSoFar.put(start, 0.0);
|
||||||
|
|
||||||
while (frontier.size() > 0 && cameFrom.size() <= (HORIZONTAL_CELLS * VERTICAL_CELLS) * 2) {
|
while (frontier.size() > 0 && cameFrom.size() <= (HORIZONTAL_CELLS * VERTICAL_CELLS) * 5) {
|
||||||
State current = frontier.poll();
|
State current = frontier.poll();
|
||||||
|
|
||||||
if (current.equals(goal)) {
|
if (current.equals(goal)) {
|
||||||
@ -200,52 +201,155 @@ public class PlayerAStarAI extends AI implements PlayerAI, Constants {
|
|||||||
private double getCost(State state) {
|
private double getCost(State state) {
|
||||||
// The cost increases based on how close the enemy is
|
// The cost increases based on how close the enemy is
|
||||||
/*
|
/*
|
||||||
2
|
22222
|
||||||
444
|
24442
|
||||||
24842
|
24842
|
||||||
444
|
24442
|
||||||
2
|
22222
|
||||||
*/
|
*/
|
||||||
if (state.getOperation() == State.Type.ENEMY) {
|
|
||||||
return 8;
|
EnemyCost enemyCost = EnemyCost.DIRECT_CORNERS;
|
||||||
|
|
||||||
|
if (enemyCost.getLevel() == EnemyCost.NONE.getLevel()) {
|
||||||
|
return EnemyCost.NONE.getCost();
|
||||||
}
|
}
|
||||||
else if (state.getX() > 0 && scene.getCells()[state.getX() - 1][state.getY()].getObject() instanceof Enemy) {
|
|
||||||
return 4;
|
if (enemyCost.getLevel() >= EnemyCost.DIRECT.getLevel()) {
|
||||||
|
// The enemy
|
||||||
|
if (scene.getCells()[state.getX()][state.getY()].getObject() instanceof Enemy) {
|
||||||
|
return EnemyCost.DIRECT.getCost();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (enemyCost.getLevel() >= EnemyCost.DIRECT_SIDES.getLevel()) {
|
||||||
|
// Left
|
||||||
|
if (state.getX() > 0 && scene.getCells()[state.getX() - 1][state.getY()].getObject() instanceof Enemy) {
|
||||||
|
return EnemyCost.DIRECT_SIDES.getCost();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Right
|
||||||
else if (state.getX() < HORIZONTAL_CELLS - 1 && scene.getCells()[state.getX() + 1][state.getY()].getObject() instanceof Enemy) {
|
else if (state.getX() < HORIZONTAL_CELLS - 1 && scene.getCells()[state.getX() + 1][state.getY()].getObject() instanceof Enemy) {
|
||||||
return 4;
|
return EnemyCost.DIRECT_SIDES.getCost();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Up
|
||||||
else if (state.getY() > 0 && scene.getCells()[state.getX()][state.getY() - 1].getObject() instanceof Enemy) {
|
else if (state.getY() > 0 && scene.getCells()[state.getX()][state.getY() - 1].getObject() instanceof Enemy) {
|
||||||
return 4;
|
return EnemyCost.DIRECT_SIDES.getCost();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Down
|
||||||
else if (state.getY() < VERTICAL_CELLS - 1 && scene.getCells()[state.getX()][state.getY() + 1].getObject() instanceof Enemy) {
|
else if (state.getY() < VERTICAL_CELLS - 1 && scene.getCells()[state.getX()][state.getY() + 1].getObject() instanceof Enemy) {
|
||||||
return 4;
|
return EnemyCost.DIRECT_SIDES.getCost();
|
||||||
}
|
}
|
||||||
else if (state.getX() > 1 && scene.getCells()[state.getX() - 2][state.getY()].getObject() instanceof Enemy) {
|
|
||||||
return 2;
|
|
||||||
}
|
}
|
||||||
else if (state.getX() < HORIZONTAL_CELLS - 2 && scene.getCells()[state.getX() + 2][state.getY()].getObject() instanceof Enemy) {
|
|
||||||
return 2;
|
if (enemyCost.getLevel() >= EnemyCost.DIRECT_CORNERS.getLevel()) {
|
||||||
}
|
// Upper left corner
|
||||||
else if (state.getY() > 1 && scene.getCells()[state.getX()][state.getY() - 2].getObject() instanceof Enemy) {
|
if (state.getX() > 0 && state.getY() > 0 && scene.getCells()[state.getX() - 1][state.getY() - 1].getObject() instanceof Enemy) {
|
||||||
return 2;
|
return EnemyCost.DIRECT_CORNERS.getCost();
|
||||||
}
|
|
||||||
else if (state.getY() < VERTICAL_CELLS - 2 && scene.getCells()[state.getX()][state.getY() + 2].getObject() instanceof Enemy) {
|
|
||||||
return 2;
|
|
||||||
}
|
|
||||||
else if (state.getX() > 0 && state.getY() > 0 && scene.getCells()[state.getX() - 1][state.getY() - 1].getObject() instanceof Enemy) {
|
|
||||||
return 4;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Upper right corner
|
||||||
else if (state.getX() < HORIZONTAL_CELLS - 1 && state.getY() > 0 && scene.getCells()[state.getX() + 1][state.getY() - 1].getObject() instanceof Enemy) {
|
else if (state.getX() < HORIZONTAL_CELLS - 1 && state.getY() > 0 && scene.getCells()[state.getX() + 1][state.getY() - 1].getObject() instanceof Enemy) {
|
||||||
return 4;
|
return EnemyCost.DIRECT_CORNERS.getCost();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Lower left corner
|
||||||
else if (state.getX() > 0 && state.getY() < VERTICAL_CELLS - 1 && scene.getCells()[state.getX() - 1][state.getY() + 1].getObject() instanceof Enemy) {
|
else if (state.getX() > 0 && state.getY() < VERTICAL_CELLS - 1 && scene.getCells()[state.getX() - 1][state.getY() + 1].getObject() instanceof Enemy) {
|
||||||
return 4;
|
return EnemyCost.DIRECT_CORNERS.getCost();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Lower right corner
|
||||||
else if (state.getX() < HORIZONTAL_CELLS - 1 && state.getY() < VERTICAL_CELLS - 1 && scene.getCells()[state.getX() + 1][state.getY() + 1].getObject() instanceof Enemy) {
|
else if (state.getX() < HORIZONTAL_CELLS - 1 && state.getY() < VERTICAL_CELLS - 1 && scene.getCells()[state.getX() + 1][state.getY() + 1].getObject() instanceof Enemy) {
|
||||||
return 4;
|
return EnemyCost.DIRECT_CORNERS.getCost();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (enemyCost.getLevel() >= EnemyCost.FAR_SIDES.getLevel()) {
|
||||||
|
// Left
|
||||||
|
if (state.getX() > 1 && scene.getCells()[state.getX() - 2][state.getY()].getObject() instanceof Enemy) {
|
||||||
|
return EnemyCost.FAR_SIDES.getCost();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Right
|
||||||
|
else if (state.getX() < HORIZONTAL_CELLS - 2 && scene.getCells()[state.getX() + 2][state.getY()].getObject() instanceof Enemy) {
|
||||||
|
return EnemyCost.FAR_SIDES.getCost();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Up
|
||||||
|
else if (state.getY() > 1 && scene.getCells()[state.getX()][state.getY() - 2].getObject() instanceof Enemy) {
|
||||||
|
return EnemyCost.FAR_SIDES.getCost();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Down
|
||||||
|
else if (state.getY() < VERTICAL_CELLS - 2 && scene.getCells()[state.getX()][state.getY() + 2].getObject() instanceof Enemy) {
|
||||||
|
return EnemyCost.FAR_SIDES.getCost();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (enemyCost.getLevel() >= EnemyCost.FAR_CORNERS.getLevel()) {
|
||||||
|
// Upper left corner
|
||||||
|
if (state.getX() > 1 && state.getY() > 0 && scene.getCells()[state.getX() - 2][state.getY() - 1].getObject() instanceof Enemy) {
|
||||||
|
return EnemyCost.FAR_CORNERS.getCost();
|
||||||
|
}
|
||||||
|
else if (state.getX() > 1 && state.getY() > 1 && scene.getCells()[state.getX() - 2][state.getY() - 2].getObject() instanceof Enemy) {
|
||||||
|
return EnemyCost.FAR_CORNERS.getCost();
|
||||||
|
}
|
||||||
|
else if (state.getX() > 0 && state.getY() > 1 && scene.getCells()[state.getX() - 1][state.getY() - 2].getObject() instanceof Enemy) {
|
||||||
|
return EnemyCost.FAR_CORNERS.getCost();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Upper right corner
|
||||||
|
else if (state.getX() < HORIZONTAL_CELLS - 2 && state.getY() > 0 && scene.getCells()[state.getX() + 2][state.getY() - 1].getObject() instanceof Enemy) {
|
||||||
|
return EnemyCost.FAR_CORNERS.getCost();
|
||||||
|
}
|
||||||
|
else if (state.getX() < HORIZONTAL_CELLS - 2 && state.getY() > 1 && scene.getCells()[state.getX() + 2][state.getY() - 2].getObject() instanceof Enemy) {
|
||||||
|
return EnemyCost.FAR_CORNERS.getCost();
|
||||||
|
}
|
||||||
|
else if (state.getX() < HORIZONTAL_CELLS - 1 && state.getY() > 1 && scene.getCells()[state.getX() + 1][state.getY() - 2].getObject() instanceof Enemy) {
|
||||||
|
return EnemyCost.FAR_CORNERS.getCost();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Lower left corner
|
||||||
|
else if (state.getX() > 1 && state.getY() < VERTICAL_CELLS - 1 && scene.getCells()[state.getX() - 2][state.getY() + 1].getObject() instanceof Enemy) {
|
||||||
|
return EnemyCost.FAR_CORNERS.getCost();
|
||||||
|
}
|
||||||
|
else if (state.getX() > 1 && state.getY() < VERTICAL_CELLS - 2 && scene.getCells()[state.getX() - 2][state.getY() + 2].getObject() instanceof Enemy) {
|
||||||
|
return EnemyCost.FAR_CORNERS.getCost();
|
||||||
|
}
|
||||||
|
else if (state.getX() > 0 && state.getY() < VERTICAL_CELLS - 2 && scene.getCells()[state.getX() - 1][state.getY() + 2].getObject() instanceof Enemy) {
|
||||||
|
return EnemyCost.FAR_CORNERS.getCost();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Lower right corner
|
||||||
|
else if (state.getX() < HORIZONTAL_CELLS - 2 && state.getY() < VERTICAL_CELLS - 1 && scene.getCells()[state.getX() + 2][state.getY() + 1].getObject() instanceof Enemy) {
|
||||||
|
return EnemyCost.FAR_CORNERS.getCost();
|
||||||
|
}
|
||||||
|
else if (state.getX() < HORIZONTAL_CELLS - 2 && state.getY() < VERTICAL_CELLS - 2 && scene.getCells()[state.getX() + 2][state.getY() + 2].getObject() instanceof Enemy) {
|
||||||
|
return EnemyCost.FAR_CORNERS.getCost();
|
||||||
|
}
|
||||||
|
else if (state.getX() < HORIZONTAL_CELLS - 1 && state.getY() < VERTICAL_CELLS - 2 && scene.getCells()[state.getX() + 1][state.getY() + 2].getObject() instanceof Enemy) {
|
||||||
|
return EnemyCost.FAR_CORNERS.getCost();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return EnemyCost.NONE.getCost();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove the picked up key from destinations if it is there
|
||||||
|
*
|
||||||
|
* @param x The x coordinate of the key
|
||||||
|
* @param y The y coordinate of the key
|
||||||
|
*/
|
||||||
|
public void removeKeyDestination(int x, int y) {
|
||||||
|
for (State state : destinations) {
|
||||||
|
if (state.getOperation() == State.Type.KEY && state.getX() == x && state.getY() == y) {
|
||||||
|
destinations.remove(state);
|
||||||
|
sortDestinations();
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -257,37 +361,6 @@ public class PlayerAStarAI extends AI implements PlayerAI, Constants {
|
|||||||
destinations.add(destination);
|
destinations.add(destination);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Calculate the route from the objective to the player
|
|
||||||
*/
|
|
||||||
private void calculateRoute() {
|
|
||||||
getLogger().info("Calculate the route!");
|
|
||||||
State predecessor = foundObjective;
|
|
||||||
do {
|
|
||||||
steps.add(0, predecessor.getOperation());
|
|
||||||
predecessor = predecessor.getPredecessor();
|
|
||||||
}
|
|
||||||
while (predecessor != null);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sort the destinations by importance, if the importance is the same then sort them by distance
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public void sortDestinations() {
|
|
||||||
destinations = sortDestinations(destinations, initial);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Clear the states to be ready for a new search
|
|
||||||
*/
|
|
||||||
private void clearStates() {
|
|
||||||
frontier.clear();
|
|
||||||
cameFrom.clear();
|
|
||||||
costSoFar.clear();
|
|
||||||
steps.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Run this in a loop
|
* Run this in a loop
|
||||||
*/
|
*/
|
||||||
@ -334,11 +407,14 @@ public class PlayerAStarAI extends AI implements PlayerAI, Constants {
|
|||||||
}
|
}
|
||||||
destinationIndex++;
|
destinationIndex++;
|
||||||
if (destinationIndex >= destinations.size()) {
|
if (destinationIndex >= destinations.size()) {
|
||||||
destinationIndex = 0;
|
getLogger().info("None of the destinations are reachable for A* Search!");
|
||||||
// No destinations are reachable, make the player move around at random to help move the enemies
|
// No destinations are reachable, make the player move around at random to help move the enemies
|
||||||
if (steps.size() > 0) {
|
if (steps.size() == 0) {
|
||||||
steps.add(1, getOpenSpaceAroundPlayer(scene));
|
steps.add(0, State.Type.PLAYER);
|
||||||
}
|
}
|
||||||
|
steps.add(1, getOpenSpaceAroundPlayer(scene));
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
while (!found && !destinations.isEmpty());
|
while (!found && !destinations.isEmpty());
|
||||||
@ -348,4 +424,103 @@ public class PlayerAStarAI extends AI implements PlayerAI, Constants {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculate the route from the objective to the player
|
||||||
|
*/
|
||||||
|
private void calculateRoute() {
|
||||||
|
getLogger().info("Calculate the route!");
|
||||||
|
State predecessor = foundObjective;
|
||||||
|
do {
|
||||||
|
steps.add(0, predecessor.getOperation());
|
||||||
|
predecessor = predecessor.getPredecessor();
|
||||||
|
}
|
||||||
|
while (predecessor != null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sort the destinations by importance, if the importance is the same then sort them by distance
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void sortDestinations() {
|
||||||
|
destinations = sortDestinations(destinations, initial);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clear the states to be ready for a new search
|
||||||
|
*/
|
||||||
|
private void clearStates() {
|
||||||
|
frontier.clear();
|
||||||
|
cameFrom.clear();
|
||||||
|
costSoFar.clear();
|
||||||
|
steps.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The cost based on enemy position
|
||||||
|
*/
|
||||||
|
private enum EnemyCost {
|
||||||
|
/**
|
||||||
|
* The enemy does not have a cost
|
||||||
|
*/
|
||||||
|
NONE(0, 1),
|
||||||
|
/**
|
||||||
|
* The enemy cell has a cost
|
||||||
|
*/
|
||||||
|
DIRECT(1, 8),
|
||||||
|
/**
|
||||||
|
* The cells to the side of the enemy have a cost
|
||||||
|
*/
|
||||||
|
DIRECT_SIDES(2, 4),
|
||||||
|
/**
|
||||||
|
* The cells on the corner of the enemy
|
||||||
|
*/
|
||||||
|
DIRECT_CORNERS(3, 4),
|
||||||
|
/**
|
||||||
|
* The cells father to the side of the enemy
|
||||||
|
*/
|
||||||
|
FAR_SIDES(4, 2),
|
||||||
|
/**
|
||||||
|
* The cells in the corner farthest from the enemy
|
||||||
|
*/
|
||||||
|
FAR_CORNERS(5, 2);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The level of cost to use for the enemy
|
||||||
|
*/
|
||||||
|
private final int level;
|
||||||
|
/**
|
||||||
|
* The cost value to use
|
||||||
|
*/
|
||||||
|
private final int cost;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize the enemy cost and level
|
||||||
|
*
|
||||||
|
* @param level The level
|
||||||
|
* @param cost The cost
|
||||||
|
*/
|
||||||
|
EnemyCost(int level, int cost) {
|
||||||
|
this.level = level;
|
||||||
|
this.cost = cost;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the cost level of the enemy
|
||||||
|
*
|
||||||
|
* @return Returns the cost level
|
||||||
|
*/
|
||||||
|
protected int getLevel() {
|
||||||
|
return this.level;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the cost of the enemy
|
||||||
|
*
|
||||||
|
* @return Returns the cost
|
||||||
|
*/
|
||||||
|
protected int getCost() {
|
||||||
|
return this.cost;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
@ -23,6 +23,7 @@ import java.util.ArrayList;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.PriorityQueue;
|
import java.util.PriorityQueue;
|
||||||
import java.util.Queue;
|
import java.util.Queue;
|
||||||
|
import java.util.concurrent.CopyOnWriteArrayList;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This is an implementation of the Breadth-First search algorithm with multiple objectives
|
* This is an implementation of the Breadth-First search algorithm with multiple objectives
|
||||||
@ -59,7 +60,7 @@ public class PlayerBreadthFirstAI extends AI implements PlayerAI, Constants {
|
|||||||
/**
|
/**
|
||||||
* The destinations to visit
|
* The destinations to visit
|
||||||
*/
|
*/
|
||||||
private List<State> destinations = new ArrayList<>();
|
private List<State> destinations = new CopyOnWriteArrayList<>();
|
||||||
/**
|
/**
|
||||||
* The initial point to start searching from
|
* The initial point to start searching from
|
||||||
*/
|
*/
|
||||||
@ -220,6 +221,22 @@ public class PlayerBreadthFirstAI extends AI implements PlayerAI, Constants {
|
|||||||
destinations.add(destination);
|
destinations.add(destination);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove the picked up key from destinations if it is there
|
||||||
|
*
|
||||||
|
* @param x The x coordinate of the key
|
||||||
|
* @param y The y coordinate of the key
|
||||||
|
*/
|
||||||
|
public void removeKeyDestination(int x, int y) {
|
||||||
|
for (State state : destinations) {
|
||||||
|
if (state.getOperation() == State.Type.KEY && state.getX() == x && state.getY() == y) {
|
||||||
|
destinations.remove(state);
|
||||||
|
sortDestinations();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sort the destinations by importance, if the importance is the same then sort them by distance
|
* Sort the destinations by importance, if the importance is the same then sort them by distance
|
||||||
*/
|
*/
|
||||||
@ -284,10 +301,14 @@ public class PlayerBreadthFirstAI extends AI implements PlayerAI, Constants {
|
|||||||
}
|
}
|
||||||
destinationIndex++;
|
destinationIndex++;
|
||||||
if (destinationIndex >= destinations.size()) {
|
if (destinationIndex >= destinations.size()) {
|
||||||
destinationIndex = 0;
|
getLogger().info("None of the destinations are reachable for Breadth-First Search!");
|
||||||
if (steps.size() > 0) {
|
// No destinations are reachable, make the player move around at random to help move the enemies
|
||||||
steps.add(1, getOpenSpaceAroundPlayer(scene));
|
if (steps.size() == 0) {
|
||||||
|
steps.add(0, State.Type.PLAYER);
|
||||||
}
|
}
|
||||||
|
steps.add(1, getOpenSpaceAroundPlayer(scene));
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
while (!found && !destinations.isEmpty());
|
while (!found && !destinations.isEmpty());
|
||||||
|
@ -18,6 +18,7 @@ package cl.cromer.azaraka.object;
|
|||||||
import cl.cromer.azaraka.Cell;
|
import cl.cromer.azaraka.Cell;
|
||||||
import cl.cromer.azaraka.Constants;
|
import cl.cromer.azaraka.Constants;
|
||||||
import cl.cromer.azaraka.Scene;
|
import cl.cromer.azaraka.Scene;
|
||||||
|
import cl.cromer.azaraka.ai.AIException;
|
||||||
import cl.cromer.azaraka.sound.Sound;
|
import cl.cromer.azaraka.sound.Sound;
|
||||||
import cl.cromer.azaraka.sound.SoundException;
|
import cl.cromer.azaraka.sound.SoundException;
|
||||||
import cl.cromer.azaraka.sprite.Animation;
|
import cl.cromer.azaraka.sprite.Animation;
|
||||||
@ -116,6 +117,12 @@ public class Key extends Object implements Constants {
|
|||||||
// Remove the key from the cell
|
// Remove the key from the cell
|
||||||
getCell().setObjectOnBottom(null);
|
getCell().setObjectOnBottom(null);
|
||||||
setState(State.HELD);
|
setState(State.HELD);
|
||||||
|
try {
|
||||||
|
getScene().getCanvas().getPlayer().getAi().removeKeyDestination(getCell().getX(), getCell().getY());
|
||||||
|
}
|
||||||
|
catch (AIException e) {
|
||||||
|
getLogger().warning(e.getMessage());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
Loading…
Reference in New Issue
Block a user