min of knight's moves to get to a destination - java

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 !

Related

iterating through a 2d array and listing only 1s which are connected

Thank you for the replies...
Hi
i would need a function which takes a 2d array or map with filled with 0 and 1. where 1 represent the walkable ground and 0 is the wall. i need an algorithm which iterates trough the whole array where its walkable... and prints out only the walkable surface and the direction how it walks it trough.. something like in the attached file.
So far i managged to print the walkable surface of an array using flood fill, but didnt managed to print the directions.
Could you help me with that , i am working in Java
Am i on the right direction with flood fill? is it possible to print how the algorithm iterates trough the walkable surface?
I already have the output where the walkable path is changed from 1 to 2 s , but still need the direction printing....
The Code so far
class Solution {
private void dfs(int row, int col,
int[][] ans,
int[][] image,
int newColor, int delRow[], int delCol[],
int iniColor) {
ans[row][col] = newColor;
int n = image.length;
int m = image[0].length;
for(int i = 0;i<4;i++) {
int nrow = row + delRow[i];
int ncol = col + delCol[i];
if(nrow>=0 && nrow<n && ncol>=0 && ncol < m &&
image[nrow][ncol] == iniColor && ans[nrow][ncol] != newColor) {
dfs(nrow, ncol, ans, image, newColor, delRow, delCol, iniColor);
if(nrow == 1) {
System.out.println("Right");
}
if(nrow == -1) {
System.out.println("Left");
}
if(ncol == 1) {
System.out.println("Up");
}
if(ncol == -1) {
System.out.println("Down");
}
}
}
}
public int[][] floodFill(int[][] image, int sr, int sc, int newColor)
{
int iniColor = image[sr][sc];
int[][] ans = image;
int delRow[] = {-1, 0, +1, 0};
int delCol[] = {0, +1, 0, -1};
dfs(sr, sc, ans, image, newColor, delRow, delCol, iniColor);
return ans;
}
public static void main(String[] args)
{
int[][] image = {
{1,1,1,0,1,1},
{0,0,1,0,1,1},
{1,1,1,1,1,0},
{0,0,0,0,0,0},
{1,1,1,0,1,1}
};
Solution obj = new Solution();
int[][] ans = obj.floodFill(image, 0, 0, 2);
for(int i = 0; i < ans.length; i++){
for(int j = 0; j < ans[i].length; j++)
System.out.print(ans[i][j] + " ");
System.out.println();
}
}
}

Knight's tour in Java with rocks

I am working on the following problem:
Write a method that, given a chessboard with one knight, rocks on some of the squares, and a target position, indicates whether or not the knight can reach the target without landing on any rocks, and if so, the smallest number of moves needed by the knight to reach the target. The method should return the minimum number of moves needed to do so; otherwise, the method should return the value -1. (If the initial position has a rock on it, the method should return -1; likewise, if the target position has a rock on it, the method should return -1.)
You can see the code I've implemented so far below. My approach to rocks is to change the "coordinates" on the chessboard that have rocks as visited, so the knight can't revisit them, hence blocking his path(?).
My program compiles but doesn't return either minimum moves or -1. Any tips/different approaches to the problem are much appreciated. Thanks!!
PS: I'm ridiculously new to Java so apologies in advance for the messy code :)
import java.util.*;
public class Knight {
public static int numMoves( int dim, int xstart, int ystart, int xtarget,
int ytarget, int[] xrock, int[] yrock )
{
int result = -1;
List<Integer> knightPos = new ArrayList<>(Arrays.asList(xstart, ystart));
int [] targetPos = {xtarget, ytarget};
int dis = 0;
// x and y direction, where a knight can move
int[] dx = { -2, -1, 1, 2, -2, -1, 1, 2 };
int[] dy = { -1, -2, -2, -1, 1, 2, 2, 1 };
// queue for storing states of knight in board
Vector<cell> q = new Vector<>();
// push starting position of knight with 0 distance
q.add(new cell(knightPos.get(xstart), knightPos.get(ystart), dis));
cell t;
int x, y;
boolean[][] visit = new boolean[dim + 1][dim + 1];
// make all cell unvisited
for (int i = 1; i <= dim; i++) {
for (int j = 1; j <= dim; j++) {
visit[i][j] = false;
}
}
// visit starting state
visit[knightPos.set(0,xstart)][knightPos.set(1,ystart)] = true;
// visit rock squares
for (int i = 0; i < xrock.length;) {
for (int j = 0; j < yrock.length; ++i, ++j) {
visit[knightPos.get(i)][knightPos.get(j)] = true;
}
}
// loop until we have one element in queue
while (!q.isEmpty()) {
t = q.firstElement();
q.remove(0);
// if current cell is equal to target cell,
// return its distance
if (t.x == targetPos[0] && t.y == targetPos[1])
return t.dis;
// loop for all reachable states
for (int i = 0; i < 8; i++) {
x = t.x + dx[i];
y = t.y + dy[i];
// If reachable state is not yet visited and
// inside board, push that state into queue
if (isInside(x, y, dim) && !visit[x][y]) {
visit[x][y] = true;
q.add(new cell(x, y,dis + 1));
}
}
}
return result;
}
public static boolean isInside (int x, int y, int dim)
{
return x >= 0 && x <= dim && y >= 0 && y <= dim;
}
static class cell {
int x, y;
int dis;
public cell(int x, int y, int dis) {
this.x = x;
this.y = y;
this.dis = dis;
}
}
public static void main( String[] args )
{
}
}

