Advertisement
tripTiPscout

Labyrinth 2

Feb 9th, 2023 (edited)
805
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Java 10.22 KB | None | 0 0
  1. import java.util.ArrayList;
  2. import java.util.Arrays;
  3. import java.util.Collections;
  4. import java.util.List;
  5. import java.util.PriorityQueue;
  6. import java.util.stream.Collectors;
  7.  
  8. public class Main {
  9.  
  10.     public static void main(String[] args) {
  11.  
  12.         // The labyrinth string representation
  13.         String maze = "" +
  14.                 " ,M,N, ,X\n" +
  15.                 "N, ,N,~, \n" +
  16.                 " , ,N, , \n" +
  17.                 " , ,N, , \n" +
  18.                 " , , , , \n" +
  19.                 " , , , , ";
  20.  
  21.         App.solveLabyrinth(maze);
  22.  
  23.     }
  24.  
  25. }
  26.  
  27. // Class from the task in moodle
  28. class App {
  29.  
  30.     // solver is refactored for presentation
  31.     public static void solveLabyrinth(String mapFilename) {
  32.  
  33.         String data = mapFilename.replaceAll(",", "");
  34.  
  35.         Labyrint labyrinth = new Labyrint(data);
  36.  
  37.         List<Cel> path = labyrinth.findPath(labyrinth);
  38.  
  39.         if (Labyrint.IS_FOUND) {
  40.             System.out.println();
  41.             labyrinth.consolePrint(path);
  42.             System.out.println("Total cost is: " + labyrinth.calculateCost(path));
  43.  
  44.             labyrinth.markPath(path);
  45.             String visualizeMazePath = labyrinth.visualizeMazePath(Labyrint.FINAL_MAZE_PATH);
  46.             System.out.println();
  47.             System.out.print(visualizeMazePath);
  48.         } else {
  49.             System.out.println("There is no path!");
  50.         }
  51.  
  52.     }
  53. }
  54.  
  55. // Labyrinth with all methods for the task solve
  56. class Labyrint {
  57.  
  58.     // static fields for initialization
  59.     private int[][] maze;
  60.     private Cel start;
  61.     private Cel end;
  62.     private boolean[][] visited;
  63.     private static final int ROAD = 0;
  64.     private static final int WALL = 1;
  65.     private static final int START = 2;
  66.     private static final int END = 3;
  67.     private static final int PATH = 4;
  68.     private static final int WATER = 5;
  69.  
  70.     //all directions
  71.     private static final int[][] DIRECTIONS_STRAIGHT = { { 0, 1 }, { 1, 0 }, { 0, -1 }, { -1, 0 } };
  72.     private static final int[][] DIRECTIONS_DIAGONAL = { { 1, 1 }, { -1, -1 }, { 1, -1 }, { -1, 1 } };
  73.  
  74.     // auxiliary fields
  75.     public static boolean IS_FOUND = false;
  76.     public static int[][] FINAL_MAZE_PATH;
  77.     public static Cel FOOD;
  78.  
  79.     public Labyrint(String maze) {
  80.         initializeMaze(maze);
  81.     }
  82.  
  83.     // represent labyrinth in 2D int matrix (using static fields)
  84.     private void initializeMaze(String text) {
  85.         if (text == null || text.length() == 0) {
  86.             throw new IllegalArgumentException("Empty lines data.");
  87.         }
  88.        
  89.         String[] lines = text.split("\n");
  90.         maze = new int[lines.length][lines[0].length()];
  91.         visited = new boolean[lines.length][lines[0].length()];
  92.  
  93.         for (int row = 0; row < getHeight(); row++) {
  94.             if (lines[row].length() != getWidth()) {
  95.                 throw new IllegalArgumentException("Line " + (row) + " wrong length (was " + lines[row].length() + " but should be " + getWidth() + ").");
  96.             }
  97.  
  98.             for (int col = 0; col < getWidth(); col++) {
  99.                 if (lines[row].charAt(col) == 'N')
  100.                     maze[row][col] = WALL;
  101.                 else if (lines[row].charAt(col) == 'M') {
  102.                     maze[row][col] = START;
  103.                     start = new Cel(row, col);
  104.                 } else if (lines[row].charAt(col) == 'X') {
  105.                     maze[row][col] = END;
  106.                     end = new Cel(row, col);
  107.                     FOOD = new Cel(row, col);
  108.                 } else if (lines[row].charAt(col) == ' ') {
  109.                     maze[row][col] = ROAD;
  110.                 } else if (lines[row].charAt(col) == '~') {
  111.                     maze[row][col] = WATER;
  112.                 }
  113.             }
  114.         }
  115.     }
  116.  
  117.     public int getHeight() {
  118.         return maze.length;
  119.     }
  120.  
  121.     public int getWidth() {
  122.         return maze[0].length;
  123.     }
  124.  
  125.     public Cel getEntry() {
  126.         return start;
  127.     }
  128.  
  129.     // the path find algorithm
  130.     public List<Cel> findPath(Labyrint labyrinth) {
  131.         //using priority queue
  132.         PriorityQueue<Cel> queue = new PriorityQueue<>(Cel::compareTo);
  133.         // entry point (Cell)
  134.         Cel start = labyrinth.getEntry();
  135.         queue.offer(start);
  136.  
  137.         while (!queue.isEmpty()) {
  138.             Cel current = queue.poll();
  139.             labyrinth.setVisited(current.getX(), current.getY(), true);
  140.  
  141.             double cost;
  142.  
  143.             if (labyrinth.isFound(current.getX(), current.getY())) {
  144.                 IS_FOUND = true;
  145.                 return backtrackPath(current);
  146.             }
  147.  
  148.             // move in straight directions - cost 1
  149.             for (int[] direction : DIRECTIONS_STRAIGHT) {
  150.                 cost = 1;
  151.                 move(labyrinth, queue, current, direction, cost);
  152.             }
  153.  
  154.             // move in diagonals - cost 1.5
  155.             for (int[] direction : DIRECTIONS_DIAGONAL) {
  156.                 cost = 1.5;
  157.                 move(labyrinth, queue, current, direction, cost);
  158.             }
  159.         }
  160.         return Collections.emptyList();
  161.     }
  162.  
  163.     // move method with different cost
  164.     private void move(Labyrint maze, PriorityQueue<Cel> queue, Cel current, int[] direction, double cost) {
  165.         Cel nextPosition = new Cel(current.getX() + direction[0], current.getY() + direction[1], current, cost);
  166.         // check for validate next position
  167.         if (maze.invalidLocation(nextPosition.getX(), nextPosition.getY())
  168.                 || maze.isExplored(nextPosition.getX(), nextPosition.getY())
  169.                 || maze.isWall(nextPosition.getX(), nextPosition.getY())) {
  170.             return;
  171.         }
  172.         // check for water
  173.         if (maze.isWater(current.getX(), current.getY())) {
  174.             nextPosition.setCost(2);
  175.         }
  176.         queue.add(nextPosition);
  177.     }
  178.  
  179.     public boolean isStart(int x, int y) {
  180.         return x == start.getX() && y == start.getY();
  181.     }
  182.  
  183.     public boolean isFound(int x, int y) {
  184.         return x == end.getX() && y == end.getY();
  185.     }
  186.  
  187.     public boolean isWall(int row, int col) {
  188.         return maze[row][col] == WALL;
  189.     }
  190.  
  191.     public boolean isWater(int row, int col) {
  192.         return maze[row][col] == WATER;
  193.     }
  194.  
  195.     public boolean isExplored(int row, int col) {
  196.         return visited[row][col];
  197.     }
  198.  
  199.     public void setVisited(int row, int col, boolean value) {
  200.         visited[row][col] = value;
  201.     }
  202.  
  203.     public boolean invalidLocation(int row, int col) {
  204.         return row < 0 || row >= getHeight() || col < 0 || col >= getWidth();
  205.     }
  206.  
  207.     // backtracking the path using parent of each visited cell
  208.     private List<Cel> backtrackPath(Cel current) {
  209.         List<Cel> path = new ArrayList<>();
  210.         Cel next = current;
  211.  
  212.  
  213.         while (next != null) {
  214.             path.add(next);
  215.             next = next.parent;
  216.         }
  217.  
  218.         return path;
  219.     }
  220.  
  221.     // marking path in 2D int matrix with value for visualisation
  222.     public void markPath(List<Cel> path) {
  223.         int[][] mazePath = Arrays.stream(maze)
  224.                 .map(int[]::clone)
  225.                 .toArray(int[][]::new);
  226.         for (Cel cell : path) {
  227.             if (isStart(cell.getX(), cell.getY()) || isFound(cell.getX(), cell.getY())) {
  228.                 continue;
  229.             }
  230.             mazePath[cell.getX()][cell.getY()] = PATH;
  231.         }
  232.         FINAL_MAZE_PATH = mazePath;
  233.     }
  234.  
  235.     // calculate total cost of founded path
  236.     public double calculateCost(List<Cel> path) {
  237.         double totalCost = 0;
  238.         for (Cel cell : path) {
  239.             if (isStart(cell.getX(), cell.getY())) {
  240.                 continue;
  241.             }
  242.             totalCost += cell.getCost();
  243.         }
  244.         return totalCost;
  245.     }
  246.  
  247.     // visualisation method for better understand (represent the 2D int matrix like a string)
  248.     public String visualizeMazePath(int[][] maze) {
  249.         StringBuilder result = new StringBuilder(maze[0].length * (maze.length + 1));
  250.         result.append("Visualization: ");
  251.         result.append(System.lineSeparator());
  252.         for (int[] row : maze) {
  253.             for (int col = 0; col < maze[0].length; col++) {
  254.                 if (row[col] == PATH) {
  255.                     result.append('.');
  256.                 } else if (row[col] == WALL) {
  257.                     result.append('N');
  258.                 } else if (row[col] == START) {
  259.                     result.append('M');
  260.                 } else if (row[col] == END) {
  261.                     result.append('X');
  262.                 } else if (row[col] == WATER) {
  263.                     result.append('~');
  264.                 } else {
  265.                     result.append(' ');
  266.                 }
  267.             }
  268.             result.append('|');
  269.             result.append(System.lineSeparator());
  270.         }
  271.         return result.toString();
  272.     }
  273.  
  274.     // print method
  275.     public void consolePrint(List<Cel> path) {
  276.         Collections.reverse(path);
  277.         String result = path.stream().map(Cel::toString).collect(Collectors.joining(", "));
  278.         System.out.println("Find path in " + (path.size() - 1) + " steps: ");
  279.         System.out.println(result);
  280.     }
  281.  
  282. }
  283.  
  284. // Cell class represent the point in labyrinth
  285. class Cel implements Comparable<Cel> {
  286.  
  287.     private final int x;
  288.  
  289.     private final int y;
  290.  
  291.     private double cost;
  292.  
  293.     public Cel parent;
  294.  
  295.     public Cel(int x, int y) {
  296.         this.x = x;
  297.         this.y = y;
  298.         this.parent = null;
  299.     }
  300.  
  301.     public Cel(int x, int y, Cel parent, double cost) {
  302.         this(x, y);
  303.         this.parent = parent;
  304.         this.cost = cost;
  305.     }
  306.  
  307.     int getX() {
  308.         return x;
  309.     }
  310.  
  311.     int getY() {
  312.         return y;
  313.     }
  314.  
  315.     public double getCost() {
  316.         return cost;
  317.     }
  318.  
  319.     public void setCost(double cost) {
  320.         this.cost = cost;
  321.     }
  322.  
  323.     // distance to target for heuristic
  324.     public double getDistanceToTarget() {
  325.         return Math.abs(getX() - Labyrint.FOOD.getX()) + Math.abs(getY() - Labyrint.FOOD.getY());
  326.     }
  327.  
  328.     // compare method for priority in queue
  329.     @Override
  330.     public int compareTo(Cel cell) {
  331.         return (int) ((getCost() + getDistanceToTarget()) - (cell.getCost() + cell.getDistanceToTarget()));
  332.     }
  333.  
  334.     @Override
  335.     public String toString() {
  336.         return String.format("%d %d", getX(), getY());
  337.     }
  338.  
  339. }
  340.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement