Binary Maze with a Trick - java

The problem is a binary maze where 1's are walls and 0's are valid paths. You start from the top left (0,0) and you have to reach the bottom right (width -1, height -1). You have to find the shortest path from the top left to the bottom right. The twist comes in because you are allowed to remove one wall at most and this is the part that is confusing me. My current code can solve the shortest path without calculating for a wall being removed.
Here are a couple of examples:
[0,1,1,0], [0,0,0,1], [1,1,0,0], [1,1,1,0] Answer: 7 moves (including entrance and exit)
Example 2:
[0,0,0,0,0],[0,1,1,1,0],[1,0,0,0,0],[0,1,1,1,1],[0,1,1,1,1],[0,0,0,0,0] Answer: 11 (Because you can break the wall at position [0][1] to make the path shorter)
So like I said before my code will find the shortest path, but at the moment doesn't try to remove a wall for a shorter path, mostly because I dont understand how to. I was thinking that I remove one wall at a time and continually re-run to see if a shorter path is produced but this seems very costly operation, but it might get the job done. However, I was hoping that I could find a more clear and easier way to do so.
import java.util.*;
public class Maze {
public static void main(String [] args)
{
int[][] arr = new int[][] {
{0,0,0,0,0},
{1,1,1,1,0},
{0,0,0,0,0},
{0,1,1,1,1},
{0,1,1,1,1},
{0,0,0,0,0},
};
answer(arr);
}
public static int answer(int[][] maze) {
maze[maze.length-1][maze[0].length -1] = 9;
Point p = getPathBFS(0,0,maze);
int length = 1;
while(p.getParent() != null) {
p = p.getParent();
length++;
}
System.out.println(length);
return length;
}
private static class Point {
int x;
int y;
Point parent;
public Point(int x, int y, Point parent) {
this.x = x;
this.y = y;
this.parent = parent;
}
public Point getParent() {
return this.parent;
}
}
public static Queue<Point> q = new LinkedList<Point>();
public static Point getPathBFS(int x, int y,int[][] arr) {
q.add(new Point(x,y, null));
while(!q.isEmpty()) {
Point p = q.remove();
if (arr[p.x][p.y] == 9) {
return p;
}
if(isFree(p.x+1,p.y,arr)) {
arr[p.x][p.y] = -1;
Point nextP = new Point(p.x+1,p.y, p);
q.add(nextP);
}
if(isFree(p.x-1,p.y,arr)) {
arr[p.x][p.y] = -1;
Point nextP = new Point(p.x-1,p.y, p);
q.add(nextP);
}
if(isFree(p.x,p.y+1,arr)) {
arr[p.x][p.y] = -1;
Point nextP = new Point(p.x,p.y+1, p);
q.add(nextP);
}
if(isFree(p.x,p.y-1,arr)) {
arr[p.x][p.y] = -1;
Point nextP = new Point(p.x,p.y-1, p);
q.add(nextP);
}
}
return null;
}
public static boolean isFree(int x, int y,int[][] arr) {
if((x >= 0 && x < arr.length) && (y >= 0 && y < arr[x].length) && (arr[x][y] == 0 || arr[x][y] == 9)) {
return true;
}
return false;
}
}

The thing to notice is the fact that shortest path through the maze with removing a section consists of two shortest paths - from entrance to removed section and then from removed section to exit.
You can use BFS to calculate distances of all positions in the maze from the starting location and distances of all positions from ending location.
Then you can find a position for which the sum of distances to entrance and to exit is minimal. If it is a wall section then it is the section to remove. Otherwise, removing any section is not useful.
Overall, this solution runs in linear time.

