|  | 
|  | 1 | +// https://www.hackerrank.com/challenges/castle-on-the-grid/problem | 
|  | 2 | + | 
|  | 3 | +package queues; | 
|  | 4 | + | 
|  | 5 | +import java.util.HashMap; | 
|  | 6 | +import java.util.LinkedList; | 
|  | 7 | +import java.util.Map; | 
|  | 8 | +import java.util.Objects; | 
|  | 9 | +import java.util.Queue; | 
|  | 10 | +import java.util.Scanner; | 
|  | 11 | + | 
|  | 12 | +public class CastleOnTheGrid { | 
|  | 13 | + private static final Scanner scanner = new Scanner(System.in); | 
|  | 14 | + | 
|  | 15 | + public static void main(String[] args) { | 
|  | 16 | + int length = scanner.nextInt(); | 
|  | 17 | + String[] grid = getGrid(length); | 
|  | 18 | + int startX = scanner.nextInt(); | 
|  | 19 | + int startY = scanner.nextInt(); | 
|  | 20 | + int endX = scanner.nextInt(); | 
|  | 21 | + int endY = scanner.nextInt(); | 
|  | 22 | + Grid solution = new Grid(grid, new Position(startX, startY), new Position(endX, endY)); | 
|  | 23 | + System.out.println(solution.shortestPath()); | 
|  | 24 | + } | 
|  | 25 | + | 
|  | 26 | + private static class Position { | 
|  | 27 | + private final int x; | 
|  | 28 | + private final int y; | 
|  | 29 | + | 
|  | 30 | + Position(int x, int y) { | 
|  | 31 | + this.x = x; | 
|  | 32 | + this.y = y; | 
|  | 33 | + } | 
|  | 34 | + | 
|  | 35 | + boolean notBlocked(String[] grid) { | 
|  | 36 | + return grid[x].charAt(y) != 'X'; | 
|  | 37 | + } | 
|  | 38 | + | 
|  | 39 | + boolean isValidPosition(String[] grid) { | 
|  | 40 | + return x < grid.length | 
|  | 41 | + && x >= 0 | 
|  | 42 | + && y < grid[0].length() | 
|  | 43 | + && y >= 0; | 
|  | 44 | + } | 
|  | 45 | + | 
|  | 46 | + Position goUp() { | 
|  | 47 | + return new Position(x - 1, y); | 
|  | 48 | + } | 
|  | 49 | + | 
|  | 50 | + Position goRight() { | 
|  | 51 | + return new Position(x, y + 1); | 
|  | 52 | + } | 
|  | 53 | + | 
|  | 54 | + Position goDown() { | 
|  | 55 | + return new Position(x + 1, y); | 
|  | 56 | + } | 
|  | 57 | + | 
|  | 58 | + Position goLeft() { | 
|  | 59 | + return new Position(x, y - 1); | 
|  | 60 | + } | 
|  | 61 | + | 
|  | 62 | + @Override | 
|  | 63 | + public boolean equals(Object o) { | 
|  | 64 | + if (this == o) return true; | 
|  | 65 | + if (o == null || getClass() != o.getClass()) return false; | 
|  | 66 | + Position position = (Position) o; | 
|  | 67 | + return x == position.x && y == position.y; | 
|  | 68 | + } | 
|  | 69 | + | 
|  | 70 | + @Override | 
|  | 71 | + public int hashCode() { | 
|  | 72 | + return Objects.hash(x, y); | 
|  | 73 | + } | 
|  | 74 | + | 
|  | 75 | + @Override | 
|  | 76 | + public String toString() { | 
|  | 77 | + return "(" + | 
|  | 78 | + "" + x + | 
|  | 79 | + ", " + y + | 
|  | 80 | + ')'; | 
|  | 81 | + } | 
|  | 82 | + } | 
|  | 83 | + | 
|  | 84 | + private static class Grid { | 
|  | 85 | + private final String[] grid; | 
|  | 86 | + private final Position source; | 
|  | 87 | + private final Position destination; | 
|  | 88 | + private final LateralMovement up = new UpLateralMovement(); | 
|  | 89 | + private final LateralMovement right = new RightLateralMovement(); | 
|  | 90 | + private final LateralMovement down = new DownLateralMovement(); | 
|  | 91 | + private final LateralMovement left = new LeftLateralMovement(); | 
|  | 92 | + | 
|  | 93 | + Grid(String[] grid, Position source, Position destination) { | 
|  | 94 | + this.grid = grid; | 
|  | 95 | + this.source = source; | 
|  | 96 | + this.destination = destination; | 
|  | 97 | + } | 
|  | 98 | + | 
|  | 99 | + int shortestPath() { | 
|  | 100 | + Map<Position, Position> prefixPositions = new HashMap<>(); | 
|  | 101 | + prefixPositions.put(source, source); | 
|  | 102 | + Queue<Position> queue = new LinkedList<>(); | 
|  | 103 | + queue.add(source); | 
|  | 104 | + | 
|  | 105 | + while (!queue.isEmpty()) { | 
|  | 106 | + Position top = queue.poll(); | 
|  | 107 | + if (top.equals(destination)) { | 
|  | 108 | + break; | 
|  | 109 | + } | 
|  | 110 | + | 
|  | 111 | + addLateralVerticesToQueue(top, prefixPositions, queue); | 
|  | 112 | + } | 
|  | 113 | + | 
|  | 114 | + return shortestPath(prefixPositions); | 
|  | 115 | + } | 
|  | 116 | + | 
|  | 117 | + private abstract class LateralMovement { | 
|  | 118 | + private void addLateralVerticesToQueue(Position position, Map<Position, Position> prefixes, Queue<Position> queue) { | 
|  | 119 | + Position current = position; | 
|  | 120 | + while (current.isValidPosition(grid) && current.notBlocked(grid)) { | 
|  | 121 | + if (!prefixes.containsKey(current)) { | 
|  | 122 | + prefixes.put(current, position); | 
|  | 123 | + queue.add(current); | 
|  | 124 | + } | 
|  | 125 | + current = lateralVertice(current); | 
|  | 126 | + } | 
|  | 127 | + } | 
|  | 128 | + | 
|  | 129 | + abstract Position lateralVertice(Position position); | 
|  | 130 | + } | 
|  | 131 | + | 
|  | 132 | + private class UpLateralMovement extends LateralMovement { | 
|  | 133 | + @Override | 
|  | 134 | + Position lateralVertice(Position position) { | 
|  | 135 | + return position.goUp(); | 
|  | 136 | + } | 
|  | 137 | + } | 
|  | 138 | + | 
|  | 139 | + private class RightLateralMovement extends LateralMovement { | 
|  | 140 | + @Override | 
|  | 141 | + Position lateralVertice(Position position) { | 
|  | 142 | + return position.goRight(); | 
|  | 143 | + } | 
|  | 144 | + } | 
|  | 145 | + | 
|  | 146 | + private class DownLateralMovement extends LateralMovement { | 
|  | 147 | + @Override | 
|  | 148 | + Position lateralVertice(Position position) { | 
|  | 149 | + return position.goDown(); | 
|  | 150 | + } | 
|  | 151 | + } | 
|  | 152 | + | 
|  | 153 | + private class LeftLateralMovement extends LateralMovement { | 
|  | 154 | + @Override | 
|  | 155 | + Position lateralVertice(Position position) { | 
|  | 156 | + return position.goLeft(); | 
|  | 157 | + } | 
|  | 158 | + } | 
|  | 159 | + | 
|  | 160 | + private void addLateralVerticesToQueue(Position position, Map<Position, Position> prefixes, Queue<Position> queue) { | 
|  | 161 | + up.addLateralVerticesToQueue(position, prefixes, queue); | 
|  | 162 | + right.addLateralVerticesToQueue(position, prefixes, queue); | 
|  | 163 | + down.addLateralVerticesToQueue(position, prefixes, queue); | 
|  | 164 | + left.addLateralVerticesToQueue(position, prefixes, queue); | 
|  | 165 | + } | 
|  | 166 | + | 
|  | 167 | + private int shortestPath(Map<Position, Position> prefixPositions) { | 
|  | 168 | + return shortestPath(prefixPositions, this.destination); | 
|  | 169 | + } | 
|  | 170 | + | 
|  | 171 | + private int shortestPath(Map<Position, Position> prefixPositions, Position position) { | 
|  | 172 | + if (position.equals(this.source)) { | 
|  | 173 | + return 0; | 
|  | 174 | + } | 
|  | 175 | + | 
|  | 176 | + return 1 + shortestPath(prefixPositions, prefixPositions.get(position)); | 
|  | 177 | + } | 
|  | 178 | + } | 
|  | 179 | + | 
|  | 180 | + private static String[] getGrid(int length) { | 
|  | 181 | + String[] array = new String[length]; | 
|  | 182 | + for (int index = 0 ; index < length ; index++) { | 
|  | 183 | + array[index] = scanner.next(); | 
|  | 184 | + } | 
|  | 185 | + return array; | 
|  | 186 | + } | 
|  | 187 | +} | 
0 commit comments