Determine Number of Squares a Knight Guards - java

I am having a bit of trouble producing the right output for this assignment and not sure what I am doing wrong.
There are K knights on N x N chessboard and you are to determine how many squares they are guarding. A square is guarded if it is either occupied by a
knight or is reachable by a knight by a single move.
Write a program that reads positive integers N and K and then K positions of knights, and prints the
number of squares that are guarded by these K knights.
Example of input: 8 2 c 1 e 2
Corresponding output: 10
Example of input: 8 6 c 1 e 2 d 4 c 7 f 7 h 6
Corresponding output: 30
When I input the first example it works, but when I input the second example it gives me 34
package knightguard;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Scanner;
import java.util.Set;
public class KnightGuard {
static class Position {
int x;
int y;
public Position(int x, int y) {
this.x = x;
this.y = y;
}
public boolean equals(Position p) {
if (p.x == x && p.y == y) {
return true;
}
return false;
}
#Override
public String toString() {
return x + "," + y;
}
}
ArrayList<Position> knightPositions;
int size;
int no_of_knights;
public KnightGuard(int size, int k, ArrayList<Position> knightPositions) {
this.knightPositions = knightPositions;
no_of_knights = k;
this.size = size;
}
public int getSafePositions() {
Set<Position> safePos = new HashSet<>();
for (Position p : knightPositions) {
if (isValid(p.x - 2, p.y - 1)) {
safePos.add(new Position(p.x - 2, p.y - 1));
}
if (isValid(p.x - 2, p.y + 1)) {
safePos.add(new Position(p.x - 2, p.y + 1));
}
if (isValid(p.x + 2, p.y - 1)) {
safePos.add(new Position(p.x + 2, p.y - 1));
}
if (isValid(p.x + 2, p.y + 1)) {
safePos.add(new Position(p.x + 2, p.y + 1));
}
if (isValid(p.x - 1, p.y - 2)) {
safePos.add(new Position(p.x - 1, p.y - 2));
}
if (isValid(p.x - 1, p.y + 2)) {
safePos.add(new Position(p.x - 1, p.y + 2));
}
if (isValid(p.x + 1, p.y - 2)) {
safePos.add(new Position(p.x + 1, p.y - 2));
}
if (isValid(p.x + 1, p.y + 2)) {
safePos.add(new Position(p.x + 1, p.y + 2));
}
}
return safePos.size();
}
private boolean isValid(int x, int y) {
if (x < 0 || x >= size || y < 0 || y >= size) {
return false;
}
if (knightPositions.contains(new Position(x, y))) {
return false;
}
return true;
}
public static void main(String[] args) {
Scanner s = new Scanner(System.in);
int size = s.nextInt();
int knights = s.nextInt();
ArrayList<Position> knightPos = new ArrayList<>();
for (int i = 0; i < knights; i++) {
int x = s.next().charAt(0) - 'a';
int y = s.nextInt() - 1;
knightPos.add(new Position(x, y));
}
KnightGuard knightGuard = new KnightGuard(size, knights, knightPos);
System.out.println(knightGuard.getSafePositions());
s.close();
}
}

