Sample code not doing as expected - java

Here is the algorithm (not working) Please let me know where the error is
Thanks
private void checkSouth(Location point, int player) {
//Loop through everything south
boolean isthereAnOppositePlayer=false;
int oppositePlayer=0;
//Set opposite player
if (player==1) {
oppositePlayer=2;
}else{
oppositePlayer=1;
}
for (int i = point.getVertical(); i < 8; i++) {
//Create a location point with the current location being compared
MyLocation locationBeingChecked= new MyLocation();
locationBeingChecked.setHorizontal(point.getHorizontal());
locationBeingChecked.setVertical(i);
int value = board[locationBeingChecked.getVertical()][locationBeingChecked.getHorizontal()];
//If the first checked is the opposite player
if (value==oppositePlayer) {
//Then potential to evaluate more
isthereAnOppositePlayer=true;
}
//If it isn't an opposite player, then break
if(!isthereAnOppositePlayer && value!=0){
break;
}
//If another of the player's piece found or 0, then end
if (isthereAnOppositePlayer && value==player || isthereAnOppositePlayer && value==0) {
break;
//end
}
//Add to number of players to flip
if(isthereAnOppositePlayer && value==oppositePlayer && value!=0){
//add to array
addToPiecesToTurn(locationBeingChecked);
}
}
}

It looks like the locations that got rotated back to the other player are the exact same as those rotated during the first move. I would guess that the array being populated by addToPiecesToTurn is perhaps not being cleared out between each move, so all the previous locations are still in there.
If you are storing the pieces to be turned in an ArrayList, you can use the clear() method to erase the contents of the collection between each turn.
Another possible problem is that you are checking for the opposite player, and then instantly beginning to populate addToPiecesToTurn. However, the pieces in that direction are not necessarily valid to be rotated unless they are "sandwiched" in by a second location containing the current player's piece. I don't think your code is properly checking for that case; when that happens, you'll want to somehow skip flipping those pieces to the other player, such as clearing out the array of piecesToTurn.
Edit: Looking at your current solution where you are implementing every direction separately, you are going to have a lot of duplicated code. If you think about what it means to walk along a certain direction, you can think of it as adjusting the x/y value by a "step" amount. The step amount could be -1 for backwards, 0 for no move, or 1 for forwards. Then you could create a single method that handles all directions without duplicating the logic:
private void checkDirection(Location point, int player, int yStep, int xStep) {
int x = point.getHorizontal() + xStep;
int y = point.getVertical() + yStep;
MyLocation locationBeingChecked = new MyLocation();
locationBeingChecked.setHorizontal(x);
locationBeingChecked.setVertical(y);
while (isValid(locationBeingChecked)) {
// do the logic here
x += xStep;
y += yStep;
locationBeingChecked = new MyLocation();
locationBeingChecked.setHorizontal(x);
locationBeingChecked.setVertical(y);
}
}
You would need to implement isValid to check that the location is valid, i.e., in the board. Then you could call this method for each direction:
// north
checkDirection(curPoint, curPlayer, -1, 0);
// north-east
checkDirection(curPoint, curPlayer, -1, 1);
// east
checkDirection(curPoint, curPlayer, 0, 1);
// etc

This is the sort of problem that is ripe for some unit testing. You could very easily set up a board, play a move, and validate the answer, and the test results would give plenty of insight into where your expectations and reality diverge.

why didn't you use a 2d array ?
each cell would contain an enum : EMPTY, PLAYER_1, PLAYER_2 .
then, in order to go over the cells, you simply use loops for each direction.
for example, upon clicking on a cell , checking to the right would be:
for(int x=pressedLocation.x+1;x<cells[pressedLocation.y].length;++x)
{
Cell cell=cells[pressedLocation.y][x];
if(cell==EMPTY||cell==currentPlayerCell)
break;
cells[pressedLocation.y][x]=currentPlayerCell;
}
checking from top to bottom would be:
for(int y=pressedLocation.y+1;y<cells.length;++y)
{
Cell cell=cells[y][pressedLocation.x];
if(cell==EMPTY||cell==currentPlayerCell)
break;
cells[y][pressedLocation.x]=currentPlayerCell;
}

Related

Find the value of a 2D arrays neighbors?

