The problem is:
Given exact k steps, how many ways to move a point from start point to destination? Point can move for eight directions(horizontally, vertically, diagonally, anti-diagonally).
I solved the problem through DP, but it works only for square board, not for rectangle board. I mean if dim[0]!=dim[1] in the code, it will run into an error result.
Here I can provide test case:
Test case 1
dim = {5,6},start = {0,2},end = {2,2},steps = 4;
result is 50(expected: 105)
Test case 2
dim = {5,5},int[] start = {0,2},end = {2,2},steps = 4;
result is 105(expected: 105)
Here is the code:
private static int[][] dir = {{0,1},{1,0},{1,1},{1,-1},{0,-1},{-1,0},{-1,-1},{-1,1}};
//DP
/*
#param dim, a tuple (width, height) of the dimensions of the board
#param start, a tuple (x, y) of the king's starting coordinate
#param target, a tuple (x, y) of the king's destination
*/
public static int countPaths2(int[] dim, int[] start, int[] des, int steps){
if(dim[0] == 0 || dim[1] == 0) return 0;
int[][][] dp = new int[dim[0]*dim[1]][dim[1]*dim[0]][steps+1];
for(int step = 0; step<=steps;step++){
for(int i = 0; i< dim[0]*dim[1];i++){
for(int j = 0; j< dim[0]*dim[1];j++){
if(step == 0 && i == j){
dp[i][j][step] = 1;
}
if(step >= 1){
for(int k =0; k< dir.length;k++){
int row = i / dim[0];
int col = i % dim[1];
if(row + dir[k][0] >= 0 && row + dir[k][0]< dim[0] && col + dir[k][1]>=0 && col + dir[k][1]< dim[1]){
int adj = (row + dir[k][0])*dim[0] + col + dir[k][1];
dp[i][j][step] += dp[adj][j][step-1];
}
}
}
}
}
}
int startPos = start[0]*dim[0] + start[1];
int targetPos = des[0]*dim[0] + des[1];
return dp[startPos][targetPos][steps];
}
public static void main(String[] args){
int[] dim = {5,5}; // can just use to square;
int[] start = {0,2};
int[] end = {2,2};
int steps = 7;
System.out.println(countPaths2(dim, start,end, steps));
}
How could I make it work for any kind of board?
The culprit is:
int row = i / dim[0];
int col = i % dim[1]; // <- this should have been dim[0]
in the div/mod pattern you are supposed to divide and modulo by the same number...
Related
I have an assignment to have a knight move around the chessboard until it either completes a full tour or has no where else to go.
im having a problem figuring out how to have it actually stop after there are no more moves. I have the algorithm for the movement down, as well as bounds checking on the chessboard.
setting the loop count to 64 just times out, because the program will try to continually find a spot that doesn't exist if a perfect tour isn't created.
two ideas I have had to fix this is to either increment a variable every time a certain position is checked around a certain spot, and if all possible moves are taken by a previous move, terminate the program. Problem is I have no idea how to actually do this.
A second idea I had is to have the program quit the for loop after 2 seconds(during which the for loop will check each position way more than once) but I feel like my professor would crucify me upside down if I did that
here is my code:
import apcslib.*; //this is only for Format()
public class ktour
{
int[][] kboard = new int[9][9];
int[] vert = new int[9];
int[] horiz = new int[9];
ktour()
{
vert[1] = -2;vert[2] = -1;vert[3] = 1;vert[4] = 2;vert[5] = 2;vert[6] = 1;vert[7] = -1;vert[8] = -2;
horiz[1] = 1;horiz[2] = 2;horiz[3] = 2;horiz[4] = 1;horiz[5] = -1;horiz[6] = -2;horiz[7] = -2;horiz[8] = -1;
path();
}
public void path()
{
int row = 1;
int col = 1;
int loops = 10; //i have this set to 10 for now
int col2 = 1;
int row2 = 1;
int r = (int)(Math.random() * (8) +1); //returns a random from 1 to 9
//System.out.println(r);
kboard[col][row] = 1;
for(int x = 2; x < loops; x++) //this runs the bounds check and places each number for the amount that loops is
{
r = (int)(Math.random() * (8) +1);
col = col2;
row = row2;
col = col + vert[r];
row = row + horiz[r];
while(col <= 0 || col > 8 || row <= 0 || row > 8) //bounds check, will keep running until both row and columb is in the board
{
r = (int)(Math.random() * (8) + 1);
col = col2;
row = row2;
col = col + vert[r];
row = row + horiz[r];
}
if(kboard[col][row] == 0)
{
kboard[col][row] = x;
row2 = row;
col2 = col;
}
else
{
x--; //if the above if is false and a number already occupies the generated spot, x is decremented and the program tries again
}
}
printboard();
}
public void printboard()
{
for(int y = 1; y < 9; y++)
{
System.out.println();
for(int x = 1; x < 9; x++)
{
System.out.print(Format.right(kboard[y][x],3));
}
}
}
}
I was able to fix my lab with the following code. I created a variable called count which I used to check if at any move there were no more moves left. As there are only 8 moves, when the variable reached 9 the code terminated, and printed up to the point it got to.
I had to put multiple if statements excluding r = math.random if count was not 0, meaning I was checking r 1-9, aka every possible move. Therefore, I couldn't use a randomizer, I had to traverse all 8 possible moves.
I also ran into problems when I reached the line where it checks if kboard[col][row] == 0. if you were running through a loop with count greater than 1, it was possible that col or row could be out of bounds, due to lack of a randomizer in the bounds checker. If left without a break, the bounds checker would run forever without a random number generated every time. I fixed this by adding an if statement that allowed the program to proceed if col and row were inside the board. if they were not, x was decremented and count was increased again, signifying a failed attempt.
This way I was able to check all possible moves, disregarding whether or not they were inside the board.
public void path()
{
int row = 1;
int col = 1;
int loops = 64; //i have this set to 10 for now
int col2 = 1;
int row2 = 1;
int count = 0;
boolean end = false;
int r = (int)(Math.random() * (8) +1); //returns a random from 1 to 9
//System.out.println(r);
kboard[col][row] = 1;
for(int x = 2; x < loops; x++) //this runs the bounds check and places each number for the amount that loops is
{
if(count == 0)
r = (int)(Math.random() * (8) +1);
if(count >= 1 && r != 8)
r++;
col = col2;
row = row2;
col = col + vert[r];
row = row + horiz[r];
while(col <= 0 || col > 8 || row <= 0 || row > 8) //bounds check, will keep running until both row and columb is in the board
{
if(count == 0)
r = (int)(Math.random() * (8) + 1);
col = col2;
row = row2;
col = col + vert[r];
row = row + horiz[r];
if(count >= 1)
break;
}
end = false;
if(r == 8 || r == 9)
r = 1;
if(count >= 9)
{
System.out.println("Halting... no where else to go");
loops = 0;
}
if(!(col <= 0 || row <= 0 || row > 8 || col > 8))
{
if(kboard[col][row] == 0)
{
kboard[col][row] = x;
row2 = row;
col2 = col;
count = 0;
}
else
{
count++;
x--; //if the above if is false and a number already occupies the generated spot, x is decremented and the program tries again
}
}
else
{
count++;
x--;
}
}
printboard();
}
I have this class that randomly creates rooms next to each other, and prints brackets (which represent the rooms) to the console. But I wanted to know how to add something like that to a JPanel for a GUI. Here is the room generator class:
public class Rooms {
static final int width = 15, height = 10;
static final int rooms = 19;
static boolean[][] room = new boolean[width][height];
static int neighborCount(int x, int y) {
int n = 0;
if (x > 0 && room[x-1][y]) n++;
if (y > 0 && room[x][y-1]) n++;
if (x < width-1 && room[x+1][y]) n++;
if (y < height-1 && room[x][y+1]) n++;
return n;
}
public void Rooms() {
room[width/2][height/2] = true;
Random r = new Random();
int x, y, nc;
for (int i = 0; i < rooms; i++) {
while (true) {
x = r.nextInt(width);
y = r.nextInt(height);
nc = neighborCount(x, y);
if (!room[x][y] && nc == 1) break;
}
room[x][y] = true;
}
for (y = 0; y < height; y++) {
for (x = 0; x < width; x++)
System.out.print(room[x][y] ? "[]" : " ");
System.out.print();
}
}
}
Thanks for the help!
You probably want to use java.awt.Graphics. It lets you draw primitive shapes like lines, rectangles, circles, etc. This might get you started. Section 2 also covers how to draw on a JPanel.
I am having some issues with the following code. First I cant seem to figure how to stop the piece from going out of bounds. Second when the code does work its not adding the count the steps correctly.
package runknightstour;
public class RunKnightsTour
{
public static void main(String[] args)
{
KnightMoves tour = new KnightMoves();
tour.runTour();
}
}
package runknightstour;
public class ChessBoard
{
public final int ROWS = 8;
public final int COLS = 8;
public final int FRAMESIZE = 12;
private int[][] board = new int[FRAMESIZE][FRAMESIZE];
public ChessBoard()
{
for (int y = 0; y < board.length; y++) {
for (int x = 0; x < board[y].length; x++) {
board[y][x] = -1;
}
for (int r = 2; r < ROWS + 2; r++) {
for (int c = 2; c < COLS + 2; c++) {
board[r][c] = 0;
}
}
}
}
public String toString()
{
String output = "";
for (int r = 0; r < FRAMESIZE; r++) {
for (int c = 0; c < FRAMESIZE; c++) {
output += board[r][c];
output += "\t";
}
output += "\n\n";
}
return output;
}
/**
*
* #param row
* #param col
* #param inStep in the range of 1 - 64
*/
public void setSquare(int row, int col, int inStep)
{
// adjust input to match 2 - 9
row += 1;
col +=1;
if (row > 1 && row < 10 && col > 1 && col < 10)
{
board[row][col] = inStep;
}
}
public int getSquare (int row, int col)
{
return board[row][col];
}
}
package runknightstour;
import java.util.Random;
import java.util.Scanner;
public class KnightMoves
{
public final int COMPLETE_TOUR = 64;
private ChessBoard kBoard = new ChessBoard();
private int[][] moves = new int[8][2];
private int stepNumber;
private int currentRow;
private int currentCol;
private int startRow;
private int startCol;
public KnightMoves()
{
moves[0][0] = -2; // move 0 row offset
moves[0][1] = 1; // move 0 col offset
moves[1][0] = -1; // move 1 row offset
moves[1][1] = 2; // move 1 col offset
moves[2][0] = 1; // move 2 row offset
moves[2][1] = 2; // move 2 col offset
moves[3][0] = 2; // move 3 row offset
moves[3][1] = 1; // move 3 col offset
moves[4][0] = 2; // move 4 row offset
moves[4][1] = -1; // move 4 col offset
moves[5][0] = 1; // move 5 row offset
moves[5][1] = -2; // move 5 col offset
moves[6][0] = -1; // move 6 row offset
moves[6][1] = -2; // move 6 col offset
moves[7][0] = -2; // move 7 row offset
moves[7][1] = -1; // move 7 col offset
stepNumber = 0;
startRow = startCol = 1;
currentRow = currentCol = 1;
}
/**
* Description: Get the starting board Position (row, col) for the
* KNIGHT from program user
*/
public void getStartPosition()
{
Scanner input = new Scanner(System.in);
System.out.print("\n enter a starting location for the knight's row ");
startRow = input.nextInt();
System.out.print("\n enter a starting location for the knight's col ");
startCol = input.nextInt();
kBoard.setSquare(startRow, startCol, 1);
System.out.println(kBoard);
}
/**
* Mutator: runTour()
*/
public void runTour()
{
getStartPosition();
// if stepNumber is equal to COMPLETE_TOUR
// report that the knight made a complete tour
do {
takeStep();
}
while (stepNumber < 64 && takeStep()== true);
System.out.println(kBoard);
System.out.println(toString());
}
private boolean takeStep()
{
boolean stepTaken = true;
int random1;
Random rand = new Random();
random1 = rand.nextInt(8);
int tryStepRow =0;
int tryStepCol=0;
int attempts =0;
do {
tryStepRow = currentRow + moves[random1][0];
tryStepCol = currentCol + moves[random1][1];
if(kBoard.getSquare(tryStepRow,tryStepCol)==0)
{
kBoard.setSquare(tryStepRow,tryStepCol, stepNumber++);
currentRow= tryStepRow;
currentCol = tryStepCol;
}
else
{
attempts++;
}
} while (stepTaken == false && attempts < 200);
return stepTaken;
}
public String toString()
{
String whatHappened = "";
whatHappened += "Starting location: [" + startRow + ", "
+ startCol + "]\n";
whatHappened += " Tour ended after " + stepNumber + " steps\n";
whatHappened += "The knight got stuck in location ["
+ (currentRow ) + ", " + (currentCol ) + "]\n";
return whatHappened;
}
}
Sample message I get.
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: -1
at runknightstour.ChessBoard.getSquare(ChessBoard.java:68)
at runknightstour.KnightMoves.takeStep(KnightMoves.java:101)
at runknightstour.KnightMoves.runTour(KnightMoves.java:80)
at runknightstour.RunKnightsTour.main(RunKnightsTour.java:22)
I:\CSC122\RunKnightsTour\nbproject\build-impl.xml:1039: The following error occurred while executing this line:
I:\CSC122\RunKnightsTour\nbproject\build-impl.xml:804: Java returned: 1
BUILD FAILED (total time: 2 seconds)
If you carefully see the function setSquare() you'll notice that it is going into an infinite loop as there is no increment conditions given on row or col.
Also, if your board size is not big enough then you can end up getting ArraysOutOfBounds exception.
public void setSquare(int row, int col, int inStep)
{
// adjust input to match 2 - 9
row += 1;
col += 1;
if (row > 1 && row < 10 && col > 1 && col < 10)
{
/* Where are you incrementing row/col? */
board[row][col] = inStep;
}
}
I have a csv file with numbers(i.e. 0, 2, 34, 0, 2,...) all on one line. I am using a scanner to read them from a file. The file represents an in-game map which is quite large. I know the width and height of this map. While scanning this file, I only want to capture the brown rectangle(part of the game's map) in the image below. I am scanning the file and wanting to put the values from the csv file into a short[].
int mapWidth = 8;
int mapHeight = 6;
int rectangleWidth = 5;
int rectangleHeight = 3;
short[] tmpMap = new short[rectangleWidth * rectangleHeight];
Scanner scanner = new Scanner(new File(path));
scanner.useDelimiter(", ");
I also am lucky enough to know the 4 corners of the rectangle that I need. The dark brown squares(four corners of the rectangle I need to capture) can be represented as:
int topLeftIndex = 17;
int topRightIndex = 21;
int bottomLeftIndex = 33;
int bottomRightIndex = 37;
I know that during my scan method I can check to see if I am within bounds of the rectangle and the blue highlighted boxes with the following:
if (count >= topLeftIndex && count <= bottomRightIndex){
//within or outside (east and west) of rectangle
I am having trouble thinking of the logic for identifying and not storing the blue highlighted squares.
The size of this rectangle, size of the overall map, and dark brown point are just numeric examples and will change, but I will always know them. Can anyone help me out?
Here is what I have so far:
private static short[] scanMapFile(String path, int topLeftIndex,
int topRightIndex, int bottomLeftIndex, int bottomRightIndex)
throws FileNotFoundException {
Scanner scanner = new Scanner(new File(path));
scanner.useDelimiter(", ");
short[] tmpMap = new short[mapWidth * mapHeight];
int count = 0;
int arrayIndex = 0;
while(scanner.hasNext()){
if (count >= topLeftIndex && count <= bottomRightIndex){
//within or outside (east and west) of rectangle
if (count == bottomRightIndex){ //last entry
tmpMap[arrayIndex] = Short.parseShort(scanner.next());
break;
} else { //not last entry
tmpMap[arrayIndex] = Short.parseShort(scanner.next());
arrayIndex++;
}
} else {
scanner.next(); //have to advance scanner
}
count++;
}
scanner.close();
return tmpMap;
}
NOTE: this is not school work :) Any help would be tremendously appreciated.
You could to it like this:
public boolean isInside(int n) {
if(n >= topLeftIndex && n <= bottomRightIndex) {
if(n % mapWidth >= topLeftIndex % mapWidth
&& mapWidth % mapWidth <= bottomRightIndex % mapWidth) {
return true;
}
}
return false;
}
This first checks, what you have already checked and then checks, whether the "column" is right as well.
This works always if you know the top-left index, the bottom-right index, and the map width.
Here is what I did to capture all of the sides:
int topLeftChunkIndex = characterX - (chunkWidth / 2) + ((characterY - (chunkHeight / 2)) * mapWidth);
int topRightChunkIndex = topLeftChunkIndex + chunkWidth - 1;
//int bottomRightChunkIndex = characterX + (chunkWidth / 2) + ((characterY + (chunkHeight / 2)) * mapWidth);
//int bottomLeftChunkIndex = bottomRightChunkIndex - chunkWidth + 1;
int[] leftChunkSides = new int[chunkHeight];
int[] rightChunkSides = new int[chunkHeight];
for (int i = 0; i < chunkHeight; i++){
leftChunkSides[i] = topLeftChunkIndex + (mapWidth * i);
rightChunkSides[i] = topRightChunkIndex + (mapWidth * i);
}
And here is how I checked later:
public static boolean isInsideMapChunk(int n, int[] leftChunkSides, int[] rightChunkSides) {
for (int i = 0; i < chunkHeight; i++){
if (n >= leftChunkSides[i] && n <= rightChunkSides[i]){
return true;
}
}
return false;
}
This question already has answers here:
How do I do a deep copy of a 2d array in Java?
(7 answers)
Closed 8 years ago.
So I am trying to make an algorithm for finding full paths in NxN grid. For example in 1x1 grid there is 1 possible path, in 2x2 grid there is 1, in 3x3 there is 2 and in 4x4 there is 8. The idea is to find scenarios where we can fill every spot of the grid by moving.
I have made a recursive function for the job and here is the code:
public static int getRoutesHelp(int[][] table, int x, int y)
{
if(x > table.length-1 || x < 0 || y < 0 || y > table.length-1)
return 0;
if(table[x][y] == 1)
return 0;
table[x][y] = 1;
if(isDeadEnd(table, x, y))
{
if(isTableFull(table))
return 1;
}
else
{
int a = getRoutesHelp(table, x-1, y);
int d = getRoutesHelp(table, x, y+1);
int b = getRoutesHelp(table, x+1, y);
int c = getRoutesHelp(table, x, y-1);
return a+b+c+d;
}
return 0;
}
public static int getRoutes(int size)
{
int[][] table = new int[size][size];
// init table
for(int i = 0; i < size; i++)
{
for(int a = 0; a < size; a++)
{
table[i][a] = 0;
}
}
return getRoutesHelp(table, 0 ,0);
}
So basically I start from 0.0 and start moving to all possible directions and by repeating this I get the amount of successful routes. The problem is that after the assignment of int d the original table is somehow filled with 1 but it should be empty as far as I understand because java passes a copy of the table right? I've been fighting with this for like 4 hours and can't really find the problem so any help is appreciated. Empty slots in table are marked with 0 and filled slots with 1.
EDIT: I managed to fix the issue I had with the copying and now my other problem is that with 5x5 grid my algorithm returns 52 routes and it should be 86. So it works with 4x4 grid okay, but once I move further it breaks.
Added the isDeadEnd function here
public static boolean isDeadEnd(int[][] table, int x, int y)
{
int toCheck[] = new int[4];
toCheck[0] = x-1; // left
toCheck[1] = y-1; // top
toCheck[2] = x+1; // right
toCheck[3] = y+1; // bottom
int valuesOfDirections[] = new int[4]; // left, top, right, bottom
for(int i = 0; i < 4; i++)
{
int tarkastettava = toCheck[i];
if(tarkastettava > table.length-1 || tarkastettava < 0)
{
valuesOfDirections[i] = 1;
}
else
{
if(i == 0 || i == 2)
{
valuesOfDirections[i] = table[tarkastettava][y];
}
else
{
valuesOfDirections[i] = table[x][tarkastettava];
}
}
}
for(int i = 0; i < 4; i++)
{
if(valuesOfDirections[i] == 0)
{
return false;
}
}
return true;
}
Come to think of it, you probably can do a simple backtrack here:
table[x][y] = 1;
if(isDeadEnd(table, x, y)) {
if(isTableFull(table))
return 1;
}
table[x][y] = 0;
}
And later:
int res = a + b + c + d;
if (res == 0) {
// backtrack here too
table[x][y] = 0;
}
return res;