One issue in using this approach is that possible duplicate positions may be generated for different knights. Example; using the picture in the post, the two knights at positions D4 and H6 can BOTH move to the square at F5. Therefore, the posted code will count this position TWICE. In theory, there could possibly be eight (8) knights at eight different positions and all could move to the same square. A check is going to have to be made to eliminate these possible “duplicate’ positions.
I am a little confused by the KnightGuard class and the getSafePositions method. The KnightGuard class has a list of positions, this is the list of the positions of the given knights. However the getSafePositions method simply returns the number of different moves all the knights could move from their respective positions. This method does not take into account that the previous knight could also move to the same position as described in the first paragraph.
To simplify things… I feel a class called Knight would be a better approach. A Knight would have a Position variable to indicate where “THIS” knight is positioned on the board. In Addition, the Knight class would contain an ArrayList of Position objects to indicate all the possible moves this knight can make given its position. A Knight should NOT be aware of any other Knights and the list of positions it can move to are all the positions it could move to regardless if there is another piece at that position. This list would contain a minimum of two (2) positions and up to a maximum of eight (8) different positions.
When a new Knight object is created, the list of possible moves is automatically generated upon instantiation along with its own position on the board, which we will need later.
Below is an example of this Knight class. It should be noted that in this class and in the main method, I changed the indexing of the board to start at 1 (a) not zero (0) on the left and moves right and also on the y index where the bottom y index is 1 and moves up. In addition a SetValidMoves method is created to allow the list of positions this knight can move, to be changed. This may be needed if another knight occupies one of the positions in this knight's list of guarded positions. This code is not taking advantage of this since we are only interested in the number of guarded squares.
public class Knight {
Position knightPosition;
ArrayList<Position> validMoves;
int boardSize;
public Knight(Position position, int inBoardSize) {
knightPosition = position;
validMoves = new ArrayList<Position>();
boardSize = inBoardSize;
SetValidMoves();
}
public Position GetKnightPosition() {
return knightPosition;
}
public ArrayList<Position> GetValidMoves() {
return validMoves;
}
public void SetValidMoves(ArrayList<Position> newMoves) {
validMoves = newMoves;
}
private void SetValidMoves() {
int thisX = knightPosition.x;
int thisY = knightPosition.y;
// check for bottom moves 2 down 1 left - right
if (thisY - 2 >= 1) {
if (thisX + 1 <= boardSize) {
validMoves.add(new Position(thisX + 1, thisY - 2));
}
if (thisX - 1 >= 1) {
validMoves.add(new Position(thisX - 1, thisY - 2));
}
}
// check for bottom moves 1 down 2 left - right
if (thisY - 1 >= 1) {
if (thisX + 2 <= boardSize) {
validMoves.add(new Position(thisX + 2, thisY - 1));
}
if (thisX - 2 >= 1) {
validMoves.add(new Position(thisX - 2, thisY - 1));
}
}
// check for top moves 2 up 1 left - right
if (thisY + 2 <= boardSize) {
if (thisX + 1 <= boardSize) {
validMoves.add(new Position(thisX + 1, thisY + 2));
}
if (thisX - 1 >= 1) {
validMoves.add(new Position(thisX - 1, thisY + 2));
}
}
// check for top moves 1 up 2 left - right
if (thisY + 1 <= boardSize) {
if (thisX + 2 <= boardSize) {
validMoves.add(new Position(thisX + 2, thisY + 1));
}
if (thisX - 2 >= 1) {
validMoves.add(new Position(thisX - 2, thisY + 1));
}
}
}
}
With an ArrayList of Knight objects (knightsOnBoard) it is possible to loop thought this list and create an ArrayList of Position objects (validMoves) where each Position indicates a position one or more of the knights is guarding. Since duplicates are not wanted, we simply ignore positions that are already in the validMoves list.
knightsOnBoard is the global list of Knight objects
private static ArrayList<Position> GetAllDifferentPositions() {
ArrayList<Position> validMoves = new ArrayList<Position>();
for (Knight curKnight : knightsOnBoard) {
for (Position curPos : curKnight.validMoves) {
if (!validMoves.contains(curPos)) {
validMoves.add(curPos);
}
}
}
return validMoves;
}
Since the above code uses the contains property to check if the position is already in the list validMoves, a change is needed in the Position class to publicly expose the equals method using an Object parameter.
#Override
public boolean equals(Object obj) {
if (obj instanceof Position) {
Position other = (Position)obj;
if (this.x == other.x && this.y == other.y)
return true;
}
return false;
}
Now we have an ArrayList of Position objects that do not have duplicates. Unfortunately, there is one last hurdle to clear. There needs to be a check to see if a Knight can move to a square but it is already occupied by another knight. Therefore we will need to remove all the ‘Knight`’s positions in the list of positions the knights can move to.
The reason this must be done is that we need to add all the given Knight’s positions to the count since the square the knight is sitting on is also a “guarded” square. Since it is possible this position is already in the list… we need to remove them. In other words, we know a Knight will not have “its” own position in its list of moves, however it may have another Knights position in its list of moves.
private static void RemoveAllKnightPositions(ArrayList<Position> allPositions) {
for (Knight curKnight : knightsOnBoard) {
if (allPositions.contains(curKnight.knightPosition)) {
allPositions.remove(curKnight.knightPosition);
}
}
}
Now the list of positions (finalResults below) has no duplicates and in addition, we know the list does not contain any of the positions where a knight is sitting. Therefore, the number of guarded squares would be the number of positions in the positions list finalResults PLUS the number of knights.
Finally, putting this all together in the main method below. Please note the code changes the indexing order so BOTH x and y start at one (1) and end at boardSize. I hope this makes sense and helps.
static ArrayList<Knight> knightsOnBoard = new ArrayList<Knight>();
public static void main(String[] args) {
Scanner s = new Scanner(System.in);
int boardSize = s.nextInt();
int knights = s.nextInt();
for (int i = 0; i < knights; i++) {
int x = (s.next().charAt(0) - 'a') + 1;
int y = s.nextInt();
Knight newKnight = new Knight(new Position(x,y), boardSize);
knightsOnBoard.add(newKnight);
System.out.println("Knight at : " + newKnight.knightPosition.x + " " + newKnight.knightPosition.y);
}
ArrayList<Position> finalResults = GetAllDifferentPositions();
RemoveAllKnightPositions(finalResults);
System.out.println("Positions: " + (finalResults.size() + knightsOnBoard.size()));
s.close();
}

Related

How do you find possible x, y values for the Knight's Tour Problem?

I was looking into the Knight's Tour Problem, where the solution is obtained when a chess knight piece moves to every square on a grid exactly once. However, upon looking at different solutions for the problem, I keep seeing a specific array of numbers:
int xMove[] = { 2, 1, -1, -2, -2, -1, 1, 2 };
int yMove[] = { 1, 2, 2, 1, -1, -2, -2, -1 };
Where exactly these integers are coming from? Is there a way that you can solve the problem without these specific integers, or are they essential to the problem? For reference, here is the full code I was looking at. (credit GeeksforGeeks)
// Java program for Knight Tour problem
class KnightTour {
static int N = 8;
/* A utility function to check if i,j are
valid indexes for N*N chessboard */
static boolean isSafe(int x, int y, int sol[][])
{
return (x >= 0 && x < N && y >= 0 && y < N
&& sol[x][y] == -1);
}
/* A utility function to print solution
matrix sol[N][N] */
static void printSolution(int sol[][])
{
for (int x = 0; x < N; x++) {
for (int y = 0; y < N; y++)
System.out.print(sol[x][y] + " ");
System.out.println();
}
}
/* This function solves the Knight Tour problem
using Backtracking. This function mainly
uses solveKTUtil() to solve the problem. It
returns false if no complete tour is possible,
otherwise return true and prints the tour.
Please note that there may be more than one
solutions, this function prints one of the
feasible solutions. */
static boolean solveKT()
{
int sol[][] = new int[8][8];
/* Initialization of solution matrix */
for (int x = 0; x < N; x++)
for (int y = 0; y < N; y++)
sol[x][y] = -1;
/* xMove[] and yMove[] define next move of Knight.
xMove[] is for next value of x coordinate
yMove[] is for next value of y coordinate */
int xMove[] = { 2, 1, -1, -2, -2, -1, 1, 2 };
int yMove[] = { 1, 2, 2, 1, -1, -2, -2, -1 };
// Since the Knight is initially at the first block
sol[0][0] = 0;
/* Start from 0,0 and explore all tours using
solveKTUtil() */
if (!solveKTUtil(0, 0, 1, sol, xMove, yMove)) {
System.out.println("Solution does not exist");
return false;
}
else
printSolution(sol);
return true;
}
/* A recursive utility function to solve Knight
Tour problem */
static boolean solveKTUtil(int x, int y, int movei,
int sol[][], int xMove[],
int yMove[])
{
int k, next_x, next_y;
if (movei == N * N)
return true;
/* Try all next moves from the current coordinate
x, y */
for (k = 0; k < 8; k++) {
next_x = x + xMove[k];
next_y = y + yMove[k];
if (isSafe(next_x, next_y, sol)) {
sol[next_x][next_y] = movei;
if (solveKTUtil(next_x, next_y, movei + 1,
sol, xMove, yMove))
return true;
else
sol[next_x][next_y]
= -1; // backtracking
}
}
return false;
}
/* Driver Code */
public static void main(String args[])
{
// Function Call
solveKT();
}
}
// This code is contributed by Abhishek Shankhadhar
It's simply an exhaustive list of all the moves a knight can make, relative to its current position. That list is determined by the rules of chess (and the rectangular grid of a chessboard).
For example, the 0'th entries in both arrays mean "2 squares right and 1 square forward" - assuming x-coordinates increase left-to-right and y coordinates increase front-to-back.
You can determine the list for yourself by enumerating every possible combination of "two squares in one direction, and then one square at right-angles to it".

Java - Last created object overwrites previous one

I am working on a dungeon styled game project and am using a 2D array to create the layout of the rooms. I am using a map generation class and a point class in order to create the map and keep track of which room is being accessed. A starting point is chosen upon generation (usually just 0,0 being the center of the 2D array) and the point for the boss (which is created but not filled). The map generation itself works fine but for some reason my starting point is being overwritten by the boss point. I've tried having the starting point just being defaulted to (0,0) and that didn't work. I tried forcing the boss point to also be (0,0) to start and that resulted in a null pointer exception. I am not sure why this is occurring and would appreciate a bit of help.
MapGeneration Class
/**********************************************
* created by Intellij idea.
* User: Kyle Castillo
* Date: 2/14/2020
* Time: 10:41 AM
* Contact: kylea.castillo#calbaptist.edu
***********************************************/
import java.util.Random;
import java.util.Vector;
public class MapGeneration {
private static Vector<Vector<Integer>> map;
private Point startPnt;
private Point bossPoint;
private static Integer size;
/************************************************************
* Constructor class for Map Generation
* The Size will always be an X by X square based on size
* Starting Point is specified by the starting (x,y)
* Rooms are designated by a numerical value
* - A 0, indicating an empty space
* - A 1, indicating a filled space with a room
* - An 8, indicating the array boundary.
************************************************************/
MapGeneration(int size, int startX, int startY) {
startPnt = new Point(startX,startY);
bossPoint = new Point();
MapGeneration.size = size + 2; //the additional two is to account for boundaries
map = new Vector<>();
//Check to prevent the creation of an array where the starting x and y are outside of the array bounds.
if (startX == 0 || startX == size - 1 || startX == size)
throw new IllegalArgumentException("Error, the starting X value " + startX + " is not allowed!");
if (startY == 0 || startY == size - 1 || startY == size)
throw new IllegalArgumentException("Error, the starting Y value " + startY + " is not allowed!");
//Creation of the starting room layout.
for (int row = 0; row < size; row++) {
Vector<Integer> tmp = new Vector<>();
for (int col = 0; col < size; col++) {
//The first row, the first value of each row, the last value of each row, and the last row must be 8
//to prevent the generation later from going out of the 2D array boundary.
if (row == 0 || col == 0 || row == size - 1 || col == size - 1 ){
tmp.add(8);
//If the row and col match the starting value then this is the first room.
} else if (row == startY && col == startX){
tmp.add(1);
} else {
//Empty space that can be filled with a room.
tmp.add(0);
}
}
map.add(tmp);
}
}
/*********************************************************************************
* The generate map populates the map based on the desired number of rooms.
* The number of rooms cannot exceed the maximum space available within the map.
* If the number of rooms fits then the map is generated from the starting point.
*********************************************************************************/
public void generateMap(int numRooms) {
//Checking to make sure that the number of rooms does not exceed the total number of empty spaces.
if (numRooms > ((map.size() - 2) * (map.get(0).size() - 2))) {
throw new IllegalArgumentException("Error, room amount exceeds map space!");
}
int x = startPnt.getX();
int y = startPnt.getY();
Point crntPnt = new Point(x,y);
bossPoint = crntPnt;
//Based a random number 0-3 a direction is chosen to create a new room.
Random randDirection = new Random();
int compass;
while (numRooms != 0) {
compass = randDirection.nextInt(4);
switch (compass) {
case 0: //Compass Index is North, indicates a shift in ROW + 1
int nextPos = map.get(crntPnt.getY() + 1).get(crntPnt.getX());
if(nextPos == 8){
//do nothing, its the map boundary
}
//As long as the next spot isn't already filled, create a room
else if (nextPos != 1) {
map.get(crntPnt.getY() + 1).set(crntPnt.getX(),1);
crntPnt.setY(crntPnt.getY() + 1);
//If the current point is further from the start point then make the boss point the current point
if (bossPoint.distance(startPnt) < crntPnt.distance(startPnt))
bossPoint = crntPnt;
numRooms--;
//If the next position is 1 move the current position but do not fill the spot or
//decrease the number of rooms left to make.
} else if (nextPos == 1) {
crntPnt.setY(crntPnt.getY() + 1);
}
break;
/****************************************
* The rest of the cases function the exact
* same way as the first.
****************************************/
case 1: //Compass Index is East, indicates a shift in COL + 1
nextPos = map.get(crntPnt.getY()).get(crntPnt.getX() + 1);
if(nextPos == 8){
//do nothing
}
if (nextPos != 1) {
map.get(crntPnt.getY()).set(crntPnt.getX() + 1,1);
crntPnt.setX(crntPnt.getX() + 1);
if (bossPoint.distance(startPnt) > crntPnt.distance(startPnt))
bossPoint = crntPnt;
numRooms--;
} else if (nextPos == 1) {
crntPnt.setX(crntPnt.getX() + 1);
}
break;
case 2: //Compass Index is South, indicates a shift in ROW - 1
nextPos = map.get(crntPnt.getY() - 1).get(crntPnt.getX());
if(nextPos == 8){
//do nothing
}
if (nextPos != 1) {
map.get(crntPnt.getY() - 1).set(crntPnt.getX(),1);
crntPnt.setY(crntPnt.getY() - 1);
if (bossPoint.distance(startPnt) > crntPnt.distance(startPnt))
bossPoint = crntPnt;
numRooms--;
} else if (nextPos == 1) {
crntPnt.setY(crntPnt.getY() - 1);
}
break;
case 3: //Compass Index is West, indicates a shift in COL - 1
nextPos = map.get(crntPnt.getY()).get(crntPnt.getX() - 1);
if(nextPos == 8){
//do nothing
}
if (nextPos != 1) {
map.get(crntPnt.getY()).set(crntPnt.getX() - 1,1);
crntPnt.setX(crntPnt.getX() - 1);
if (bossPoint.distance(startPnt) > crntPnt.distance(startPnt))
bossPoint = crntPnt;
numRooms--;
} else if (nextPos == 1) {
crntPnt.setX(crntPnt.getX() - 1);
}
break;
}
}
map.get(bossPoint.getY()).set(bossPoint.getX(),2);
}
#Override
public String toString() {
int sizeTemp = map.get(0).size();
for (int row = 0; row < sizeTemp; row++) {
System.out.print("[ ");
for (int col = 0; col < sizeTemp; col++) {
int type = map.get(row).get(col);
System.out.print(type + " ");
}
System.out.print("]\n");
}
return "";
}
public static void main(String[] args) {
MapGeneration map = new MapGeneration(11, 5, 5);
System.out.println("Empty Map:");
System.out.println(map);
System.out.println("Starting point prior to map generation: " + map.startPnt);
map.generateMap(10);
System.out.println(map);
System.out.println("The starting room is at " + map.startPnt);
System.out.println("The boss room is at " + map.bossPoint);
System.out.println("The distance to the boss room is: " + (int) map.startPnt.distance(map.bossPoint));
}
}
Point Class
/**********************************************
* created by Intellij idea.
* User: Kyle Castillo
* Date: 3/4/2020
* Time: 9:04 AM
* Contact: kylea.castillo#calbaptist.edu
***********************************************/
public class Point {
private static int x;
private static int y;
Point(){
//default constructor
}
Point(int x, int y){
this.x = x;
this.y = y;
}
public static int getX(){
return x;
}
public static int getY(){
return y;
}
public void setX(int x){
this.x = x;
}
public void setY(int y){
this.y = y;
}
public static double distance(Point b){
int bX = b.getX();
int bY = b.getY();
return Math.sqrt((Math.pow((bX - getX()),2.0) + Math.pow( bY - getY(), 2.0)));
}
#Override
public String toString(){
return "(" + getX() + ", " + getY() + ")";
}
}
Welcome to Stack Overflow. Your mistake in the code is, x and y variables are marked static in Point class. Then they will be class variables, not instance variables. Eventhough you create a new instance of Point crntPnt = new Point( x, y ) varibles x and y does not belong to this particular instance.
Just change the Point class as below, and make sure to change the getters and setters as well
public class Point {
private int x;
private int y;
public int getX(){
return x;
}
public int getY(){
return y;
}
public void setX(int x){
this.x = x;
}
public void setY(int y){
this.y = y;
}
}
As a side note, line map.get( crntPnt.getY() - 1 ).set( crntPnt.getX(), 1 ) will throw an ArrayIndexOutOfBounds exception if the value is crntPnt.getY() is 0. So you may want to handle that too.

Java program for all walking paths of a square grid

I'm trying to write a program that outputs (in the console) all possible paths (in (x1,x1) --> (x2,x2) --> etc.. format) for navigating a grid of size NxN, from top-left to bottom-right; i.e. from (0,0) to (N-1,N-1). You can only move down or right; i.e. from (0,0) to (0,1) or to (1,0). I want the program to output each time a full path set is found (i.e. all moves from top-left to bottom-right), and what that path set is.
It seems as though the best way to write this is with a recursive method inputting each move into an arrayList (see the buildPath method - the last method in the program), which is where I'm having trouble.
To make it slightly more complicated, I'm also generating random grid positions that are "off-limits" and as such can't be passed through.
That said, I can probably work that part out for myself once we/I figure out how to actually get the thing working with any paths at all.
How would I implement a recursive method to determine which paths are possible? Any help is appreciated (even pseudo-code would be better than nothing)!
Here is my code so far (the simple bits are in pseudo-code to make it easier to work through, but let me know if I should put the full code in):
import java.util.*;
public class RecursiveAlgorithm {
public static ArrayList<Integer> allPaths = new ArrayList<Integer>();
public static ArrayList<String> pathSet = new ArrayList<String>();
public static int path;
public static int N, M, x = 0, y = 0;
public static String nString, mString;
public static boolean grid[][];
public static int right, down;
#SuppressWarnings("resource")
public static void main(String[] args) {
//sets the current position to (0,0)
right = 0;
down = 0;
Input value of N (size of grid)
Input value of M (number of off-limits locations)
offLimits(N, M); //calls offLimits method to randomly generate off-limits locations
buildPath(right, down, allPaths, N); //calls buildPath method
}
public static void offLimits (int N, int M) {
int mCount = 0;
if (M == 0){
} else {
while (mCount < (M + 1)) {
//int range1 = (max - min) + 1;
int range1 = ((N-1) - 1) + 1;
int range2 = ((N-1) - 0) + 1;
int random1 = (int)((Math.random() * range1) + 1);
int random2 = (int)(Math.random() * range2);
//if an 'off-limits' point is generated at the finish point, move it to either 1 place to the left or 1 place above
if ((random1 == N-1) && (random2 == N-1)) {
int switchSelect = (int)(Math.random() * 2);
while (switchSelect > 0) {
switch (switchSelect){
case 1: random1--;
break;
case 2: random2--;
break;
}
}
}
//sets a grid position to 'off-limits' (i.e. random1 = 1, random2 = 2 --> (1, 2) is 'off-limits')
grid[random1][random2] = true;
//counts the amount of off-limits grid locations generated
mCount++;
}
}
}
public static ArrayList<String> buildPath (int right, int down, ArrayList<Integer> allPaths, int N) {
//Updates path with current location (right, down)
/***** FROM HERE ON IS WHERE I AM HAVING TROUBLE *****/
//Stopping Condition
if ((right == N-1) && (down == N-1)) { //robot cannot go right
allPaths.add(path);
return pathSet;
}
//Recursive Steps
if (right == N-1) { //robot cannot go right
buildPath (right, down + 1, allPaths, N);
} else if (down == N-1) { //robot cannot go down
buildPath (right + 1, down, allPaths, N);
} else { //robot CAN go right or go down
buildPath (right + 1, down, allPaths, N);
//pathSet.add(Integer.toString(right));
//pathSet.add(Integer.toString(down));
buildPath (right, down + 1, allPaths, N);
if (grid[x][y] == false) {
//valid new position (substitute x and y for proposed new path step)
} else if (grid[x][y] == true) {
//off-limits position (substitute x and y for proposed new path step)
}
}
return pathSet;
}
}
You're on the right track, but headed toward a solution more complex than needed. Here's one approach that finds them allowing all 4 compass directions (not just right and down). See how simple you can make it by removing code.
import java.util.LinkedHashSet;
class Experimental {
static class PathFinder {
final int gridSize;
final boolean [] [] isBlocked;
final Coord goal;
final LinkedHashSet<Coord> path = new LinkedHashSet<>();
final Random gen = new Random();
PathFinder(int gridSize, int nBlocked) {
this.gridSize = gridSize;
this.isBlocked = new boolean[gridSize][gridSize];
this.goal = new Coord(gridSize - 1, gridSize - 1);
// This gets really inefficient if nBlocked is too big.
for (int n = 0; n < nBlocked; ++n) {
int x, y;
do {
x = gen.nextInt(gridSize);
y = gen.nextInt(gridSize);
} while (isBlocked[x][y] || (x == gridSize - 1 && y == gridSize - 1));
isBlocked[x][y] = true;
}
}
void searchFrom(Coord coord) {
if (path.contains(coord)) return;
path.add(coord);
if (coord.equals(goal)) System.out.println(path);
if (coord.x > 0 && !isBlocked[coord.x - 1][coord.y])
searchFrom(new Coord(coord.x - 1, coord.y));
if (coord.y > 0 && !isBlocked[coord.x][coord.y - 1])
searchFrom(new Coord(coord.x, coord.y - 1));
if (coord.x < gridSize - 1 && !isBlocked[coord.x + 1][coord.y])
searchFrom(new Coord(coord.x + 1, coord.y));
if (coord.y < gridSize - 1 && !isBlocked[coord.x][coord.y + 1])
searchFrom(new Coord(coord.x, coord.y + 1));
path.remove(coord);
}
void printAllPaths() {
searchFrom(new Coord(0, 0));
}
static class Coord {
final int x, y;
public Coord(int x, int y) {
this.x = x;
this.y = y;
}
#Override
public boolean equals(Object obj) {
if (obj instanceof Coord) {
Coord other = (Coord) obj;
return x == other.x && y == other.y;
}
return false;
}
#Override
public int hashCode() {
return Integer.hashCode(x) ^ Integer.hashCode(-y);
}
#Override
public String toString() {
return '(' + Integer.toString(x) + ',' + Integer.toString(y) + ')';
}
}
}
public static void main(String[] args) {
new PathFinder(4, new boolean [] [] {
{ false, false, false, false },
{ false, false, true, false },
{ true, false, false, false },
{ false, false, false, false },
}).printAllPaths();
}
}
One hint: The linked hash set is a reasonable choice for the path here because we need to look "backward" at each step to make sure we're not about to visit a location already visited. The set makes the lookups O(1), while the linking ensures order is maintained, which normal hash sets don't. Your problem is different.

What steps would one have to go through to change a program with char arrays to Strings in java?

Ok so in my program I have to make a dumbed down version of Monopoly called Opoly. Its a basic program with a few simple rules
If your board piece lands on a board cell that is evenly divisible
by 7, your reward doubles.
If you land on the final board cell, you must go back 3 spaces. Thus
if the board size is 20, the last position is position 19, and if
you land there, you should go back to position 16. (If the position
of the last cell is evenly divisible by 7, no extra points are
added, but if the new piece location, 3 places back, IS evenly
divisible by 7, then extra points ARE added).
If you make it all the way around the board, you get 100 points.
Note that if you land exactly on location 0, you first receive 100
extra points (for making it all the around), and then your score is
doubled, since 0 is evenly divisible by 7,
Every tenth move (that is, every tenth spin of the spinner, move
numbers 10,20,30,... etc.), reduces the reward by 50 points. This
penalty is applied up front, as soon as the 10th or 20th or 30th
move is made, even if other actions at that instant also apply.
Notice that with this rule it's possible for the reward amount to
become negative.
I have done this successfully. However, now my teacher wants us to do the same thing using Strings instead of a char Array. So I know a String is virtually a char array so what stepts would i have to take to make this really painless.
here is my code is you need something visual. I commented most of the code to help understanding it.
import java.util.*;
public class OpolyDriver{
public static void main(String[] args){
System.out.println("Enter an int > 3 - the size of the board");
Scanner s = new Scanner(System.in);
int boardSize = s.nextInt();
System.out.println("Board Size: " + boardSize);
Opoly g = new Opoly(boardSize);
g.playGame();
}
}
public class Opoly{
private static int size; //how big the board is
private static int spin; //value of the spinner
private static int reward; //total points
private static int turnNumber; //how many turns have passed
private static char[] board; //the array of the board and holding the position of the player
private static boolean first; //temp variable to create the array with *'s and o
public Opoly(int s){ //constructor
size = s; //sets the size passed by the main method defined by the user
reward = 100; //startes player with 100 points
turnNumber = 0; //sets turn number to 0
board = new char[size]; //creates the array
first = true; //temp variable to create the array with *'s and o
}
public void playGame(){
Opoly.drawBoard(); //prints out board for the first time
while (Opoly.isGameOver()){ //checks when the player has recieved 1000 points or more
Opoly.spinAndMove(); //spins, moves, and adds points
Opoly.drawBoard(); //prints out the updated board and reward
}
Opoly.displayReport(); //displays the stats when the game is over
}
public static void spin(){
spin = (1 + (int)(Math.random() * 5)); //generates a number from 1 to 5
}
public static void move(){
if (turnNumber % 10 == 0) //RULE #4 - Every tenth move, reduces the reward by 50 points.
reward = reward - 50;
for (int k = 0; k < size; k++){ //finds the position of the player
if (board[k] == 'o'){
board[k] = '*';
if (k == (size - 1)){ //RULE #2 (condition 1) - If you land on the final board cell, you must go back 3 spaces.
board[k] = '*';
board[k - 3] = 'o';
if (((k - 3) % 7 == 0) && (k - 3 != 0)) //RULE #2 (condition 2 & 3) - If the position of the last cell is evenly divisible by 7, no extra points are added. If the new piece location, 3 places back, IS evenly divisible by 7, then extra points ARE doubled
reward = reward * 2;
if (((k - 3) + spin) >= size){ //brings the array back in bounds to cirlce the position of the player
board[k - 3] = '*';
reward = reward + 100; //RULE #3 - If you make it all the way around the board, you get 100 points.
board[((k - 3) + spin) - size] = 'o';
}
else if (((k - 3) + spin) <= size){ //moves the position when player is in bounds of array
board[k - 3] = '*';
board[(k - 3) + spin] = 'o';
}
}
else if ((k + spin) >= size){ //brings the array back in bounds to cirlce the position of the player
reward = reward + 100; //RULE #3 - If you make it all the way around the board, you get 100 points.
board[(k + spin) - size] = 'o';
}
else if ((k + spin) <= size) //moves the position when player is in bounds of array
board[k + spin] = 'o';
k = size; //resets k
}
}
}
public static void spinAndMove(){
turnNumber++; //adds a turn
Opoly.spin(); //sets a number to the spin variable
Opoly.move(); //moves the position
for (int k = 0; k < size; k++){ //adds points
if (board[k] == 'o'){
if (k == 0) //RULE #1 - Score is doubled, since 0 is evenly divisible by 7,
reward = reward * 2;
else if ((k % 7 == 0) && (k != (size - 1))) //RULE #1 - Score is doubled when it is evenly divisible by 7,
reward = reward * 2;
}
}
}
public static boolean isGameOver(){
boolean isOver = true; //checks if game is over
if (reward >= 1000) //if the reward is 1000 points or over than the game is over
isOver = false;
return isOver;
}
public static void drawBoard(){
if (first){ //temp variable is used to create the board for the first time
board[0] = 'o';
for(int i = 1; i < size; i++)
board[i] = '*';
}
for(int i = 0; i < size; i++) //for loop that prints out the updated board
System.out.print(board[i]);
System.out.println(" " + reward); //prints out the reward
first = false; //temp variable set to flase so it wont recreate the board again
}
public static void displayReport(){ //displays stats
System.out.println("game over");
System.out.println("rounds of play: " + turnNumber);
System.out.println("final reward: " + reward);
}
}
Does not really answers the question, so this can be removed if needs be.
Your board contains 2 types of values: o and *. The player, and not the player.
When you loop on the board array and test if (board[k] == 'o'){, what you are really doing is finding k such as k is the position of the player.
When you are modifying the board array, board[k - 3] = 'o'; what you are really doing is affecting k - 3 to the position of the player.
The position of the player can be represented as an integer, default value 0, and that should stay bounded between 0 and size - 1.
Typically, you would replace those
for (int k = 0; k < size; k++){
if (board[k] == 'o') {
// ...
}
}
blocks by simply using playerPosition instead of k, and the
board[k] = '*';
board[<someValue>] = 'o';
by simply playerPosition = <someValue>; where is k - 3, k + spin...

Recursive brute force maze solver Java

In an attempt to write a brute force maze solving C program, I've written this java program first to test an idea. I'm very new to C and intend to convert it after getting this right in java. As a result, I'm trying stick away from arraylists, fancy libraries, and such to make it easier to convert to C. The program needs to generate a single width path of shortest steps to solve a maze. I think my problem may be in fragmenting a path-storing array passed through each recursion. Thanks for looking at this. -Joe
maze:
1 3 3 3 3
3 3 3 3 3
3 0 0 0 3
3 0 3 3 3
0 3 3 3 2
Same maze solved by this program:
4 4 4 4 4
4 4 4 4 4
4 0 0 0 4
3 0 3 3 4
0 3 3 3 2
number notation are explained in code
public class javamaze {
static storage[] best_path;
static int best_count;
static storage[] path;
//the maze - 1 = start; 2 = finish; 3 = open path
static int maze[][] = {{1, 3, 3, 3, 3},
{3, 3, 3, 3, 3},
{0, 0, 0, 0, 3},
{0, 0, 3, 3, 3},
{3, 3, 3, 3, 2}};
public static void main(String[] args) {
int count1;
int count2;
//declares variables used in the solve method
best_count = 0;
storage[] path = new storage[10000];
best_path = new storage[10000];
int path_count = 0;
System.out.println("Here is the maze:");
for(count1 = 0; count1 < 5; count1++) {
for(count2 = 0; count2 < 5; count2++) {
System.out.print(maze[count1][count2] + " ");
}
System.out.println("");
}
//solves the maze
solve(findStart()/5, findStart()%5, path, path_count);
//assigns an int 4 path to the maze to visually represent the shortest path
for(int count = 0; count <= best_path.length - 1; count++)
if (best_path[count] != null)
maze[best_path[count].getx()][best_path[count].gety()] = 4;
System.out.print("Here is the solved maze\n");
//prints the solved maze
for(count1 = 0; count1 < 5; count1++) {
for(count2 = 0; count2 < 5; count2++){
System.out.print(maze[count1][count2] + " ");
}
System.out.print("\n");
}
}
//finds maze start marked by int 1 - this works perfectly and isn't related to the problem
public static int findStart() {
int count1, count2;
for(count1 = 0; count1 < 5; count1++) {
for(count2 = 0; count2 < 5; count2++) {
if (maze[count1][count2] == 1)
return (count1 * 5 + count2);
}
}
return -1;
}
//saves path coordinate values into a new array
public static void save_storage(storage[] old_storage) {
int count;
for(count = 0; count < old_storage.length; count++) {
best_path[count] = old_storage[count];
}
}
//solves the maze
public static Boolean solve(int x, int y, storage[] path, int path_count) {
//checks to see if grid squares are valid (3 = open path; 0 = wall
if (x < 0 || x > 4) { //array grid is a 5 by 5
//System.out.println("found row end returning false");
return false;
}
if (y < 0 || y > 4) {
//System.out.println("Found col end returning false");
return false;
}
//when finding finish - records the number of moves in static int best_count
if (maze[x][y] == 2) {
if (best_count == 0 || best_count > path_count) {
System.out.println("Found end with this many moves: " + path_count);
best_count = path_count;
save_storage(path); //copies path counting array into a new static array
}
}
//returns false if it hits a wall
if (maze[x][y] == 0)
return false;
//checks with previously crossed paths to prevent an unnecessary repeat in steps
for(storage i: path)
if (i != null)
if (i.getx() == x && i.gety() == y)
return false;
//saves current recursive x, y (row, col) coordinates into a storage object which is then added to an array.
//this array is supposed to fragment per each recursion which doesn't seem to - this may be the issue
storage storespoints = new storage(x, y);
path[path_count] = storespoints;
//recurses up, down, right, left
if (solve((x-1), y, path, path_count++) == true || solve((x+1), y, path, path_count++) == true ||
solve(x, (y+1), path, path_count++) == true || solve(x, (y-1), path, path_count++) == true) {
return true;
}
return false;
}
}
//stores (x, y) aka row, col coordinate points
class storage {
private int x;
private int y;
public storage(int x, int y) {
this.x = x;
this.y = y;
}
public int getx() {
return x;
}
public int gety() {
return y;
}
public String toString() {
return ("storage coordinate: " + x + ", " + y + "-------");
}
}
This wasn't originally intended to be an answer but it sort of evolved into one. Honestly, I think starting in Java and moving to C is a bad idea because the two languages are really nothing alike, and you won't be doing yourself any favors because you will run into serious issues porting it if you rely on any features java has that C doesn't (i.e. most of them)
That said, I'll sketch out some algorithmic C stuff.
Support Structures
typedef
struct Node
{
int x, y;
// x and y are array indices
}
Node;
typedef
struct Path
{
int maxlen, head;
Node * path;
// maxlen is size of path, head is the index of the current node
// path is the pointer to the node array
}
Path;
int node_compare(Node * n1, Node * n2); // returns true if nodes are equal, else false
void path_setup(Path * p, Node * n); // allocates Path.path and sets first node
void path_embiggen(Path * p); // use realloc to make path bigger in case it fills up
int path_toosmall(Path * p); // returns true if the path needs to be reallocated to add more nodes
Node * path_head(Path * p); // returns the head node of the path
void path_push(Path * p, Node * n); // pushes a new head node onto the path
void path_pop(Path * p); // pops a node from path
You might to change your maze format into an adjacency list sort of thing. You could store each node as a mask detailing which nodes you can travel to from the node.
Maze Format
const int // these constants indicate which directions of travel are possible from a node
N = (1 << 0), // travel NORTH from node is possible
S = (1 << 1), // travel SOUTH from node is possible
E = (1 << 2), // travel EAST from node is possible
W = (1 << 3), // travel WEST from node is possible
NUM_DIRECTIONS = 4; // number of directions (might not be 4. no reason it has to be)
const int
START = (1 << 4), // starting node
FINISH = (1 << 5); // finishing node
const int
MAZE_X = 4, // maze dimensions
MAZE_Y = 4;
int maze[MAZE_X][MAZE_Y] =
{
{E, S|E|W, S|E|W, S|W },
{S|FINISH, N|S, N|START, N|S },
{N|S, N|E, S|E|W, N|S|W },
{N|E, E|W, N|W, N }
};
Node start = {1, 2}; // position of start node
Node finish = {1, 0}; // position of end node
My maze is different from yours: the two formats don't quite map to each other 1:1. For example, your format allows finer movement, but mine allows one-way paths.
Note that your format explicitly positions walls. With my format, walls are conceptually located anywhere where a path is not possible. The maze I created has 3 horizontal walls and 5 vertical ones (and is also enclosed, i.e. there is a continuous wall surrounding the whole maze)
For your brute force traversal, I would use a depth first search. You can map flags to directions in a number of ways, like maybe the following. Since you are looping over each one anyway, access times are irrelevant so an array and not some sort of faster associative container will be sufficient.
Data Format to Offset Mappings
// map directions to array offsets
// format is [flag], [x offset], [y offset]
int mappings[][] =
{
{N, -1, 0},
{S, 1, 0},
{E, 0, 1},
{W, 0, -1}
}
Finally, your search. You could implement it iteratively or recursively. My example uses recursion.
Search Algorithm Pseudocode
int search_for_path(int ** maze, char ** visited, Path * path)
{
Node * head = path_head(path);
Node temp;
int i;
if (node_compare(head, &finish)) return 1; // found finish
if (visited[head->x][head->y]) return 0; // don't traverse again, that's pointless
visited[head->x][head->y] = 1;
if (path_toosmall(path)) path_embiggen(path);
for (i = 0; i < NUM_DIRECTIONS; ++i)
{
if (maze[head->x][head->y] & mappings[i][0]) // path in this direction
{
temp = {head->x + mappings[i][1], head->y + mappings[i][2]};
path_push(path, &temp);
if (search_for_path(maze, visited, path)) return 1; // something found end
path_pop(path);
}
}
return 0; // unable to find path from any unvisited neighbor
}
To call this function, you should set everything up like this:
Calling The Solver
// we already have the maze
// int maze[MAZE_X][MAZE_Y] = {...};
// make a visited list, set to all 0 (unvisited)
int visited[MAZE_X][MAZE_Y] =
{
{0,0,0,0},
{0,0,0,0},
{0,0,0,0},
{0,0,0,0}
};
// setup the path
Path p;
path_setup(&p, &start);
if (search_for_path(maze, visited, &path))
{
// succeeded, path contains the list of nodes containing coordinates from start to end
}
else
{
// maze was impossible
}
It's worth noting that because I wrote this all in the edit box, I haven't tested any of it. It probably won't work on the first try and might take a little fiddling. For example, unless start and finish are declared globally, there will be a few issues. It would be better to pass the target node to the search function instead of using a global variable.

Categories

Resources