I have a 2d array that generates terrain using perlin noise, and then places a (3D) block at a specific height - Before you click away, all I need help with is the 2D array that generates the "height-map". I am trying to figure out whether or not the block next to it is at the same elevation (if it is "neighboring" or not) by checking the values directly up, down, left, and right in the 2D array. If they are equal, then they are at the same elevation, and therefore "neighbors". if the problem that I am running into is that the check is always returning true for all the neighbors, even if the block has no neighbors.
A small example of the perlin noise height map
151514141312121111
151414131313121211
141414131312121211
141313131312121211
131313121212121111
131312121212111111
121212121111111111
111111111110101111
111111111010101111
111111111010101010
111111111010101010
101011101010101010
101010101099109999
991010109999988889
999109999888888999
and here is the checking code, you will have to see the entire file, linked below for context
if (terrain[x][leftColumn] == terrain[x][z]) {
neighbors[2] = true; // left side
}
if (terrain[x][rightColumn] == terrain[x][z]) {
neighbors[3] = true; //right side
}
if (terrain[belowRow][z] == terrain[x][z]) {
neighbors[4] = true; // front side (below)
}
if (terrain[aboveRow][z] == terrain[x][z]) {
neighbors[5] = true; // back side (above)
}
Pastebin: https://www.pastiebin.com/5d5c5416391ec
any help is appreciated, Asher
Move this static variable initialization
boolean[] neighbors = new boolean[]{false, false, false, false, false, false};
inside the inner loop, where you check each block's neighbors, to instantiate a new neighbors array for each individual block. Right now neighbors is a static variable. You never reset the values on the neighbors array so it remains true after each iteration.
edit:
Also
if (belowRow > 1) {
belowRowExists = false;
belowRow = 0;
}
if (rightColumn > - 1) {
rightColumnExists = false;
rightColumn = 0;
}
is wrong, you want to check if the column or row is out of bounds right? Then you want to see if they are >= chunkSize.

Minmax algorithm doesn't return direct child of root (returns illegal move)

I am trying to create "AI" for Nine Men's Morris but I got hardstuck on minMax algorithm. Summing up, I was trying to find the issue for over 10h but didn't manage to. (debugging this recursion is nasty or I am doing it badly or both)
Since I started doubting everything I wrote I decided to post my issue so someone can find anything wrong in my version of minMax. I realise it is really hard task without the whole application so any suggestions where I should triple check my code are also very welcome.
Here is link to the video, explaining minMax, on which I based my implementation: https://www.youtube.com/watch?v=l-hh51ncgDI (First video that pops up on yt after searching for minmax - just in case you want to watch the video and don't want to click the link)
My minMax without alpha-beta pruning:
//turn - tells which player is going to move
//gameStage - what action can be done in this move, where possible actions are: put pawn, move pawn, take opponent's pawn
//depth - tells how far down the game tree should minMax go
//spots - game board
private int minMax(int depth, Turn turn, GameStage gameStage, Spot[] spots){
if(depth==0){
return evaluateBoard(spots);
}
//in my scenario I am playing as WHITE and "AI" is playing as BLACK
//since heuristic (evaluateBoard) returns number equal to black pawns - white pawns
//I have decided that in my minMax algorithm every white turn will try to minimize and black turn will try to maximize
//I dont know if this is correct approach but It seems logical to me so let me know if this is wrong
boolean isMaximizing = turn.equals(Turn.BLACK);
//get all possible (legal) actions based on circumstances
ArrayList<Action> children = gameManager.getAllPossibleActions(spots,turn,gameStage);
//this object will hold information about game circumstances after applying child move
//and this information will be passed in recursive call
ActionResult result;
//placeholder for value returned by minMax()
int eval;
//scenario for maximizing player
if(isMaximizing){
int maxEval = NEGATIVE_INF;
for (Action child : children){
//aplying possible action (child) and passing its result to recursive call
result = gameManager.applyMove(child,turn,spots);
//evaluate child move
eval = minMax(depth-1,result.getTurn(),result.getGameStage(),result.getSpots());
//resets board (which is array of Spots) so that board is not changed after minMax algorithm
//because I am working on the original board to avoid time consuming copies
gameManager.unapplyMove(child,turn,spots,result);
if(maxEval<eval){
maxEval = eval;
//assign child with the biggest value to global static reference
Instances.theBestAction = child;
}
}
return maxEval;
}
//scenario for minimizing player - the same logic as for maximizing player but for minimizing
else{
int minEval = POSITIVE_INF;
for (Action child : children){
result = engine.getGameManager().applyMove(child,turn,spots);
eval = minMax(depth-1,result.getTurn(),result.getGameStage(),result.getSpots());
engine.getGameManager().unapplyMove(child,turn,spots,result);
if(minEval>eval){
minEval=eval;
Instances.theBestAction = child;
}
}
return minEval;
}
}
Simple heuristic for evaluation:
//calculates the difference between black pawns on board
//and white pawns on board
public int evaluateBoard(Spot[] spots) {
int value = 0;
for (Spot spot : spots) {
if (spot.getTurn().equals(Turn.BLACK)) {
value++;
}else if(spot.getTurn().equals(Turn.WHITE)){
value--;
}
}
return value;
}
My issue:
//the same parameters as in minMax() function
public void checkMove(GameStage gameStage, Turn turn, Spot[] spots) {
//one of these must be returned by minMax() function
//because these are the only legal actions that can be done in this turn
ArrayList<Action> possibleActions = gameManager.getAllPossibleActions(spots,turn,gameStage);
//I ignore int returned by minMax() because,
//after execution of this function, action choosed by minMax() is assigned
//to global static reference
minMax(1,turn,gameStage,spots);
//getting action choosed by minMax() from global
//static reference
Action aiAction = Instances.theBestAction;
//flag to check if aiAction is in possibleActions
boolean wasFound = false;
//find the same action returned by minMax() in possibleActions
//change the flag upon finding one
for(Action possibleAction : possibleActions){
if(possibleAction.getStartSpotId() == aiAction.getStartSpotId() &&
possibleAction.getEndSpotId() == aiAction.getEndSpotId() &&
possibleAction.getActionType().equals(aiAction.getActionType())){
wasFound = true;
break;
}
}
//when depth is equal to 1 it always is true
//because there is no other choice, but
//when depth>1 it really soon is false
//so direct child of root is not chosen
System.out.println("wasFound?: "+wasFound);
}
Is the idea behind my implementation of minMax algorithm correct?
I think the error might exist in that you are updating Instances.theBestAction even while evaluating child moves.
For example, lets say 'Move 4' is the true best move that will eventually be returned, but while evaluating 'Move 5', theBestAction is set to the best child action of 'Move 5'. From this point on, you won't update the original theBestAction back to 'Move 4'.
Perhaps just a simple condition that only sets theBestAction when depth == originalDepth?
Rather than using a global, you could also consider returning a struct/object that contains both the best score AND the move that earned the score.

