Java- Iterating backwards through Array under a condition - java

So for one of my game models, there is an array of elements represented as a string "--X-X" so that this board has 5 boxes, and positions are 0-4. Each 'X' can only move left. There is an "X-Index" so that if I run getIXPosition(1) it will return the position of the first X which is 2. And getXPosition(2) will return second X's position which is 4. So the string board is "--X-X" but in my code it's represented as an array as "00102" so that I can keep track of xIndex.
Now my issue is that I need to make a move method that prevents the second x from skipping over the first X into position 1 or 0. That is not allowed in this game. I thought I wrote the method correctly but my tests aren't passing when I test to make sure second X can not hop over any X's before it.
public void move(int xIndex, int newPosition)
{
int oldPosition = getXPosition(xIndex);
for(int i= oldPosition - 1; i >= 0;i--)
{
while (board[i] == 0 )
{
board[oldPosition] = '0'; // so this spot is open '-'
board[newPosition] = xIndex;
}
throw new IllegalArgumentException("Error cannot move X to new position");
}
}
What am I doing wrong?

If you know the position you want to move to, you don't have to search for it, just move there.
if (board[newPosition] == '0') {
board[newPosition[ = xIndex;
board[oldPosition] = '0';
} else {
throw new IllegalArgumentException("Error cannot move X to new position");
}
Note: The character '0' is not the value 0 (Actually it is 48 in ASCII)

I think the code is a bit flawed. First, I don't think you need to iterate all the way to 0. You should only iterate until you hit newPosition.
Then the while loop doesn't make much sense. I think you were after an if.
Lastly, personally I wouldn't throw an IllegalArgumentException in this case (actually, you're throwing after the first iteration regardless, so that's another flaw). It's the state of the board that's problematic, not the arguments. I would maybe throw IllegalArgumentException if one of the arguments was negative etc.
public void move(int xIndex, int newPosition) {
int oldPosition = getXPosition(xIndex);
for(int i= oldPosition - 1; i >= newPosition; i--) {
if(board[i] == '0') {
board[oldPosition] = '0';
board[i] = xIndex;
oldPosition = i;
} else {
//throw some custom exception; we found the other X here.
}
}
}

Related

Array from recursive call being overwritten

We're making a program to solve an asterisk sudoku via a recursive approach with back tracking.
The solveIt method calls the solve method which is the recursive method. grid is declared before to be a 9x9 2D array that contains the puzzle to be filled in. If there is one solution, the program must print out the completed puzzle however if there are more solutions it must only print out the number of possible solutions.
Question is: Inside of solve, print(); works just fine and prints out the complete puzzle. However outside of the method it prints out the empty initial puzzle. Why is this? We cannot figure out why a separate variable (h in this case) also gets randomly overwritten when solve completes.
int[][] h;
int solutionCounter = 0;
void solve() {
int[] next = findEmptySquare();
if (!(next[0] == -1 && next[1] == -1)) {
if (grid[next[0]][next[1]] == 0) {
for (int i = SUDOKU_MIN_NUMBER; i <= SUDOKU_MAX_NUMBER; i++) {
if (!(givesConflict(next[0], next[1], i))) {
//fills in the puzzle
grid[next[0]][next[1]] = i;
//go to next number
solve();
}
}
grid[next[0]][next[1]] = 0;
}
} else {
//print(); here it works just fine
solutionCounter++;
h = grid.clone();
}
}
void solveIt() {
solve();
if (solutionCounter > 1) {
System.out.println(solutionCounter);
} else {
grid = h.clone();
print(); //here it prints the empty puzzle
}
}
Solution
The .clone() method seems to simply reference h to grid. So h points to grid and takes on its values leading to the problem we were having above.
Therefore the following solution was implemented:
//copy the grid into h.
for (int x = 0; x < 9; x++) {
for (int y = 0; y < 9; y++) {
h[x][y] = grid[x][y];
}
}
More information on clone():
https://www.geeksforgeeks.org/clone-method-in-java-2/

What is wrong with my method to see if a value is in a 2D array in O(n) time?

I'm trying to write a method that takes a 2D array(arranged so that the elements in every row are in increasing order from left to right, and the elements in every column are in increasing order from top to bottom) and an int, and sees if the int is in the 2D array. I wanted to use nested loops, but that would make it go in O(N^2) time. I'm therefore trying to make conditionals that make it so it tests if the int is smaller than the first in one of the sub arrays and bigger than the last, and if so, goes onto the next subarray. Here's what I have:
static boolean has(int number, int[][] a) {
int q = 0;
boolean c = false;
for (int i = 0; i < a[q].length-1; i++){
if ((number < a[i][q]) || (number > a[a[j].length-1][i])){
q++;
}
else if (number == a[i][q]){
c = true;
break;
}
else c = false;
}
return c;
}
could use some help. This method compiles but gives me outOfBounds Thanks!
This solution runs in O(n+m):
static boolean has(int number, int[][] a) {
int row = 0;
int col = a[0].length - 1;
while (row < a.length && col >= 0) {
int n = a[row][col];
if (n < number) {
row++;
} else if (n > number) {
col--;
} else {
return true;
}
}
return false;
}
You can solve this in O(log(n) + log(m)) first find the row that contain the integer you're looking for using binary search (since columns are sorted), then find the exact position of the integer in that row, by performing another binary search (since rows are sorted).

Minimax Connect 4 AI trouble

I am making connect 4 AI, except the game continues until all 42 spaces are filled.
Score is kept by every 4 in a row gets 1 point.
public int[] Max_Value(GameBoard playBoard, int depth){
GameBoard temp = new GameBoard(playBoard.playBoard);
int h = 0, tempH = 999, tempCol=0;
int myDepth = depth - 1;
int[] tempH2 = new int[2];
boolean noChildren = true;
if(myDepth != -1){
for(int i = 0; i < 7; i++){
if(temp.isValidPlay(i)){
count++;
temp.playPiece(i);
noChildren = false;
tempH2 = Min_Value(temp, myDepth);
if(tempH2[1] < tempH){
tempH=tempH2[1];
tempCol = i;
}
temp.removePiece(i);
}
}
}
int[] x = new int[2];
if(noChildren){
h = temp.getHeuristic();
}
else{
h = tempH;
x[0]=tempCol;
}
x[1]=h;
return x;
}
public int[] Min_Value(GameBoard playBoard, int depth){
GameBoard temp = new GameBoard(playBoard.playBoard);
int h = 0, tempH = -999, tempCol=0;
int myDepth = depth - 1;
int[] tempH2 = new int[2];
boolean noChildren = true;
if(myDepth != -1){
for(int i = 0; i < 7; i++){
if(temp.isValidPlay(i)){
count++;
temp.playPiece(i);
noChildren = false;
tempH2 = Max_Value(temp, myDepth);
if(tempH2[1] > tempH){
tempH=tempH2[1];
tempCol = i;
}
temp.removePiece(i);
}
}
}
int[] x = new int[2];
if(noChildren){
h = temp.getHeuristic();
}
else{
h = tempH;
x[0]=tempCol;
}
x[1]=h;
return x;
}
I feel like I just stumbled through everything, and it feels like terrible code. However, I have never attempted anything like this before, and would appreciate any input. I can't tell where I am going wrong. My evaluation function just gives 1 point for each 4 in a row it can find for any given state. The main function calls the Min_Value function to start things off with a depth of 10.
I am attempting to return the column as well as the value of the heuristic. I hope I have provided enough information. Thanks for any insight.
Allright, after implementing the methods not shown (like evaluation, playmove, remove etc.) I was able to debug this. Assuming that these functions are implemented in some correct way in your version, the mistake is that you never actually call the evaluation function if depth is -1:
You have this:
[...]if(myDepth != -1)
{/*restofthecode*/}[...]
But what you need is something like this:
[...]if(myDepth == -1)
{
return temp.getHeuristic();
}
/*restofthecode*/
[...]
That way, whenever you reach depth -1 (a leaf in your minimax tree), the board will be evaluated and the value returned (which is excactly what you need in minimax).
Do this modification in both parts (min and max) and everything shuold be allright. If there are other problems, feel free to ask.
Even though it isn't stated in the question, I think you are not getting good moves from your search, right?
Without looking through your while code, I can already say that your program will only work during the last 10 moves of the game (last 10 empty fields or forced win in 10). Otherwise, your program will return either the last or the first move it evaluated. That is because of your evaluation function, where you only handle a win (respectively 4 in a row), but not 2 in a row, traps, 3 in a row, etc.). It will think of all moves as equal if it can't force a win.
This is a problem, because starting with an empty field, a win can only be forced by the starting player, and just with the 2nd last piece to be placed on the board. (In your version 4 in a row forced).
And since your searchdepth (10) is smaller than the maximum game moves (42), your program will always play its first move.
If the rest of your algorithm is correctly implemented, you can fix this by simply improve your evaluation function, so that it can differ between "good" and "bad" game positions.

When navigating a 2D array, check neighboring elements for valid path relative to point of entry?

The nature of this problem has changed since submission, but the question isn't fit for deletion. I've answered the problem below and marked it as a community post.
I'm writing a recursive path-navigating function and the final piece I need involves knowing which cell you came from, and determining where to go next.
The Stage
You are given a 2d array where 0's denote an invalid path and 1's denote a valid path. As far as I know, you are allowed to manipulate the data of the array you're navigating, so I mark a traveled path with 2's.
The Goal
You need to recursively find and print all paths from origin to exit. There are four mazes, some with multiple paths, dead ends, or loops.
I've written code that can correctly handle all three cases, except the method for finding the next path is flawed in that it starts at a fixed location relative to your current index, and checks for a travelled path; If you encounter it, it's supposed to retreat.
While this works in most cases, it fails in a case when the first place it checks happens to be the place you came from. At this point, it returns out and ends prematurely.
Because of this, I need to find a way to intelligently start scanning (clockwise or anti-clockwise) based on where you came from, so that that place is always the last place checked.
Here is some code describing the process (note: edge cases are handled prior to this, so we don't need to worry about that):
private static void main()
{
int StartX = ;//Any arbitrary X
int StartY = ;//Any arbitrary Y
String Path = ""; //Recursive calls will tack on their location to this and print only when an exit path is found.
int[][] myArray = ;//We are given this array, I just edit it as I go
Navigator(StartX, StartY, Path, myArray);
}
private static void Navigator(int locX, int locY, String Path, int[][] myArray)
{
int newX = 0; int newY = 0;
Path = Path.concat("["+locX+","+locY+"]");
//Case 1: You're on the edge of the maze
boolean bIsOnEdge = (locX == 0 || locX == myArray.length-1 || locY == 0 || locY == myArray[0].length-1);
if (bIsOnEdge)
{
System.out.println(Path);
return;
}
int[][] Surroundings = surroundingsFinder(locX, locY, myArray);
for (int i = 0; i <= 7; i++)
{
//Case 2: Path encountered
if (Surroundings[0][i] == 1)
{
myArray[locX][locY] = 2;
newX = Surroundings[1][i];
newY = Surroundings[2][i];
Navigator(newX, newY, myArray, Path);
}
//Case 3: Breadcrumb encountered
if (Surroundings[0][i] == 2)
{
myArray[locX][locY] = 1;
return;
}
}
}
//generates 2D array of your surroundings clockwise from N to NW
//THIS IS THE PART THAT NEEDS TO BE IMPROVED, It always starts at A.
//
// H A B
// G - C
// F E D
//
static int[][] surroundingsFinder(int locX, int locY, int[][] myArray)
{
int[][] Surroundings = new int[3][8];
for (int i = -1; i <= 1; i++)
{
for (int j = -1; j <= 1; j++)
{
}
}
//Can be done simpler, is done this way for clarity
int xA = locX-1; int yA = locY; int valA = myArray[xA][yA];
int xB = locX-1; int yB = locY+1; int valB = myArray[xB][yB];
int xC = locX; int yC = locY+1; int valC = myArray[xC][yC];
int xD = locX+1; int yD = locY+1; int valD = myArray[xD][yD];
int xE = locX+1; int yE = locY; int valE = myArray[xE][yE];
int xF = locX+1; int yF = locY-1; int valF = myArray[xF][yF];
int xG = locX; int yG = locY-1; int valG = myArray[xG][yG];
int xH = locX-1; int yH = locY-1; int valH = myArray[xH][yH];
int[][] Surroundings = new int[3][8];
Surroundings[0][0] = valA; Surroundings[1][0] = xA; Surroundings[2][0] = yA;
Surroundings[0][1] = valB; Surroundings[1][1] = xB; Surroundings[2][1] = yB;
Surroundings[0][2] = valC; Surroundings[1][2] = xC; Surroundings[2][2] = yC;
Surroundings[0][3] = valD; Surroundings[1][3] = xD; Surroundings[2][3] = yD;
Surroundings[0][4] = valE; Surroundings[1][4] = xE; Surroundings[2][4] = yE;
Surroundings[0][5] = valF; Surroundings[1][5] = xF; Surroundings[2][5] = yF;
Surroundings[0][6] = valG; Surroundings[1][6] = xG; Surroundings[2][6] = yG;
Surroundings[0][7] = valH; Surroundings[1][7] = xH; Surroundings[2][7] = yH;
return Surroundings;
}
Can anyone help me with this? As you can see, surroundingsFinder always finds A first, then B all the way to H. This is fine if and only if you entered from H. But if fails on cases where you entered from A, so I need to make a way to intelligently determine where to start finding. Once I know this, I can probably adapt the logic so I no longer use a 2D array of values, as well. But so far I can't come up with the logic for the smart searcher!
NOTE: I am aware that Java does not optimize middle-recursion. It seems impossible to get tail recursion working for a problem like this.
The Solution
The initial goal was to print, from start to end, all of the paths that exit the array.
An earlier rendition of the script wrote "0" on treaded locations rather than "2", but for some reason I imagined that I needed the "2" and I needed to differentiate between "treaded path" and "invalid path".
In fact, due to the recursive nature of the problem, I discovered that you can in fact solve the problem writing only 0's as you go. Also, I no longer needed to keep track of where I came from and instead of checking clockwise over a matrix, I was iterating from left to right down the 3x3 matrix surrounding me, skipping my own cell.
Here is the completed code for such a solution. It prints to console upon finding an exit (edge) and otherwise traces itself around the maze, complete with recursion. To start the function, you are given a square 2D array of 0's and 1's where 1 is a valid path and 0 is invalid. You are also given a set of coordinates where you are "dropped in" (locX, locY) and an empty string that accumulates coordinates, forming a path that is later printed out (String Path = "")
Here is the code:
static void Navigator(int locX, int locY, int[][] myArray, String Path)
{
int newX = 0;
int newY = 0;
Path = Path.concat("["+locX+","+locY+"]");
if ((locX == 0 || locX == myArray.length-1 || locY == 0 || locY == myArray[0].length-1))
{//Edge Found
System.out.println(Path);
pathCnt++;
myArray[locX][locY] = 1;
return;
}
for (int row = -1; row <= 1; row++)
{
for (int col = -1; col <= 1; col++)
{
if (!(col == 0 && row == 0) && (myArray[locX+row][locY+col] == 1))
{ //Valid Path Found
myArray[locX][locY] = 0;
Navigator(locX+row, locY+col, myArray, Path);
}
}
}
//Dead End Found
myArray[locX][locY] = 1;
return;
} System.out.println(Path);
pathCnt++;
swamp[locX][locY] = 1;
return;
}
for (int row = -1; row <= 1; row++)
{
for (int col = -1; col <= 1; col++)
{
if (!(col == 0 && row == 0) && (swamp[locX+row][locY+col] == 1))
{ //Valid Path Found
swamp[locX][locY] = 0;
Navigator(locX+row, locY+col, swamp, Path);
}
}
}
//Dead End Found
swamp[locX][locY] = 1;
return;
}
As you may determine yourself, every time we "enter" a cell, we have 8 neighbors to check for validity. First, to save on run time and to avoid going out of the array during our for loop (it can't find myArray[i][j] if i or j point it outside, and it will error out), we check for edges. Since we're given the area of our swamp we use a truth comparison statement that essentially says ("(am I on the top or left edge?) or (am I on the bottom or right edge?)"). If we ARE on an edge, we print out the Path we're holding (thanks to deep copy, we have a unique copy of the original Path that only prints if we're on an edge, and includes our full set of coordinates).
If we aren't on an edge, then we start looking around us. We start at top left and move horizontally to bottom right, with a special check to make sure we're not checking where we're standing.:
A B C
D . E
F G H
This loop checks only for 1's and only calls the function up again should that happen. Why? Because it is the second-to-last case. There is only one extra situation that will occur, and if we reach the end of the function it means we hit that case. Why write extra code (checking for 0's to specifically recognize it?
So, as I just mentioned, if we exit the for loop, it means we didn't encounter any 1's at all. It means we're surrounded by zeros! It means we've hit a dead end, and that means that all we have to do is error our away out of that instance of the function, ergo the final return;.
All in all, the final function is simple. But coming from no background and having to realize the patterns and meanings of these cases, and after several failed attempts at this, it can take quite a bit of work. I was several days at work on perfecting this.
Happy coding, Everyone!
Your issue seems to be with:
if (Surroundings[0][i] == 2)
{
myArray[locX][locY] = 1;
return;
}
Perhaps this should be changed to:
if (Surroundings[0][i] == 2)
{
// not sure why you need this if it's already 1
myArray[locX][locY] = 1;
// go to next iteration of the "i" loop
// and keep looking for next available path
continue;
}
Your recursive method will automatically return when none of the surrounding cells satisfy the condition if (Surroundings[0][i] == 1).
PS: It's conventional to name your variables using small letter as the first character. For example: surroundings, path, startX or myVar

