import java.util.*;
class Ideone {
public static void main
(String[] args
) { char[][] board = {{'0', '2', '1', '1', '1'},
{'0', '1', '0', '0', '1'},
{'0', '0', '0', '0', '1'},
{'0', '0', 'A', '0', '1'},
{'1', '1', 'a', '1', '1'},
{'1', 'b', '0', '0', 'B'},
{'1', '1', '0', '0', '1'},
{'0', '1', '0', '0', '3'}};
System.
out.
println(pathToString
(solve
(board
))); }
private static final class Coord {
final int y, x;
Coord(int y, int x) {
this.y = y;
this.x = x;
}
@Override
public String toString
() { return String.
valueOf(this.
y).
concat(String.
valueOf(this.
x)); }
}
private static String pathToString
(Iterable
<Coord
> path
) { StringJoiner joiner = new StringJoiner("->");
for (Coord coord : path)
joiner.add(coord.toString());
return joiner.toString();
}
private static List<Coord> solve(char[][] board) {
List<Coord> shortestPathToGoal = new ArrayList<>();
for (int y = 0; y < board.length; y++)
for (int x = 0; x < board[y].length; x++)
if (board[y][x] == '2'/*Start*/)
walk(board, y, x, 0, initVisited(board), new ArrayDeque<>(), shortestPathToGoal);
return shortestPathToGoal;
}
private static void walk(char[][] board, int y, int x, int keyRing, boolean[][] visited,
Deque<Coord> path, List<Coord> shortestPathToGoal) {
if (y < 0 || y >= board.length || x < 0 || x >= board[y].length || visited[y][x])
return; // outside board or already visited
char point = board[y][x];
if (point == '0'/*Water*/)
return; // cannot walk on water
if (point == '3'/*Goal*/) {
shortestPathToGoal.clear();
shortestPathToGoal.addAll(path);
shortestPathToGoal.add(new Coord(y, x));
return; // return to look for alternate shorter path
}
if (! shortestPathToGoal.isEmpty() && path.size() + 2 >= shortestPathToGoal.size())
return; // shorter (or equal) path already found
if (point >= 'A' && point <= 'Z') { // Door
if ((keyRing & (1 << (point - 'A'))) == 0)
return; // missing key
} else if (point >= 'a' && point <= 'z') { // Key
if ((keyRing & (1 << (point - 'a'))) == 0) {
keyRing |= (1 << (point - 'a')); // add key to keyring
visited = initVisited(board); // may now revisit previous steps
}
}
visited[y][x] = true;
path.addLast(new Coord(y, x));
walk(board, y , x + 1, keyRing, visited, path, shortestPathToGoal); // right
walk(board, y + 1, x , keyRing, visited, path, shortestPathToGoal); // down
walk(board, y , x - 1, keyRing, visited, path, shortestPathToGoal); // left
walk(board, y - 1, x , keyRing, visited, path, shortestPathToGoal); // up
path.removeLast();
visited[y][x] = false;
}
private static boolean[][] initVisited(char[][] board) {
boolean[][] visited = new boolean[board.length][];
for (int y = 0; y < board.length; y++)
visited[y] = new boolean[board[y].length];
return visited;
}
}
aW1wb3J0IGphdmEudXRpbC4qOwoKY2xhc3MgSWRlb25lIHsKCXB1YmxpYyBzdGF0aWMgdm9pZCBtYWluIChTdHJpbmdbXSBhcmdzKSB7CgkJY2hhcltdW10gYm9hcmQgPSB7eycwJywgJzInLCAnMScsICcxJywgJzEnfSwKCQkgICAgICAgICAgICAgICAgICB7JzAnLCAnMScsICcwJywgJzAnLCAnMSd9LAoJCSAgICAgICAgICAgICAgICAgIHsnMCcsICcwJywgJzAnLCAnMCcsICcxJ30sCgkJICAgICAgICAgICAgICAgICAgeycwJywgJzAnLCAnQScsICcwJywgJzEnfSwKCQkgICAgICAgICAgICAgICAgICB7JzEnLCAnMScsICdhJywgJzEnLCAnMSd9LAoJCSAgICAgICAgICAgICAgICAgIHsnMScsICdiJywgJzAnLCAnMCcsICdCJ30sCgkJICAgICAgICAgICAgICAgICAgeycxJywgJzEnLCAnMCcsICcwJywgJzEnfSwKCQkgICAgICAgICAgICAgICAgICB7JzAnLCAnMScsICcwJywgJzAnLCAnMyd9fTsKCQlTeXN0ZW0ub3V0LnByaW50bG4ocGF0aFRvU3RyaW5nKHNvbHZlKGJvYXJkKSkpOwoJfQoJcHJpdmF0ZSBzdGF0aWMgZmluYWwgY2xhc3MgQ29vcmQgewoJCWZpbmFsIGludCB5LCB4OwoJCUNvb3JkKGludCB5LCBpbnQgeCkgewoJCQl0aGlzLnkgPSB5OwoJCQl0aGlzLnggPSB4OwoJCX0KCQlAT3ZlcnJpZGUgcHVibGljIFN0cmluZyB0b1N0cmluZygpIHsKCQkJcmV0dXJuIFN0cmluZy52YWx1ZU9mKHRoaXMueSkuY29uY2F0KFN0cmluZy52YWx1ZU9mKHRoaXMueCkpOwoJCX0KCX0KCXByaXZhdGUgc3RhdGljIFN0cmluZyBwYXRoVG9TdHJpbmcoSXRlcmFibGU8Q29vcmQ+IHBhdGgpIHsKCQlTdHJpbmdKb2luZXIgam9pbmVyID0gbmV3IFN0cmluZ0pvaW5lcigiLT4iKTsKCQlmb3IgKENvb3JkIGNvb3JkIDogcGF0aCkKCQkJam9pbmVyLmFkZChjb29yZC50b1N0cmluZygpKTsKCQlyZXR1cm4gam9pbmVyLnRvU3RyaW5nKCk7Cgl9Cglwcml2YXRlIHN0YXRpYyBMaXN0PENvb3JkPiBzb2x2ZShjaGFyW11bXSBib2FyZCkgewoJCUxpc3Q8Q29vcmQ+IHNob3J0ZXN0UGF0aFRvR29hbCA9IG5ldyBBcnJheUxpc3Q8PigpOwoJCWZvciAoaW50IHkgPSAwOyB5IDwgYm9hcmQubGVuZ3RoOyB5KyspCgkJCWZvciAoaW50IHggPSAwOyB4IDwgYm9hcmRbeV0ubGVuZ3RoOyB4KyspCgkJCQlpZiAoYm9hcmRbeV1beF0gPT0gJzInLypTdGFydCovKQoJCQkJCXdhbGsoYm9hcmQsIHksIHgsIDAsIGluaXRWaXNpdGVkKGJvYXJkKSwgbmV3IEFycmF5RGVxdWU8PigpLCBzaG9ydGVzdFBhdGhUb0dvYWwpOwoJCXJldHVybiBzaG9ydGVzdFBhdGhUb0dvYWw7Cgl9Cglwcml2YXRlIHN0YXRpYyB2b2lkIHdhbGsoY2hhcltdW10gYm9hcmQsIGludCB5LCBpbnQgeCwgaW50IGtleVJpbmcsIGJvb2xlYW5bXVtdIHZpc2l0ZWQsCgkgICAgICAgICAgICAgICAgICAgICAgICAgRGVxdWU8Q29vcmQ+IHBhdGgsIExpc3Q8Q29vcmQ+IHNob3J0ZXN0UGF0aFRvR29hbCkgewoJCWlmICh5IDwgMCB8fCB5ID49IGJvYXJkLmxlbmd0aCB8fCB4IDwgMCB8fCB4ID49IGJvYXJkW3ldLmxlbmd0aCB8fCB2aXNpdGVkW3ldW3hdKQoJCQlyZXR1cm47IC8vIG91dHNpZGUgYm9hcmQgb3IgYWxyZWFkeSB2aXNpdGVkCgkJY2hhciBwb2ludCA9IGJvYXJkW3ldW3hdOwoJCWlmIChwb2ludCA9PSAnMCcvKldhdGVyKi8pCgkJCXJldHVybjsgLy8gY2Fubm90IHdhbGsgb24gd2F0ZXIKCQlpZiAocG9pbnQgPT0gJzMnLypHb2FsKi8pIHsKCQkJc2hvcnRlc3RQYXRoVG9Hb2FsLmNsZWFyKCk7CgkJCXNob3J0ZXN0UGF0aFRvR29hbC5hZGRBbGwocGF0aCk7CgkJCXNob3J0ZXN0UGF0aFRvR29hbC5hZGQobmV3IENvb3JkKHksIHgpKTsKCQkJcmV0dXJuOyAvLyByZXR1cm4gdG8gbG9vayBmb3IgYWx0ZXJuYXRlIHNob3J0ZXIgcGF0aAoJCX0KCQlpZiAoISBzaG9ydGVzdFBhdGhUb0dvYWwuaXNFbXB0eSgpICYmIHBhdGguc2l6ZSgpICsgMiA+PSBzaG9ydGVzdFBhdGhUb0dvYWwuc2l6ZSgpKQoJCQlyZXR1cm47IC8vIHNob3J0ZXIgKG9yIGVxdWFsKSBwYXRoIGFscmVhZHkgZm91bmQKCQlpZiAocG9pbnQgPj0gJ0EnICYmIHBvaW50IDw9ICdaJykgeyAvLyBEb29yCgkJCWlmICgoa2V5UmluZyAmICgxIDw8IChwb2ludCAtICdBJykpKSA9PSAwKQoJCQkJcmV0dXJuOyAvLyBtaXNzaW5nIGtleQoJCX0gZWxzZSBpZiAocG9pbnQgPj0gJ2EnICYmIHBvaW50IDw9ICd6JykgeyAvLyBLZXkKCQkJaWYgKChrZXlSaW5nICYgKDEgPDwgKHBvaW50IC0gJ2EnKSkpID09IDApIHsKCQkJCWtleVJpbmcgfD0gKDEgPDwgKHBvaW50IC0gJ2EnKSk7IC8vIGFkZCBrZXkgdG8ga2V5cmluZwoJCQkJdmlzaXRlZCA9IGluaXRWaXNpdGVkKGJvYXJkKTsgLy8gbWF5IG5vdyByZXZpc2l0IHByZXZpb3VzIHN0ZXBzCgkJCX0KCQl9CgkJdmlzaXRlZFt5XVt4XSA9IHRydWU7CgkJcGF0aC5hZGRMYXN0KG5ldyBDb29yZCh5LCB4KSk7CgkJd2Fsayhib2FyZCwgeSAgICAsIHggKyAxLCBrZXlSaW5nLCB2aXNpdGVkLCBwYXRoLCBzaG9ydGVzdFBhdGhUb0dvYWwpOyAvLyByaWdodAoJCXdhbGsoYm9hcmQsIHkgKyAxLCB4ICAgICwga2V5UmluZywgdmlzaXRlZCwgcGF0aCwgc2hvcnRlc3RQYXRoVG9Hb2FsKTsgLy8gZG93bgoJCXdhbGsoYm9hcmQsIHkgICAgLCB4IC0gMSwga2V5UmluZywgdmlzaXRlZCwgcGF0aCwgc2hvcnRlc3RQYXRoVG9Hb2FsKTsgLy8gbGVmdAoJCXdhbGsoYm9hcmQsIHkgLSAxLCB4ICAgICwga2V5UmluZywgdmlzaXRlZCwgcGF0aCwgc2hvcnRlc3RQYXRoVG9Hb2FsKTsgLy8gdXAKCQlwYXRoLnJlbW92ZUxhc3QoKTsKCQl2aXNpdGVkW3ldW3hdID0gZmFsc2U7Cgl9Cglwcml2YXRlIHN0YXRpYyBib29sZWFuW11bXSBpbml0VmlzaXRlZChjaGFyW11bXSBib2FyZCkgewoJCWJvb2xlYW5bXVtdIHZpc2l0ZWQgPSBuZXcgYm9vbGVhbltib2FyZC5sZW5ndGhdW107CgkJZm9yIChpbnQgeSA9IDA7IHkgPCBib2FyZC5sZW5ndGg7IHkrKykKCQkJdmlzaXRlZFt5XSA9IG5ldyBib29sZWFuW2JvYXJkW3ldLmxlbmd0aF07CgkJcmV0dXJuIHZpc2l0ZWQ7Cgl9Cn0=