You use a Point class to represent the position of the player as he walks through the maze. Without the wall rule, this position is all you need to know about the player to determine what he can do next, and so you can do BFS on the directed graph of all possible positions to find the path.
With the wall rule, in order to determine where the player can go next, you also have to know whether or not he has already removed a wall, so the full state of the player includes not only his position, but also a boolean that indicates whether or not a wall has been removed.
You can then do BFS on the graph of these expanded states to find the shortest path with at most one wall removed.
Since you've posted your actual code for the simpler problem, I'll just fix it up with the expanded state (and a Set to keep you from visiting the same state twice, instead of modifying arr):
import java.util.*;
public class Maze {
public static void main(String [] args)
{
int[][] arr = new int[][] {
{0,0,0,0,0},
{1,1,1,1,0},
{0,0,0,0,0},
{0,1,1,1,1},
{0,1,1,1,1},
{0,0,0,0,0},
};
answer(arr);
}
public static int answer(int[][] maze) {
maze[maze.length-1][maze[0].length -1] = 9;
State p = getPathBFS(0,0,maze);
int length = 1;
while(p.getParent() != null) {
p = p.getParent();
length++;
}
System.out.println(length);
return length;
}
private static class State {
int x;
int y;
boolean wallRemoved;
State parent;
public State(int x, int y, boolean wallRemoved, State parent) {
this.x = x;
this.y = y;
this.wallRemoved = wallRemoved;
this.parent = parent;
}
public State getParent() {
return this.parent;
}
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + (wallRemoved ? 1231 : 1237);
result = prime * result + x;
result = prime * result + y;
return result;
}
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null ||getClass() != obj.getClass())
return false;
State other = (State) obj;
if (wallRemoved != other.wallRemoved)
return false;
if (x != other.x)
return false;
if (y != other.y)
return false;
return true;
}
}
public static Queue<State> q = new LinkedList<>();
public static HashSet<State> seen = new HashSet<>();
public static State getPathBFS(int x, int y,int[][] arr) {
q.add(new State(x,y,false, null));
while(!q.isEmpty()) {
State p = q.remove();
if (arr[p.x][p.y] == 9) {
return p;
}
tryNext(p,p.x+1,p.y,arr);
tryNext(p,p.x-1,p.y,arr);
tryNext(p,p.x,p.y+1,arr);
tryNext(p,p.x,p.y-1,arr);
}
return null;
}
public static void tryNext(State p, int x, int y, int[][]arr) {
if (x<0 || y<0 || x>=arr.length || y>=arr[x].length)
return;
State newState;
if (arr[x][y] == 0 || arr[x][y]==9) {
newState = new State(x, y, p.wallRemoved, p);
} else if (!p.wallRemoved) {
newState = new State(x, y, true, p);
} else {
return;
}
if (seen.add(newState)) {
q.add(newState);
}
}
}

Related

Give a list of bomb, each mine has 3 numbers, x, y coordinates and explosion range. Find the initial mine that can eventually detonate the most mines