How to make a knight randomly move in a chessboard?

I have this program called knight tour where the knight moves around a chess board. I have been trying to figure out how to make the knight move randomly, instead of following a pattern.
I would like to know how to randomly move the knight.
Here's my code:
package assignment3;
import java.util.Random;
/*
* knows its current position (row and column)
* knows the eight types of moves it can make
* can tell you it’s current row and column
* can determine whether a move of a given type is legal or not
* can move
*/
public class Knight {
private int boardSize = 8;
private int[] rowMoves = {-1, -2, -2, -1, 1, 2, 2, 1};
private int[] colMoves = {2, 1, -1, -2, -2, -1, 1, 2};
public Knight() {
//ignore this constructor
}
public void InitializeBoard() {
//initialize board
for (int i = 0; i < boardSize; i++)
Arrays.fill(chessboard2[i], Integer.MIN_VALUE); //setting array to negative value
}
/**
* calls method canMove to check if knight can move
* moves knight
*/
public boolean move(int moveNum, int x, int y, int[][] chessboard2) {
Random rand = new Random();
//if moveNum == 64 all squares have been visited
if (moveNum == 64) {
System.out.println("\ntrue board is 64\n");
return true;
}
//int nextRow = rand.nextInt(boardSize);
//int nextCol = rand.nextInt(boardSize);
//for loop to try 8 possibe moves
for (int i = 0; i < rowMoves.length; i++) {
int nextRow = x + rowMoves[i];
int nextCol = y + colMoves[i];
//check if postion is valid and not visited yet
if (canMove(nextRow, nextCol) && chessboard2[nextRow][nextCol] == Integer.MIN_VALUE) {
//if move is valid knight moves
chessboard2[nextRow][nextCol] = moveNum + 1;
//make next move
if(move(moveNum + 1, nextRow, nextCol, chessboard2))
return true;
//move(moveNum + 1, nextRow, nextCol);
//if cant find next move: backtrack
chessboard2[nextRow][nextCol] = Integer.MIN_VALUE;
}
}
return false;
}
/**
* calls method moveLegal from class Chessboard to see if move is legal
* #return true if move is legal, else return false
*/
public boolean canMove(int x, int y) {
//if statement to check if currentRow and currentCol is whithin
//boundaries
return(x >= 0 && x < boardSize && y >= 0 && y < boardSize);
}
public void print() {
for (int i = 0; i < boardSize; i++)
System.out.println(String.join(" ", chessboard2[i]));
}
public void solve() {
//setting array location [0][0] to 0
chessboard2[0][0] = 1;
//check move
if (move(1, 0, 0)) // if true, it will print chess board
print();
else //if false, there is no solution
System.out.print("no solution");
}
}
public class TesterMain {
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
Knight test = new Knight();
test.solve();
}
}
Sorry if my code is a bit messy, I am still working on the program.
There is a solution but it would require some refactoring:
Create a ChessMove class that stores a row and a column move (integers)
Add a ChessMove[] to store all possible moves that your knight can possibly do
Refactor the move method:
Create an ArrayList<ChessMove> that stores all possible moves that your knight can do in its current position
Randomly select a move in this list using rand.nextInt(possibleMoves.size());
Here is the complete code:
package assignment3;
import java.lang.*;
import java.util.*;
public class Knight {
private int boardSize = 8;
private int[][] chessboard2 = new int[boardSize][boardSize];
private final ChessMove[] moves = {
new ChessMove(-1, 2),
new ChessMove(-2, 1),
new ChessMove(-2, -1),
new ChessMove(-1, -2),
new ChessMove(1, -2),
new ChessMove(2, -1),
new ChessMove(2, 1),
new ChessMove(1, 2)
};
public Knight() {
initializeBoard();
}
public void initializeBoard() {
for (int i = 0; i < boardSize; i++)
Arrays.fill(chessboard2[i], Integer.MIN_VALUE); //setting array to negative value
}
public boolean move(int moveNum, int x, int y) {
//if moveNum == 64 all squares have been visited
if (moveNum == 64) {
System.out.println("\ntrue board is 64\n");
return true;
}
ArrayList<ChessMove> possibleMoves = new ArrayList<ChessMove>();
for (ChessMove move : moves) {
int nextRow = x + move.row;
int nextCol = y + move.col;
//check if postion is valid and not visited yet
if (canMove(nextRow, nextCol) && chessboard2[nextRow][nextCol] == Integer.MIN_VALUE)
possibleMoves.add(move);
}
if (!possibleMoves.isEmpty()) {
Random rand = new Random();
// Move choice is done here
ChessMove chosenMove = possibleMoves.get(rand.nextInt(possibleMoves.size()));
int nextRow = x + chosenMove.row;
int nextCol = y + chosenMove.col;
//if move is valid knight moves
chessboard2[nextRow][nextCol] = moveNum + 1;
//make next move
move(moveNum + 1, nextRow, nextCol);
return true;
} else
return false;
}
public boolean canMove(int x, int y) {
return (x >= 0 && x < boardSize && y >= 0 && y < boardSize);
}
public void print() {
for (int i = 0; i < boardSize; i++) {
for (int cell : chessboard2[i])
if (cell == Integer.MIN_VALUE)
System.out.print("*** ");
else
System.out.print(String.format("%3d", cell) + " ");
System.out.println();
}
}
public void solve() {
chessboard2[0][0] = 1;
if (move(1, 0, 0)) // if true, it will print chess board
print();
else //if false, there is no solution
System.out.print("no solution");
}
class ChessMove {
int row = 0, col = 0;
ChessMove(int r, int c) {
this.row = r;
this.col = c;
}
}
}
public class TesterMain {
public static void main(String[] args) {
Knight test = new Knight();
test.solve();
}
}
The easiest way to randomise your move is to create a list of valid moves for a given position of the knight and then select one at random. List and Random APIs go hand in hand:
//List<Integer> moves = ...
int move = moves.get(new Random().nextInt(moves.size()));
Restructuring your move method to something like this should do the job:
public boolean move(int moveNum, int x, int y, int [][] chessboard2) {
// 1. List all valid moves
List<Integer> validMoves = new ArrayList<Integer>();
//for loop to try 8 possibe moves
for(int i = 0; i < rowMoves.length; i++) {
if (
canMove(x + rowMoves[i], y + colMoves[i])
&& chessboard2[x + rowMoves[i]][y + colMoves[i]] == Integer.MIN_VALUE
) {
validMoves.add(i);
}
}
// 2. Try to make the move if any available
if (validMoves.isEmpty()) {
return false;
}
Random rand = new Random();
int move = validMoves.get(rand.nextInt(validMoves.size()));
int nextRow = x + rowMoves[move];
int nextCol = y + colMoves[move]:
chessboard2[nextRow][nextCol] = moveNumb + 1;
return move(moveNum + 1, nextRow, nextCol, chessboard2);
}
You can use an enum, let's call it Move, to represent every single move, and then make a list of these moves using Move.values().
Then you can shuffle the list with Collections.shuffle every time you want to move and take the first legal move.

