0

I'm currently trying to implement a game of chess. I've structured it so that possible moves are generated for each piece type and stored in an array list. My board is a 2d array. I wondered how to write that if the xTo yTo(coordinates of spot wanted to move to) was a possible move then that move could be made, but it won't let me use the array list.contains(), any suggestions much appreciated! Here is an example of what I have. (The user enters the coordinates xFrom, yFrom then xTo yTo via the terminal) I'm now wondering if it would be easier to convert this to a boolean? and getting rid of the array list?

public Board() {
    this.boardsize = DEFAULT_SIZE;

    board = new char[boardsize][boardsize];

    // Clear all playable fields
    for (int x = 0; x < boardsize; x++)
        for (int y = 0; y < boardsize; y++)
            board[x][y] = FREE;

    board[0][7] = BLACKROOK;
    board[2][7] = BLACKBISHOP;
    board[5][7] = BLACKBISHOP;
    board[7][7] = BLACKROOK;
    board[0][0] = WHITEROOK;
    board[2][0] = WHITEBISHOP;
    board[5][0] = WHITEBISHOP;
    board[7][0] = WHITEROOK;

For the Rook....

public ArrayList<int[]> possibleMoves = new ArrayList<int[]>();


public ArrayList<int[]> generatePossibleMoves(char[][] gameBoard, int xFrom, int yFrom) {
    for (int i = 1; xFrom + i < gameBoard.length; i++) {
        if (getPieceColour(gameBoard, xFrom + i, yFrom) != getPieceColour(gameBoard, xFrom, yFrom)) {
            if (gameBoard[xFrom + i][yFrom] != FREE) {
                int[] move = {xFrom + i, yFrom};
                possibleMoves.add(move);
                break;                              //stops iterating here since a rook is not allowed to jump over other pieces
            } else
                {
                int[] move = {xFrom + i, yFrom};
                possibleMoves.add(move);
            }
        }
    }
    for (int i = 1; xFrom - i < gameBoard.length; i++) {
        if (getPieceColour(gameBoard, xFrom - i, yFrom) != getPieceColour(gameBoard, xFrom, yFrom)) {
            if (gameBoard[xFrom - i][yFrom] != FREE) {
                int[] move = {xFrom - i, yFrom};
                possibleMoves.add(move);
                break;
            }
            else
                {
                int[] move = {xFrom - i, yFrom};
                possibleMoves.add(move);
            }
        }
    }
    for (int i = 1; yFrom + i < gameBoard.length+1; i++) {       //makes sure the place to be moved is on the board
        if (getPieceColour(gameBoard, xFrom + i, yFrom) != getPieceColour(gameBoard, xFrom, yFrom)) {
            if (gameBoard[xFrom][yFrom+i] != FREE) {
                int[] move = {xFrom, yFrom+i};
                possibleMoves.add(move);
                break;
            }
            else
                {
                int[] move = {xFrom, yFrom+i};
                possibleMoves.add(move);
            }
        }
    }
    for (int i = 1; yFrom- i < gameBoard.length+1; i++)
        if (getPieceColour(gameBoard, xFrom, yFrom - 1) != getPieceColour(gameBoard, xFrom, yFrom)) {
            if (gameBoard[xFrom][yFrom - 1] != FREE) {
                int[] move = {xFrom, yFrom - 1};
                possibleMoves.add(move);
                break;
            } else {
                int[] move = {xFrom, yFrom - 1};
                possibleMoves.add(move);
            }
        }
    return possibleMoves;
}




public boolean moveLegal(char[][] gameBoard, int xFrom, int yFrom, int xTo, int yTo){
    generatePossibleMoves(gameBoard, xFrom,yFrom);

    if(possibleMoves.contains(xTo,yTo){
        //this is where I'm stuck
    }

}
NobodyNada
  • 7,529
  • 6
  • 44
  • 51
Shemar
  • 7
  • 3
  • Create a new Point class with x,y variable and implement hashcode and equals method on this class. Then change possibleMoves to Set. That will solve you current problem. On the algo side, I would recommend doing the validation directly without generating all the possible moves. – gagan singh Nov 09 '18 at 23:54
  • 1
    Please don't make more work for other people by vandalizing your posts. By posting on the Stack Exchange (SE) network, you've granted a non-revocable right, under the [CC BY-SA 3.0 license](//creativecommons.org/licenses/by-sa/3.0), for SE to distribute that content (i.e. regardless of your future choices). By SE policy, the non-vandalized version of the post is the one which is distributed. Thus, any vandalism will be reverted. If you want to know more about deleting a post please see: [How does deleting work? ...](https://meta.stackexchange.com/q/5221/271271) – Makyen Nov 10 '18 at 22:35

3 Answers3

0

To check if the move is possible, one way to do is to compare the couple { xTo, yTo } with all the legal moves you calculate through your generatePossibleMoves function :

public boolean moveLegal(char[][] gameBoard, int xFrom, int yFrom, int xTo, int 
yTo){
       int[] wantedMove = new int[] {xTo, yTo};
       ArrayList<int[]> possibleMoves = generatePossibleMoves(gameBoard, xFrom,yFrom);
       boolean isMoveLegal = possibleMoves.stream().anyMatch(possibleMove -> 
           Arrays.equals(wantedMove, possibleMove));
       return isMoveLegal;
}
Murat
  • 1,135
  • 8
  • 12
0

I would create another class Coordinates that implements correctly the equals method

public class Coordinates {
    int x = 0;
    int y = 0;

    public Coordinates(int x, int y) {
        super();
        this.x = x;
        this.y = y;
    }

    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + x;
        result = prime * result + y;
        return result;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        Coordinates other = (Coordinates) obj;
        if (x != other.x)
            return false;
        if (y != other.y)
            return false;
        return true;
    }


}

and then use this class for the type of ArrayList

So for example

public List<Coordinates> possibleMoves = new ArrayList<Coordinates>();

then the function becomes

public boolean moveLegal(char[][] gameBoard, int xFrom, int yFrom, int xTo, int yTo){
    generatePossibleMoves(gameBoard, xFrom,yFrom);
    Coordinates checkCoordinates = new Coordinates (xTo,yTo);
    if(possibleMoves.contains(xTo,yTo){
      ...
    }
}
Periklis Douvitsas
  • 2,431
  • 1
  • 13
  • 14
  • 1
    The best practice is to declare field type as generic as possivle. That's why I would suggest you to use `List` instead `ArrayList` and change `public ArrayList possibleMoves = new ArrayList();` to `public List possibleMoves = new ArrayList();` – ADS Nov 10 '18 at 00:04
  • Hi @ADS I absolutely agree. I have written a quick exam in order MuratK to see how he can use the contains method without changing too much his current code. – Periklis Douvitsas Nov 10 '18 at 00:06
  • 1
    Sure, don't get my comment as personal attack. I'm here just to help you to improve your answer since it could see many people, not only the author. – ADS Nov 10 '18 at 00:10
  • 1
    I have up voted both of your comments and edited my code.thanks! – Periklis Douvitsas Nov 10 '18 at 00:12
  • so would everything work if I just used list?(sorry I'm kinda new to programming – Shemar Nov 10 '18 at 06:07
  • also, is this @over ride needed? – Shemar Nov 10 '18 at 06:11
  • @Shemar Annotation `@Override` is not needed but it's much, much better to add it. It helps to avoid such silly mistakes like having `equals(Coordinates)` instead of `equals(Object)`. With `@Override` compiler would suggest that you have mistake. – ADS Nov 10 '18 at 07:30
  • @Shemar about `List` and `ArrayList` you could read more [in another question](https://stackoverflow.com/questions/147468/why-should-the-interface-for-a-java-class-be-preferred). In short, having `List` is just best-practice which helps when you when you change code (and you will do so even if not planning right now). But this change do not solve any problem: both options would compile. Also, I would suggest to have a book for Java beginners. It answer to many questions even before you ask them. – ADS Nov 10 '18 at 07:37
0

The main reason is you save in possibleMoves array but trying to check not an array. As described in documentation, List.contains() accepts only 1 parameter. Since you put array to your List, you could want to check against array: if(possibleMoves.contains({xTo,yTo})

But in fact it wouldn't work correctly. You mixed up possible moves from all pieces so you could select Queen and move to any point which could reach a Knight.

Offtopic: I would suggest you to use more OOP-style approach: use less raw arrays and more objects which reflects pieces. For example

enum Side { 
   White; Black; 
   public Side opposite() {
      if (this==White) return Black;
      else return White;
   }
}
// in separate file
class Pawn {
  private ChessSquare currentPosition;
  private final Side color;
  public boolean couldMoveTo(ChessSquare another) {
     if (currentPosition.x == another.x) {
       return another.y - currentPosition.y == 1; //TODO check for first move in two sruares
     } else if (another.hasPiece(this.color.opposite())) {
        // TODO allow to take enemy piece in diagonal
     }
  }
 public List<ChessField> possibleMoves() { 
   List<ChessField> result = new ArrayList<>();
   for (currentSquare in ALL_SQUARES) {
     if (couldMoveTo(currentSquare)) result.add(currentSquare)
   }
   return result;
}

My example is inefficient and could be improved in many ways. Also there are many other options how to organize code structure. I suppose it demonstrated how you could check if a piece could make move from perspective of this piece. Also you could hide many details (like en passant rule) inside Pawn class and in the same time have clear code at upper levels. You could see that possibleMoves() is very small and in fact could be common for all pieces.

P.S. Chess is a great game and I wish you could learn both chess and Java while creating your game.

ADS
  • 708
  • 3
  • 14
  • Thank you everyone for your responses, would it be easier to convert this method to a boolean? returning true if can move and false if not? – Shemar Nov 10 '18 at 06:03
  • @Shemar I just forgot to declare return type for method `couldMoveTo`. I updates answer – ADS Nov 10 '18 at 07:24