diff --git a/src/main/java/ruscz/game/gameOfProd/AStar/AStar.java b/src/main/java/ruscz/game/gameOfProd/AStar/AStar.java new file mode 100644 index 0000000..d28c763 --- /dev/null +++ b/src/main/java/ruscz/game/gameOfProd/AStar/AStar.java @@ -0,0 +1,211 @@ +package ruscz.game.gameOfProd.AStar; + +import java.util.*; + +/** + * A Star Algorithm + * + * @author Marcelo Surriabre + * @version 2.1, 2017-02-23 + */ +public class AStar { + private static int DEFAULT_HV_COST = 1; + private static int DEFAULT_DIAGONAL_COST = 1000000000; + private int hvCost; + private int diagonalCost; + private Node[][] searchArea; + private PriorityQueue openList; + private Set closedSet; + private Node initialNode; + private Node finalNode; + + public AStar(int rows, int cols, Node initialNode, Node finalNode, int hvCost, int diagonalCost) { + this.hvCost = hvCost; + this.diagonalCost = diagonalCost; + setInitialNode(initialNode); + setFinalNode(finalNode); + this.searchArea = new Node[rows][cols]; + this.openList = new PriorityQueue<>(Comparator.comparingInt(Node::getF)); + setNodes(); + this.closedSet = new HashSet<>(); + } + + public AStar(int rows, int cols, Node initialNode, Node finalNode) { + this(rows, cols, initialNode, finalNode, DEFAULT_HV_COST, DEFAULT_DIAGONAL_COST); + } + + private void setNodes() { + for (int i = 0; i < searchArea.length; i++) { + for (int j = 0; j < searchArea[0].length; j++) { + Node node = new Node(i, j); + node.calculateHeuristic(getFinalNode()); + this.searchArea[i][j] = node; + } + } + } + + public void setBlocks(int[][] blocksArray) { + for (int i = 0; i < blocksArray.length; i++) { + int row = blocksArray[i][0]; + int col = blocksArray[i][1]; + setBlock(row, col); + } + } + + public List findPath() { + openList.add(initialNode); + while (!isEmpty(openList)) { + Node currentNode = openList.poll(); + closedSet.add(currentNode); + assert currentNode != null; + if (isFinalNode(currentNode)) { + return getPath(currentNode); + } else { + addAdjacentNodes(currentNode); + } + } + return new ArrayList<>(); + } + + private List getPath(Node currentNode) { + List path = new ArrayList<>(); + path.add(currentNode); + Node parent; + while ((parent = currentNode.getParent()) != null) { + path.add(0, parent); + currentNode = parent; + } + return path; + } + + private void addAdjacentNodes(Node currentNode) { + addAdjacentUpperRow(currentNode); + addAdjacentMiddleRow(currentNode); + addAdjacentLowerRow(currentNode); + } + + private void addAdjacentLowerRow(Node currentNode) { + int row = currentNode.getRow(); + int col = currentNode.getCol(); + int lowerRow = row + 1; + if (lowerRow < getSearchArea().length) { + if (col - 1 >= 0) { + checkNode(currentNode, col - 1, lowerRow, getDiagonalCost()); // Comment this line if diagonal movements are not allowed + } + if (col + 1 < getSearchArea()[0].length) { + checkNode(currentNode, col + 1, lowerRow, getDiagonalCost()); // Comment this line if diagonal movements are not allowed + } + checkNode(currentNode, col, lowerRow, getHvCost()); + } + } + + private void addAdjacentMiddleRow(Node currentNode) { + int row = currentNode.getRow(); + int col = currentNode.getCol(); + if (col - 1 >= 0) { + checkNode(currentNode, col - 1, row, getHvCost()); + } + if (col + 1 < getSearchArea()[0].length) { + checkNode(currentNode, col + 1, row, getHvCost()); + } + } + + private void addAdjacentUpperRow(Node currentNode) { + int row = currentNode.getRow(); + int col = currentNode.getCol(); + int upperRow = row - 1; + if (upperRow >= 0) { + if (col - 1 >= 0) { + checkNode(currentNode, col - 1, upperRow, getDiagonalCost()); // Comment this if diagonal movements are not allowed + } + if (col + 1 < getSearchArea()[0].length) { + checkNode(currentNode, col + 1, upperRow, getDiagonalCost()); // Comment this if diagonal movements are not allowed + } + checkNode(currentNode, col, upperRow, getHvCost()); + } + } + + private void checkNode(Node currentNode, int col, int row, int cost) { + Node adjacentNode = getSearchArea()[row][col]; + if (!adjacentNode.isBlock() && !getClosedSet().contains(adjacentNode)) { + if (!getOpenList().contains(adjacentNode)) { + adjacentNode.setNodeData(currentNode, cost); + getOpenList().add(adjacentNode); + } else { + boolean changed = adjacentNode.checkBetterPath(currentNode, cost); + if (changed) { + getOpenList().remove(adjacentNode); + getOpenList().add(adjacentNode); + } + } + } + } + + private boolean isFinalNode(Node currentNode) { + return currentNode.equals(finalNode); + } + + private boolean isEmpty(PriorityQueue openList) { + return openList.size() == 0; + } + + public void setBlock(int row, int col) { + this.searchArea[row][col].setBlock(true); + } + + public Node getInitialNode() { + return initialNode; + } + + public void setInitialNode(Node initialNode) { + this.initialNode = initialNode; + } + + public Node getFinalNode() { + return finalNode; + } + + public void setFinalNode(Node finalNode) { + this.finalNode = finalNode; + } + + public Node[][] getSearchArea() { + return searchArea; + } + + public void setSearchArea(Node[][] searchArea) { + this.searchArea = searchArea; + } + + public PriorityQueue getOpenList() { + return openList; + } + + public void setOpenList(PriorityQueue openList) { + this.openList = openList; + } + + public Set getClosedSet() { + return closedSet; + } + + public void setClosedSet(Set closedSet) { + this.closedSet = closedSet; + } + + public int getHvCost() { + return hvCost; + } + + public void setHvCost(int hvCost) { + this.hvCost = hvCost; + } + + private int getDiagonalCost() { + return diagonalCost; + } + + private void setDiagonalCost(int diagonalCost) { + this.diagonalCost = diagonalCost; + } +} \ No newline at end of file diff --git a/src/main/java/ruscz/game/gameOfProd/AStar/Node.java b/src/main/java/ruscz/game/gameOfProd/AStar/Node.java new file mode 100644 index 0000000..6975151 --- /dev/null +++ b/src/main/java/ruscz/game/gameOfProd/AStar/Node.java @@ -0,0 +1,116 @@ +package ruscz.game.gameOfProd.AStar; + +/** + * Node Class + * + * @author Marcelo Surriabre + * @version 2.0, 2017-02-23 + */ +public class Node { + + private int g; + private int f; + private int h; + private int row; + private int col; + private boolean isBlock; + private Node parent; + + public Node(int row, int col) { + super(); + this.row = row; + this.col = col; + } + + public void calculateHeuristic(Node finalNode) { + this.h = Math.abs(finalNode.getRow() - getRow()) + Math.abs(finalNode.getCol() - getCol()); + } + + public void setNodeData(Node currentNode, int cost) { + int gCost = currentNode.getG() + cost; + setParent(currentNode); + setG(gCost); + calculateFinalCost(); + } + + public boolean checkBetterPath(Node currentNode, int cost) { + int gCost = currentNode.getG() + cost; + if (gCost < getG()) { + setNodeData(currentNode, cost); + return true; + } + return false; + } + + private void calculateFinalCost() { + int finalCost = getG() + getH(); + setF(finalCost); + } + + @Override + public boolean equals(Object arg0) { + Node other = (Node) arg0; + return this.getRow() == other.getRow() && this.getCol() == other.getCol(); + } + + @Override + public String toString() { + return "Node [row=" + row + ", col=" + col + "]"; + } + + public int getH() { + return h; + } + + public void setH(int h) { + this.h = h; + } + + public int getG() { + return g; + } + + public void setG(int g) { + this.g = g; + } + + public int getF() { + return f; + } + + public void setF(int f) { + this.f = f; + } + + public Node getParent() { + return parent; + } + + public void setParent(Node parent) { + this.parent = parent; + } + + public boolean isBlock() { + return isBlock; + } + + public void setBlock(boolean isBlock) { + this.isBlock = isBlock; + } + + public int getRow() { + return row; + } + + public void setRow(int row) { + this.row = row; + } + + public int getCol() { + return col; + } + + public void setCol(int col) { + this.col = col; + } +} diff --git a/src/main/java/ruscz/game/gameOfProd/Map/Map.java b/src/main/java/ruscz/game/gameOfProd/Map/Map.java index f846e16..faeb070 100644 --- a/src/main/java/ruscz/game/gameOfProd/Map/Map.java +++ b/src/main/java/ruscz/game/gameOfProd/Map/Map.java @@ -21,7 +21,6 @@ public class Map { private LinkedList interactionCells; private LinkedList triggerCells; private LinkedList npcs; - private boolean isBlocked; private int idExit; private ImageCell imageCell; @@ -31,12 +30,11 @@ public class Map { name = "Spawn"; idExit = 0; mapArray = new TypeOfCell[height][width]; - moveToCells = new LinkedList(); - interactionCells = new LinkedList(); - triggerCells = new LinkedList(); + moveToCells = new LinkedList<>(); + interactionCells = new LinkedList<>(); + triggerCells = new LinkedList<>(); npcs = new LinkedList<>(); - block = new LinkedList(); - isBlocked = false; + block = new LinkedList<>(); imageCell = new ImageCell(); TypeOfCell type; @@ -57,13 +55,12 @@ public class Map { public Map(int height, int width, Boolean isBlocked) { name = "Spawn"; idExit = 0; - moveToCells = new LinkedList(); - block = new LinkedList(); - interactionCells = new LinkedList(); - triggerCells = new LinkedList(); + moveToCells = new LinkedList<>(); + block = new LinkedList<>(); + interactionCells = new LinkedList<>(); + triggerCells = new LinkedList<>(); mapArray = new TypeOfCell[height][width]; npcs = new LinkedList<>(); - this.isBlocked = isBlocked; imageCell = new ImageCell(); TypeOfCell type; @@ -72,8 +69,8 @@ public class Map { else type = TypeOfCell.EMPTY; - for (int i = 0; i < mapArray.length; i++) { - for (int j = 0; j < mapArray[0].length; j++) { + for (int i = 0; i < mapArray.length / 2; i++) { + for (int j = 0; j < mapArray[0].length / 2; j++) { mapArray[0][j] = type; mapArray[mapArray.length - 1][j] = type; } @@ -86,11 +83,10 @@ public class Map { public Map(TypeOfCell[][] mapArray) { idExit = 0; - moveToCells = new LinkedList(); - interactionCells = new LinkedList(); - triggerCells = new LinkedList(); - block = new LinkedList(); - isBlocked = false; + moveToCells = new LinkedList<>(); + interactionCells = new LinkedList<>(); + triggerCells = new LinkedList<>(); + block = new LinkedList<>(); imageCell = new ImageCell(); npcs = new LinkedList<>(); this.mapArray = mapArray; diff --git a/src/main/java/ruscz/game/gameOfProd/Scripts/PathFinder.java b/src/main/java/ruscz/game/gameOfProd/Scripts/PathFinder.java index 733d449..8d68928 100644 --- a/src/main/java/ruscz/game/gameOfProd/Scripts/PathFinder.java +++ b/src/main/java/ruscz/game/gameOfProd/Scripts/PathFinder.java @@ -1,33 +1,23 @@ package ruscz.game.gameOfProd.Scripts; +import ruscz.game.gameOfProd.AStar.*; +import ruscz.game.gameOfProd.Cells.TypeOfCell; import ruscz.game.gameOfProd.Map.Map; -import ruscz.game.gameOfProd.Windows.WindowOfFreeMove; import java.util.LinkedList; +import java.util.List; public class PathFinder { - private static final int MAX_STEPS = 200; - private Map map; private boolean foundWay; - private int startX; - private int startY; + + private static final int MAX_STEPS = 200; public PathFinder(Map map) { this.map = map; foundWay = false; } - private LinkedList prepareDirection(){ - LinkedList directions = new LinkedList<>(); - directions.add(Direction.NONE); - return directions; - } - - private Direction[] getAllWays(){ - return new Direction[]{Direction.DOWN, Direction.UP, Direction.RIGHT, Direction.LEFT}; - } - public LinkedList getWayWithoutCollision(int startX, int startY, int endX, int endY) { int nowX = startX; int nowY = startY; @@ -57,61 +47,49 @@ public class PathFinder { return directions; } - private LinkedList getWayWithCollision(int startX, int startY, int endX, int endY, LinkedList directions) { - System.out.println(directions); - if (startX == endX && startY == endY){ - foundWay = true; - return directions; - } - if (directions.toArray().length == MAX_STEPS){ - return prepareDirection(); - } + public LinkedList getWayWithCollision(int startX, int startY, int endX, int endY) { + AStar aStar = new AStar(map.getMapArray().length, map.getMapArray()[0].length, new Node(startX, startY), new Node(endX, endY)); + LinkedList directions = new LinkedList<>(); - for (Direction direction: getAllWays()){ - switch (direction){ - case UP: - if (!map.isBusyCell(startX, startY - 1) && startY - 1 != -1 && directions.getLast() != Direction.DOWN){ - directions.add(Direction.UP); - startY--; - return getWayWithCollision(startX, startY, endX, endY, directions); - } - break; - case DOWN: - if (!map.isBusyCell(startX, startY + 1) & startY + 1 != WindowOfFreeMove.CANVAS_HEIGHT + 1 && directions.getLast() != Direction.UP){ - directions.add(Direction.DOWN); - startY++; - return getWayWithCollision(startX, startY, endX, endY, directions); - } - break; - case LEFT: - if (!map.isBusyCell(startX - 1, startY) && startX - 1 != -1 && directions.getLast() != Direction.RIGHT){ - directions.add(Direction.LEFT); - startX--; - return getWayWithCollision(startX, startY, endX, endY, directions); - } - break; - case RIGHT: - if (!map.isBusyCell(startX + 1, startY) && startX - 1 != WindowOfFreeMove.CANVAS_WIDTH + 1 && directions.getLast() != Direction.LEFT){ - directions.add(Direction.RIGHT); - startX++; - return getWayWithCollision(startX, startY, endX, endY, directions); - } - break; + for (int i = 0; i < map.getMapArray().length; i++) { + for (int j = 0; j < map.getMapArray()[0].length; j++) { + if (map.getMapArray()[i][j] == TypeOfCell.BLOCK || map.getMapArray()[i][j] == TypeOfCell.EVENT) { + aStar.setBlock(i, j); + } } } - directions.removeLast(); - return getWayWithCollision(startX, startY, endX, endY, directions); - } - public LinkedList getWayWithCollision(int startX, int startY, int endX, int endY){ - this.startX = startX; - this.startY = startY; + List nodeList = aStar.findPath(); + if (nodeList.size() == 0) { + return directions; + } + Node nowNode = nodeList.get(0); + if (nodeList.get(nodeList.size() - 1).getG() > MAX_STEPS) + return new LinkedList<>(); - LinkedList directions = getWayWithCollision(startX, startY, endX, endY, prepareDirection()); - if (foundWay) - return directions; - else - return prepareDirection(); + for (Node node : nodeList) { + if (nowNode == node) { + continue; + } + + if (nowNode.getG() > MAX_STEPS) + return new LinkedList<>(); + + if (node.getRow() - nowNode.getRow() == 1) { + directions.add(Direction.RIGHT); + } + if (node.getRow() - nowNode.getRow() == -1) { + directions.add(Direction.LEFT); + } + if (node.getCol() - nowNode.getCol() == 1) { + directions.add(Direction.DOWN); + } + if (node.getCol() - nowNode.getCol() == -1) { + directions.add(Direction.UP); + } + nowNode = node; + } + return directions; } } \ No newline at end of file diff --git a/src/main/java/ruscz/game/gameOfProd/Windows/WindowOfFreeMove.java b/src/main/java/ruscz/game/gameOfProd/Windows/WindowOfFreeMove.java index d2d96de..2dc51b5 100644 --- a/src/main/java/ruscz/game/gameOfProd/Windows/WindowOfFreeMove.java +++ b/src/main/java/ruscz/game/gameOfProd/Windows/WindowOfFreeMove.java @@ -87,12 +87,9 @@ public class WindowOfFreeMove extends JFrame { dialogBar.setVisible(false); dialogBar.setLayout(null); - inputTimer = new Timer(10, new ActionListener() { - @Override - public void actionPerformed(ActionEvent actionEvent) { - if (!mapPainter.getActualMap().getPerson().getIsMoving() && canPersonMove && nextMove != KEY_EVENT) { - mapPainter.getActualMap().getPerson().setDirectionMove(nextMove); - } + inputTimer = new Timer(10, actionEvent -> { + if (!mapPainter.getActualMap().getPerson().getIsMoving() && canPersonMove && nextMove != KEY_EVENT) { + mapPainter.getActualMap().getPerson().setDirectionMove(nextMove); } }); @@ -190,8 +187,10 @@ public class WindowOfFreeMove extends JFrame { mapPainter = new MapPainter(mapLinkedList, canvas); - Npc npc1 = new Npc(1,1, m5, mapPainter); - m5.setNpcs(npc1); + int startX = 1; + int startY = 1; + int endX = 8; + int endY = 8; setMapPainter(m5); @@ -200,22 +199,20 @@ public class WindowOfFreeMove extends JFrame { isReadyToPaint = true; canvas.repaint(); - Npc npc2 = new Npc(1,1, m6, mapPainter); + Npc npc2 = new Npc(startX, startY, m6, mapPainter); m6.setNpcs(npc2); - Timer timer = new Timer(10, new ActionListener() { - @Override - public void actionPerformed(ActionEvent actionEvent) { - mapPainter.getActualMap().getPerson().move(); - mapPainter.moveCamera(); - canvas.repaint(); - } + Timer timer = new Timer(10, actionEvent -> { + mapPainter.getActualMap().getPerson().move(); + mapPainter.moveCamera(); + canvas.repaint(); }); timer.start(); - while (true){ - npc2.move(9,9); - npc2.move(1,1); + while (true) { + npc2.move(endX, endY); + npc2.move(startX, startY); } + } public class Canvas extends JPanel { @@ -241,7 +238,7 @@ public class WindowOfFreeMove extends JFrame { for (Cell cell : mapPainter.getActualMap().getInteractionEventCells()) { cell.paint(g2D); } - for (Person person: mapPainter.getActualMap().getNpcs()){ + for (Person person : mapPainter.getActualMap().getNpcs()) { person.paint(g2D); } }