recursion cannot get this right

We have triangle made of blocks. The topmost row has 1 block, the next row down has 2 blocks, the next row has 3 blocks, and so on. Compute recursively (no loops or multiplication) the total number of blocks in such a triangle with the given number of rows.
triangle(0) → 0
triangle(1) → 1
triangle(2) → 3
This is my code:
public int triangle(int rows) {
int n = 0;
if (rows == 0) {
return n;
} else {
n = n + rows;
triangle(rows - 1);
}
}
When writing a simple recursive function, it helps to split it into the "base case" (when you stop) and the case when you recurse. Both cases need to return something, but the recursive case is going to call the function again at some point.
public int triangle(int row) {
if (row == 0) {
return 0;
} else {
return row + triangle(row - 1);
}
}
If you look further into recursive definitions, you will find the idea of "tail recursion", which is usually best as it allows certain compiler optimisations that won't overflow the stack. My code example, while simple and correct, is not tail recursive.
You are not making use of the return value of your function. Instead you always declare a new local variable. Otherwise your solution is quite close to the correct one. Also you should add another return in case you are not at row 0.
public static int triangle (int rows) {
int n = 0;
if (rows == 0) {
return n;
} else {
n = n + rows;
n = n + triangle(rows - 1);
}
return n;
}

Categories