Give a list of mines, each mine contains 3 numbers, x, y coordinates and explosion range . Find the initial mine that can eventually detonate the most mines and maximum number of mine it denotes.
the x, y coordinates can be negative numbers and all three numbers can be double.
I coded a dfs solution but got incorrect result. Does it seem like an ok implementation . Any inputs will be helpful.
List<Node> list;
RadiusBlast(List<Node> list){
this.list = list;
}
static boolean isInside(int circle_x, int circle_y,
int rad, int x, int y)
{
// Compare radius of circle with
// distance of its center from
// given point
//System.out.println("source:"+ circle_x + "," + circle_y);
if ((x - circle_x) * (x - circle_x) +
(y - circle_y) * (y - circle_y) <= rad * rad) {
//System.out.println("isInside:"+ x + "," + y);
return true;
}
else
return false;
}
public int dfs2(int i,Node node,boolean[] visited) {
//System.out.println("dfs");
visited[i] = true;
int res = 1;
for(Node newNode : list){
if(!visited[newNode.index]) {
if (isInside(node.x, node.y, node.r, newNode.x, newNode.y))
res += dfs2(newNode.index,node,visited);
}
}
return res;
}
static class Node{
int x,y,r ;
int index;
boolean depthvisited;
//boolean visited;
public Node(int x, int y, int r,int index) {
this.x = x;
this.y = y;
this.r = r;
this.index = index;
}
}
// Driver Program to test above function
public static void main(String arg[])
{
//RadiusBlast r = new RadiusBlast();
int x = -1, y = 3;
x = 2 ; y = 3;
int x1 = 2 ; int y2 = 3 ;
int circle_x = 0, circle_y = 7, rad = 5;
if (isInside(circle_x, circle_y, rad, x, y))
System.out.println("Inside1 main");
else
System.out.println("Outside");
if (isInside(circle_x, circle_y, rad, x1, y2))
System.out.println("Inside2 main");
else
System.out.println("Outside ");
//x1, y1, r1
// 2,3,3
// -1,3,2
// 3,2,5
List<Node> list = new ArrayList<Node>();
list.add(new Node(2,3,3,0));
list.add(new Node(2,3,1,1));
list.add(new Node(0,7,5,2));
boolean[] visited;
RadiusBlast r = new RadiusBlast(list);
int res =0 ;
for(int i =0; i < list.size(); i++){
visited = new boolean[list.size()];
res = Math.max(res,r.dfs2(list.get(i).index,list.get(i),visited));
//System.out.println("res:" + (res));
}
System.out.println("result:" + (res - 1));
}
Iterate over mines list and explode each mine recursively. Collect exploded count and pick maximum one. Something like this:
public class Test {
public static void main(String[] args) throws Exception {
List<Node> list = new ArrayList<Node>();
list.add(new Node(2, 3, 3, 0));
list.add(new Node(2, 3, 1, 1));
list.add(new Node(0, 7, 5, 2));
System.out.println("Deadliest node is: " + findDeadliest(list).index);
}
public static Node findDeadliest(List<Node> mines) {
Node result = mines.get(0);
for(Node n : mines) {
List<Node> exploded = new ArrayList<>();
explode(n, mines, exploded);
n.triggeredCount = exploded.size();
result = (n.triggeredCount > result.triggeredCount) ? n : result;
}
return result;
}
public static void explode(Node mine, List<Node> mines, List<Node> exploded){
for(Node target: mines) {
if(!exploded.contains(target)) {
if(isInside(mine, target)) {
exploded.add(target);
explode(target, mines, exploded);
}
}
}
}
static boolean isInside(Node s, Node t) {
double d = Math.pow(s.r,2) - ( Math.pow(s.x-t.x, 2) + Math.pow(s.y-t.y, 2));
return d>0;
}
}
class Node {
#Override
public int hashCode() {
return this.index;
}
#Override
public boolean equals(Object obj) {
if(obj instanceof Node) {
return this.index == ((Node)obj).index;
}
return false;
}
int x, y, r;
int index;
int triggeredCount;
public Node(int x, int y, int r, int index) {
this.x = x;
this.y = y;
this.r = r;
this.index = index;
}
}
Output:
Deadliest node is: 2
Modify the code as per your needs. Do the null checks and error handling.
There might be some improvements to search with memorization in this problem - we don't really need to search again if the detonated bombs have been calculated before.
memory = [-1] * N
visited = [False] * N
def count_explosion(source):
if memory[source] != -1:
return memory[source]
accu = 1
visited[source] = True
for k in range(N):
if source == k:
continue
if adjacent[source][k] and not visited[k]:
if memory[k] != -1:
accu += memory[k]
else:
accu += count_explosion(k)
memory[source] = accu
return accu
max_num = 1
for i in range(N):
max_num = max(max_num, count_explosion(i))
return max_num
Note the adjacent is the matrix to store the directed graph, where we pre-process using the euclidean distance. We need a visited here as well to avoid cyclic cases.

min of knight's moves to get to a destination