How to DFS a 2D array to record paths from leftmost column to rightmost column?

Here I want to use DFS to traverse in a 2D array from leftmost column to rightmost column, each element can go to its upper right element or right element or lower right element. I need to record each possible path. For example, here I have:
1 2 3
4 5 6
7 8 9
Then the possible paths will be 123, 126, 153, 156, 159, 423, 426, 453, 456, 459, 486, 489, 753, 756, 759, 786, 789
Now my idea is straightforward backtrack:
public int findSolution(int[][] array) {
List<List<Integer>> availablePaths = new ArrayList<List<Integer>>();
for (int i = 0; i < array.length; i++) {
List<Integer> tempList = new ArrayList<Integer>();
dfs(array, availablePaths, tempList, 0, i);
}
int res = 0;
int min = Integer.MAX_VALUE;
for (List<Integer> path : availablePaths) {
min = Integer.MAX_VALUE;
for (Integer cur : path) {
if (cur < min) {
min = cur;
}
}
if (min > res) {
res = min;
}
}
return res;
}
public void dfs(int[][] array, List<List<Integer>> availablePaths, List<Integer> tempList, int curCol, int curRow) {
if (tempList.size() == array[0].length) {
availablePaths.add(new ArrayList<Integer>(tempList));
return;
}
tempList.add(array[curRow][curCol]);
int startRow;
int endRow;
// Next Column
if (curRow == 0) {
startRow = 0;
endRow = curRow+1;
} else if (curRow == array.length-1) {
startRow = curRow - 1;
endRow = curRow;
} else {
startRow = curRow - 1;
endRow = curRow + 1;
}
for (int i = startRow; i <= endRow; i++) {
dfs(array, availablePaths, tempList, curCol + 1, i);
tempList.remove(tempList.size()-1);
}
}
However, this can not work because of ArrayIndexOutOfBoundsException, so I guess my code has wrong idea.
Could someone give a solution to solve this problem?
The following DFS implementation solves your problem. I added your example as a test case as well.Basically, we start a new dfs on each cell on the first column. In each dfs call, as long as the current cell is in bound, we add it to the current path in a list. If the current cell is already the last column, add the path stored in the list to the final result.
The dx, dy arrays are a concise way of implementing the 3 possible moves.
import java.util.ArrayList;
import java.util.List;
public class Solution {
private static int[] dx = {-1,0,1}, dy = {1,1,1};
public static List<List<Integer>> dfsForAllPaths(int[][] grid) {
List<List<Integer>> res = new ArrayList<>();
if(grid == null) {
return res;
}
for(int i = 0; i < grid[0].length; i++) {
dfsHelper(grid, i, 0, res, new ArrayList<>());
}
return res;
}
private static void dfsHelper(int[][] grid, int x, int y, List<List<Integer>> res, List<Integer> list) {
if(!isInBound(grid, x, y)) {
return;
}
list.add(grid[x][y]);
if(y == grid[0].length - 1) {
res.add(new ArrayList<>(list));
}
for(int dir = 0; dir < 3; dir++) {
int newX = x + dx[dir], newY = y + dy[dir];
dfsHelper(grid, newX, newY, res, list);
}
list.remove(list.size() - 1);
}
private static boolean isInBound(int[][] grid, int x, int y) {
return x >= 0 && x < grid.length && y >= 0 && y < grid[0].length;
}
public static void main(String[] args) {
int[][] grid = {{1,2,3},{4,5,6},{7,8,9}};
List<List<Integer>> res = dfsForAllPaths(grid);
for(int i = 0; i < res.size(); i++) {
System.out.println(res.get(i));
}
}
}

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

Categories

Resources