Converting a recursive method into a non-recursive method using loop in java

So I'm currently making a game where the instructions are to move left or right within an array using the integer stored at a marked index (circle in this case) until we can get the circle to the last index of the array. The last integer of the array is always 0.
For example,
[4] 1 2 3 1 0, here we start at the circle 0 (index)
We move 4 to the right, 4 1 2 3 [1] 0
Then 1 time to the right, 4 1 2 3 1 [0]. Here the game stops and we win.
My code is as follows for a recursive method:
public static boolean rightWing (int circle, int[] game, List<Integer> checkerList){
int last = game.length-1;
if (circle == last){ // base case for recursion
return true;
}
if (circle < 0){ // if we go out of bounds on the left
return false;
}
if (circle > last){ // if we go out of bounds on the right
return false;
}
if (checkerList.contains(circle)){ // check for the impossible case
return false;
}
checkerList.add(circle); // adds the circle value for the last check to checkerList so we can check for the impossible case
int moveRight = circle + game[circle]; // these two integers help the game move according to the value of the int at circle
int moveLeft = circle - game[circle];
return rightWing( moveRight, game, checkerList) || rightWing(moveLeft, game,checkerList);
}
This works great, but the only problem is it's recursive and slow. I'm trying to redesign it using loops and stacks/queues to make it more efficient, but I'm stuck after writing this (in pseudo):
Boolean rightWing (int circle, List<int> game, List<int> checkerList)
Int lastPlace = game.size() - 1
For int i <- 0 to game.size() - 1 do
If i equals lastPlace then // returns true when i is at the last position of the game
Return true
Any input on how to go forward would be appreciated!
The most important bit: when debugging app for the slowness, you should collect some performance data first to identify where your app is spending the most of its time. Otherwise fixing performance is inefficient. You can use jvisualvm it's bundled with jdk.
Data structures rule the world of performance
One thing why it can be slow is because of this:
if (checkerList.contains(circle)){ // check for the impossible case
return false;
}
The more items you have in the list, the slower it becomes. List has linear complexity for the contains method. You can make it constant complexity if you'll use HashSet. E.g. if you have list with 100 elements, this part will be around slower 100 times with List than with HashSet.
Another thing which might be taking some time is boxing/unboxing: each time you put element to the list, int is being wrapped into new Integer object - this is called boxing. You might want to use IntSet to avoid boxing/unboxing and save on the GC time.
Converting to the iterative form
I won't expect this to affect your application speed, but just for the sake of completeness of the answer.
Converting recursive app to iterative form is pretty simple: each of the method parameters under the cover is stored on a hidden stack on each call of your (or others function). During conversion you just create your own stack and manage it manually
public static boolean rightWingRecursive(int circle, int[] game) {
Set<Integer> checkerList = new HashSet<Integer>();
Deque<Integer> statesToExplore = new LinkedList<>();
int last = game.length - 1;
statesToExplore.push(circle);
while (!statesToExplore.isEmpty()) {
int circleState = statesToExplore.pop();
if (circleState == last) { // base case for recursion
return true;
}
if (circleState < 0) { // if we go out of bounds on the left
continue;
}
if (circleState > last) { // if we go out of bounds on the right
continue;
}
if (checkerList.contains(circle)) { // check for the impossible case
continue;
}
checkerList.add(circle); // adds the circle value for the last check to
// checkerList so we can check for the
// impossible case
int moveRight = circle + game[circle]; // these two integers help the
// game move according to the
// value of the int at circle
int moveLeft = circle - game[circle];
statesToExplore.push(moveRight);
statesToExplore.push(moveLeft);
}
return false;
}