I'm trying to solve this challenge which is to get the min cost of Knight's moves from a source to a destination in a (8*8) chess board and I'm getting a case that not working … I guess I messed up somewhere and I cant figure that out.
see image here
the full code
import java.util.ArrayList;
import java.util.List;
public class Solution {
static class Position{
public int x;
public int y;
public Position(int x, int y) {
this.x = x;
this.y = y;
}
}
public static int solution(int src, int dest) {
int min = 100000000;
int depth = 0;
Position source = new Position(0, 0), destination = new Position(0, 0);
int [][] board = getBoard(src, dest, source, destination);
if(arrived(source, destination)) return 0;
return solve(board, source, destination, (depth), min);
}
public static int[][] getBoard(int src, int dest, Position source, Position destination) {
int c = 0;
int [][] board = new int[8][8];
for(int i = 0; i < board.length; i++){
for(int j = 0; j < board.length; j++){
if(c == src) {
board[i][j] = 1;
source.x = i;
source.y = j;
}else if(c == dest) {
board[i][j] = -1;
destination.x = i;
destination.y = j;
}else {
board[i][j] = 0;
}
c++;
}
}
return board;
}
public static int solve(int[][] board, Position position, Position destination, int depth, int min){
if(depth > min) {
return depth;
}
for(Position p: sort(getPossibleMoves(board, position), destination)){
if(arrived(p,destination)) {
return depth + 1;
}
board[p.x][p.y] = depth +2;
int cost = solve(board, p, destination, (depth + 1), min);
board[p.x][p.y] = 0;
if(cost < min){
min = cost;
}
}
return min;
}
public static List<Position> sort(List<Position> positions, Position dest) {
Position temp;
boolean sorted = false;
while(!sorted) {
sorted = true;
for(int i = 0; i < positions.size() - 1; i++) {
if(distance(positions.get(i), dest) > distance(positions.get(i+1), dest)) {
temp = positions.get(i);
positions.set(i, positions.get(i+1));
positions.set(i+1, temp);
sorted = false;
}
}
}
return positions;
}
public static double distance(Position a, Position b) {
if(a.x == b.x && a.y == b.y) return 0;
return Math.sqrt(Math.pow(a.x - b.x, 2) + Math.pow(a.y - b.y, 2));
}
public static boolean arrived(Position src, Position dest) {
return src.x == dest.x && src.y == dest.y;
}
public static List<Position> getPossibleMoves(int [][] board, Position current){
int [][] moves = {{1,2}, {2,1}, {-1,2}, {1,-2}, {-2,1}, {2,-1}, {-1,-2}, {-2,-1}};
List<Position> positions = new ArrayList();
for(int i = 0; i < moves.length; i++) {
int x = current.x + moves[i][0];
int y = current.y + moves[i][1];
if(x >= 0 && y >= 0 && x < board.length && y < board.length && board[x][y] <= 0)
positions.add(new Position(x, y));
}
return positions;
}
public static void main(String [] args) {
System.out.println(solution(0, 1));
}
}
so here is my approach :
we start from a position and we try all the possible moves (sorted by the nearest) till we find the destination and then do some kind of backtracking to see if there's a better way to get there at a low cost and return the minimum.
some rules I've set :
the board is represented by a matrix of integers ( full of zeros if empty)
the source is represented by 1
the destination is represented by -1
wherever the knight goes its going to be marked by an integer representing the cost (the start is 1 the second move will be 2 , third 3 and so on …)
let me break the code a little bit down to make it easier
we start from the function solution public static int solution(int src, int dest) which will initialize the board, set the source and destinatin positions, and return the cost using the solve(board, source, destination, (depth), min) function
the function public static int[][] getBoard(int src, int dest, Position source, Position destination) take the board, position … look trough all possible moves ( unmarked positions and sorted by the nearest) for that position and call recursively with a new position until it found the destination or the depth (witch is the cost) is bigger then the minimum that we already have
the function public static List<Position> getPossibleMoves(int [][] board, Position current) will return the 8 possible moves for knight from a position but only those who are not out of the board and are also unvisited ( unvisited will be 0 or -1 for the destination )
the function public static List<Position> sort(List<Position> positions, Position dest) will sort the possible moves by the nearest to the destination ( let's prioritize the nearest one)
please if you can help me figure out what's wrong or if you have another approach I'd really appreciate !

Java 2D Array Specific Move

I have made a class where a 6x10 2D array is generated to act as a board.
A random starting location is then generated in the constructor.I only want adjacent moves to be possible.
For example, if the random location has been generated as (2,3) then for example the user enters (1,2) it would be a valid move, but (6,1) would be an invalid move.
Then if the user enters say (1,2), they can then go to any adjacent cell from (1,2).
I have included the class below, and the adjacent method I tried to make to test it, but I'm a bit confused on how I am approaching this.
import java.util.Arrays;
import java.util.Random;
public class Test {
public static final int ROWS = 6;
public static final int COLUMNS = 10;
public int[][] board;
public static void main(String[] args)
{
Test t = new Test();
t.getBoard();
t.makeMove(6,1); //I want this to be an invalid move.
t.getBoard();
t.makeMove(1,2); // this should be a valid move
t.getBoard();
}
public Test()
{
board = new int[ROWS][COLUMNS];
createRandomLocation();
}
public void createRandomLocation()
{
Random rand = new Random();
int x = rand.nextInt(6);
int y = rand.nextInt(10);
board[x][y] = 1;
}
public void makeMove(int x,int y){
if (Math.abs(x-cur_x)==0 || Math.abs(y-cur_y)==0) {
board[x][y] = 1;
}
public String getBoard() {
for (int i = 0; i < board.length; i++) {
for (int j = 0; j < board[i].length; j++) {
System.out.print(board[i][j] + " ");
}
System.out.println();
}
System.out.println();
return Arrays.deepToString(board);
}
}
Adjacent:
/*public boolean isMoveAllowed(int [][] array,int x, int y){
boolean adjacent = false;
int trueCount = 0;
if(array[x-1][y-1] == 0) trueCount++; //topleft
if(array[x-1][y] == 0) trueCount++; //top
if(array[x-1][y+1] == 0) trueCount++;//topright
if(array[x][y+1] == 0) trueCount++;//right
if(array[x][y-1] == 0) trueCount++;//left
if(array[x+1][y-1] == 0) trueCount++;//bottomleft
if(array[x+1][y] == 0) trueCount++;//bottom
if(array[x+1][y+1] == 0) trueCount++; //bottomright
if (trueCount == 8)
{
adjacent = true;
}
return adjacent;
}*/
Your problem description has the answer baked into it already. You want any move from (a,b) to (c,d) to be legal if the distance between a and c, and b and d, is zero or one. So if you see Math.abs(a-c)>1, that's an illegal move. So: have the current position stored in some variables, and compare them to the desired new location:
public static void main(String[] args)
{
Board b = new Board(6, 10);
try {
b.tryMove(6,1);
} catch(IllegalMoveException e) {
// do whatever you need to do to inform the user that move is illegal
}
}
With the Board class responsible for tracking coordinates:
class Board {
protected int cur_x, cur_y, rows, cols;
public Board(int rows, int cols) {
this.rows = rows;
this.cols = cols;
this.setRandomPosition();
}
public void setRandomPosition() {
cur_x = (int) Math.round(Math.random() * cols);
cur_y = (int) Math.round(Math.random() * rows);
}
public void tryMove(int x, int y) throws IllegalMoveException {
if (Math.abs(x-cur_x)>1 || Math.abs(y-cur_y)>1) {
throw new IllegalMoveException(...);
}
// bounds check omitted here, but: ensure that
// 0<=x<cols and 0<=y<rows, otherwise throw an
// IllegalMoveException as well.
cur_x = x;
cur_y = y;
}
// with getters for the current x and y, etc.
}
It would be much easier to test for a true case rather than a false case like you currently have, the isMoveAllowed method should look something like this:
public boolean isMoveAllowed(int[][] array, int x, int y) {
return ((array[x + 1][y] == 1) ||
(array[x - 1][y] == 1) ||
(array[x][y + 1] == 1) ||
(array[x][y - 1] == 1));
}
This will return true if the move is adjacent to the current player position

Why is is my TreeMap not sorted correctly?

import java.util.TreeMap;
class Point implements Comparable<Point>{
private int x, y;
public Point(int x, int y) {
this.x = x;
this.y = y;
}
#Override
public boolean equals(Object arg0) {
Point p = (Point) arg0;
return (this.x == p.x && this.y == p.y);
}
#Override
public String toString() {
return "("+x+", "+y+")";
}
#Override
public int compareTo(Point arg0) {
if(this.x == arg0.x && this.y == arg0.y)
return 0;
return -1;
}
}
public class Test {
static int row, col;
static TreeMap<Point, Integer> dist;
public static void main(String[] args) {
dist = new TreeMap<>();
row = 4;
col = 7;
for(int i=0; i<row; i++){
for(int j=0; j<col; j++){
Point p = new Point(i, j);
dist.put(p, Integer.MAX_VALUE);
}
if(i >= 1)
System.out.println(i+": "+dist.keySet().contains(new Point(1, 5)));
}
}
}
The output should be:
1: true
2: true
3: true
but its coming
1: true
2: false
3: false
can some one please explain why is this output coming?
this code is working fine if i am taking predefined data types
as key to the map.
can some one please explain why is this output coming?
this code is working fine if i am taking predefined data types
as key to the map.
Your compareTo is not transitive anti-symmetric. See here for more detail.
#Override
public int compareTo(Point arg0) {
if(this.x == arg0.x && this.y == arg0.y)
return 0;
return -1;
}
When a!=b, a.compareTo(b) returns -1, but b.compareTo(a) also returns -1. This leads to incorrect sorting.
As #RobAu points out, the problem is your compareTo method. Note the documentation of that method:
Returns a negative integer, zero, or a positive integer as this object
is less than, equal to, or greater than the specified object.
You need to modify your code to allow for proper comparison between points, that is, you have to come up with some ordering for points. For instance, here is an alternative implementation that works:
#Override
public int compareTo(Point arg0) {
int ret = Integer.compare(x, arg0.x);
if (ret == 0) {
ret = Integer.compare(y, arg0.y);
}
return ret;
}

Java - How to find for a value of a variable inside an object which belongs to an Array of objects?

I would like to ask how do we find the element in an array with the value of a variable inside the element? Is it possible? If so, please do tell. Suppose we have an object called Pt:
public class Pt {
private int x, y;
public void setCoords(int i, int j){
x = i;
y = j;
}
public int getX(){
return x;
}
public int getY(){
return y;
}
}
Then we create an Array of Pt object and also initialize it's elements.
Pt[] point;
point[0].setCoords(0,0);
point[1].setCoords(1,1);
The problem that I am having now is how do I find the element with the coordinates (1,1)?
You just need to loop through the array and check each of the elements. To loop through the array, you can use an enhanced for loop.
for (Pt pt : point) {
if(pt.getX() == 1 && pt.getY() == 1){
//what you want to do with the object...
break;
}
}
public static void main(String[] args) {
Pt[] point = new Pt[2];
Pt pt1 = new Pt();
pt1.setCoords(0, 0);
Pt pt2 = new Pt();
pt2.setCoords(1, 1);
point[0] = pt1;
point[1] = pt2;
getElement(point, 1, 1); // returns element with coords of (1, 1) or null if doesn't exist
}
public static Pt getElement(Pt[] point, int xCoord, int yCoord) {
for (int i = 0; i < point.length; i++) {
if (point[i].getX() == xCoord && point[i].getY() == yCoord) {
return point[i];
}
}
return null;
}

Categories

Resources