Chess alpha beta returning wrong move for the board

I am trying to implement a chess game with alpha beta pruning. The following is almost working, but it returns wrong moves.
For example, the following can occur.
White (user) to move, white king position - a1 / Black (computer), black king position - h1
White moves its king from a1 - a2, then black return the move g2 - g1???
It appears that the computer returns a move for the wrong node (board representation), as if the best evaluation of a given board position is not being propagated all the way back up the tree. So in one of the simulated positions explored, the computer "imagines" its king moving to g2 and then returns the move to be made from this position, not realising that this position is a simulated position and not the representation of the actual board (the root node?).
How can I correct the code to make the computer return a move for the actual board representation and not one of the simulations by mistake?
Thank you.
Initial call alphaBeta(3, ChessEngine.invertBoard(ChessEngine.board), -10000, 10000, true);
private static int alphaBetaEvaluate = 0;
private static int alphaBetaSelectedSquare = 0;
private static int alphaBetaMoveToSquare = 0;
public static int alphaBeta(int depth, char[] board, int alpha, int beta, boolean maxPlayer) {
//create a copy of the board
char[] boardCopy = board.clone();
//if terminal state has not been met, keep searching
if (maxPlayer == true && depth > 0) {
//for all of the moves that max can make
for (int i = 0; i < board.length; i++) {
for (int move : ChessEngine.getValidMoves(i, boardCopy)) {
//make the move
boardCopy[move] = boardCopy[i];
boardCopy[i] = '.';
alphaBetaEvaluate = rating(board, boardCopy, i, move);
//store the best move to make
int temp = alphaBeta(--depth, ChessEngine.invertBoard(boardCopy), -10000, 10000, false);
if (temp > alpha) {
alphaBetaSelectedSquare = i;
alphaBetaMoveToSquare = move;
alpha = temp;
}
//reset the board for the next simulated move
boardCopy = board.clone();
if (beta <= alpha) {
break;
}
}
}
return alpha;
} else if (maxPlayer == false && depth > 0) {
//for all of the moves that min can make
for (int i = 0; i < board.length; i++) {
for (int move : ChessEngine.getValidMoves(i, boardCopy)) {
//make the move
boardCopy[move] = boardCopy[i];
boardCopy[i] = '.';
beta = Math.min(beta, alphaBeta(--depth, ChessEngine.invertBoard(boardCopy), -10000, 10000, true));
//reset the board for the next simulated move
boardCopy = board.clone();
if (beta <= alpha) {
break;
}
}
}
return beta;
}
return alphaBetaEvaluate;
}
I dont get your implementation after all. First of all what you want to do is create a tree. A decision tree and propagates the decision up. You want to maximize your evaluation and also expect that the enemy will select the move that minimizes your evaluation in return.
So inverting the board does not sound so reasonable for me unless you know that the evaluation you do uppon the situation is correctly adjusting.
Another serious problem for me is that you always call the min/max for the next move with -10k and 10k as the bounderies for alpha and beta. This way your algorithm does not 'learn' from previous moves.
What you need is to check the algorithm again (wikipedia for instance, which I used) and see that they use alpha and beta being modified by former evaluation. This way the calculation in higher depth can firstly stop and secondly evaluate the best move better.
I am no expert in this. its decades ago when I wrote my implementation and I used something different.
Another idea is not to use min and max within the same method but use the min and max methods instead. It makes it more likely you spot other defects.
Also do not use two kings for evaluation. There is no goal in that. Two kings are random, cant win. One thing might be two knights or four queens and alike. It is not so random and you can see the queens dancing around without being able to catch each other. Or use three knights versus a single queen.
And try to create yourself some unit tests around your other parts. Just to insure that the parts are working correctly independently. And why are you using characters? Why not using enums or objects. You can reuse the objets for each field (its more like kinds of figures).
But anyhow this is style and not algorithm correctness.

Making a player move on 2D array game grid

I am creating a game using a 10x10 2D array. The player starts at the top left hand corner indicated as "P" and the objective is to get the player to avoid obstacles to get to the treasure indicated as "T" located in the lower right corner.
How would I go about making the player move about the grid using commands Up/Down/Left/Right?
Would I use a for loop to count through the elements in the array to designate the move?
Here is what I have so far:
import java.util.Scanner;
import java.util.Random;
public class Adventure {
public static void main(String[] args) {
char grid[][]= new char[10][10];
Scanner move = new Scanner(System.in);
System.out.println("Here is the current game board:");
System.out.println("-------------------------------");
for(int i=0; i<grid.length; i++) {
for(int j=0; j<grid.length; j++) {
double random = Math.random();
if(random <=.05) {
grid[i][j]='*';
}
else if(random > .06 && random <= .15) {
grid[i][j]='X';
}
else {
grid[i][j]='.';
}
grid[0][0]='P';
grid[9][9]='T';
System.out.print(grid[i][j]);
}
System.out.println("");
}
System.out.print("Enter your move (U/D/L/R)>");
}
}
you should keep track of the current position of the player and just update those variables.
initial values would be (0,0) as you said.
int px = 0;
int py = 0;
when a move is made, update the variables accordingly:
grid[px][py] = <empty cell>;
switch (move) {
case 'u': py += 1; break;
case 'r': px += 1; break;
...
}
grid[px][py] = 'P';
of course you shouldn't just updated the values "blindly", you should insert some validation logic to follow the rules of the game:
if (grid[px][py] != <obstacle> )
// update player coordinates...
Looks like you're using row-major ordering, judging from the way your board prints out. Based on that, here's what you'll need to do:
First, you need to store the player's position somewhere. Right now it's hardcoded to 0,0.
Second, you need to read in the player's move. That will have to happen in a loop, where you get a move, check if the move is allowed, perform the move, and display the results.
Third, you need to be able to calculate the new position based on the move. Up means row -= 1. Right means column += 1. Etc.
Given the new coordinates, you need to make sure the move is valid. At the very least, you have to stop them from walking off the board, but you may also prevent them from entering a square with an obstacle, etc.
Once you know that the move is valid, you have to update the variables you're storing the current coordinates in.
At the end of the loop, you'll need to redraw the board.
That's the basic gist of it. Right now you are doing everything in main(), and that's okay, but if it were me I would start to split things out into separate methods, like InitializeBoard(), GetNextMove(), CheckIfMoveIsValid(int r, int c), and so on. That way, main() becomes a high-level view of your game loop, and the guts of the different operations are compartmentalized and more easy to deal with. This will require storing off things like your game board into class variables rather than local variables, which should actually make things like obstacle detection easier than it would be currently.
All of the above answers are great. Here are a few suggestions I would make:
Instead of a char two-dimensional array, I would make a custom object, such as Space, and define a two-dimensional array of Spaces (eg, Space[][]). There are a few reasons for this:
You can define a space in a variety of ways (rather than just 1 character). For example, Space[i][j].hasTreasure() can return a boolean to let you know whether or not you found the treasure.
If you want to add functionality later, its as easy as adding an attribute to your Space class. Again, you are not limited to one character here.
More to your question of movement, I would also recommend a few things. Similar to redneckjedi's suggestion of a CheckIfMoveIsValid() method, I would pass the grid and move direction as parameters and return a boolean. To ensure that you do not end up with ArrayIndexOutOfBounds issues, I would also suggest adding a row/column of walls on each side. I would widen the grid out to 12x12 and put a strip of obstacle-type blocks around the outside. This will ensure that you cannot step outside of the grid as hitting a wall will always return 'false' on a valid move.

Categories