Mark movements available in chess

1

I hope you can answer the question I have.

What I want to do with my chess program is that when I select a piece of the board I can mark all the boxes where this piece can move, an example would be the peon, assuming it is the first move that any peon will make which you select will have 2 possible squares to which you can move, it can be 1 square towards the front or 2 squares towards the front. The way I would like to mark these boxes is with some image as I do when selecting any piece of chess as I do in the paintcomponent class of the Display class.

Here I leave you a video of what you want to achieve, it is not necessary to go ahead, the videos will be played in the exact second of what I want to achieve: link

I already tried creating different classes for my program and different conditions, no method worked for me.

If you need it, I'll give you the complete project link: link

GAME CLASS

package chess;

import java.util.List;
import java.util.ArrayList;

import static chess.PieceColor.*;

class Game {

    Game() {
        _moves = new ArrayList<Move>();
        _gui = new ChessGUI("Ajedrez", this);
        newGame();
    }

    public void newGame() {
        initializeBoard();
        _moves.clear();
        _turn = WHITE;
        _selectedX = -1;
        _selectedY = -1;
    }

    public void quit() {
        System.exit(0);
    }

    public void undoMove() {
        if (_moves.size() > 0) {
            Move lastMove = _moves.remove(_moves.size() - 1);
            makeMove(lastMove.undoMove());
            _moves.remove(_moves.size() - 1);
        }
    }

    public void makeMove(Move move) {
        _moves.add(move);
        if (!move.isDouble()) {
            SingleMove singlemove = (SingleMove) move;
            executeMove(singlemove);
        } else {
            DoubleMove doublemove = (DoubleMove) move;
            executeMove(doublemove.move1());
            executeMove(doublemove.move2());
        }
        _turn = _turn.opposite();
    }

    private void executeMove(SingleMove move) {
        _board[move.x1()][move.y1()] = move.replace();
        if (move.replace() != null) {
            move.replace().setLocation(move.x1(), move.y1());
        }
        _board[move.x2()][move.y2()] = move.selected();
        if (move.selected() != null) {
            move.selected().setLocation(move.x2(), move.y2());
        }
        if (move.target() != null) {
            move.target().setLocation(-1, -1);
        }
    }

    public boolean inCheck(PieceColor color) {
        int x = kingX(color);
        int y = kingY(color);
        for (int i = 0; i < 8; i++) {
            for (int j = 0; j < 8; j++) {
                Piece p = get(i, j);
                if (p != null && p.color() == color.opposite()
                    && p.canCapture(x, y)) {
                    return true;
                }
            }
        }
        return false;
    }

    public boolean noMoves() {
        for (int i = 0; i < 8; i++) {
            for (int j = 0; j < 8; j++) {
                Piece p = get(i, j);
                if (p != null && p.color() == _turn) {
                    if (p.hasMove()) {
                        return false;
                    }
                }
            }
        }
        return true;
    }

    public boolean guarded(int x, int y) {
        for (int i = 0; i < 8; i++) {
            for (int j = 0; j < 8; j++) {
                Piece p = get(i, j);
                if (p != null && p.color() == _turn.opposite()
                    && p.canCapture(x, y)) {
                    return true;
                }
            }
        }
        return false;
    }

    public Piece get(int i, int j) {
        return _board[i][j];
    }

    public Piece lastMover() {
        return _moves.get(_moves.size() - 1).movedPiece();
    }

    private void initializeBoard() {
        Piece blackRo0 = new Rook(BLACK, this, 0, 0);
        Piece blackKn0 = new Knight(BLACK, this, 1, 0);
        Piece blackBi0 = new Bishop(BLACK, this, 2, 0);
        Piece blackQu0 = new Queen(BLACK, this, 3, 0);
        _blackKi = new King(BLACK, this, 4, 0);
        Piece blackBi1 = new Bishop(BLACK, this, 5, 0);
        Piece blackKn1 = new Knight(BLACK, this, 6, 0);
        Piece blackRo1 = new Rook(BLACK, this, 7, 0);
        Piece blackPa0 = new Pawn(BLACK, this, 0, 1);
        Piece blackPa1 = new Pawn(BLACK, this, 1, 1);
        Piece blackPa2 = new Pawn(BLACK, this, 2, 1);
        Piece blackPa3 = new Pawn(BLACK, this, 3, 1);
        Piece blackPa4 = new Pawn(BLACK, this, 4, 1);
        Piece blackPa5 = new Pawn(BLACK, this, 5, 1);
        Piece blackPa6 = new Pawn(BLACK, this, 6, 1);
        Piece blackPa7 = new Pawn(BLACK, this, 7, 1);
        Piece whiteRo0 = new Rook(WHITE, this, 0, 7);
        Piece whiteKn0 = new Knight(WHITE, this, 1, 7);
        Piece whiteBi0 = new Bishop(WHITE, this, 2, 7);
        Piece whiteQu0 = new Queen(WHITE, this, 3, 7);
        _whiteKi = new King(WHITE, this, 4, 7);
        Piece whiteBi1 = new Bishop(WHITE, this, 5, 7);
        Piece whiteKn1 = new Knight(WHITE, this, 6, 7);
        Piece whiteRo1 = new Rook(WHITE, this, 7, 7);
        Piece whitePa0 = new Pawn(WHITE, this, 0, 6);
        Piece whitePa1 = new Pawn(WHITE, this, 1, 6);
        Piece whitePa2 = new Pawn(WHITE, this, 2, 6);
        Piece whitePa3 = new Pawn(WHITE, this, 3, 6);
        Piece whitePa4 = new Pawn(WHITE, this, 4, 6);
        Piece whitePa5 = new Pawn(WHITE, this, 5, 6);
        Piece whitePa6 = new Pawn(WHITE, this, 6, 6);
        Piece whitePa7 = new Pawn(WHITE, this, 7, 6);
        Piece[][] newBoard = {
            {blackRo0, blackPa0, null, null, null, null, whitePa0, whiteRo0},
            {blackKn0, blackPa1, null, null, null, null, whitePa1, whiteKn0},
            {blackBi0, blackPa2, null, null, null, null, whitePa2, whiteBi0},
            {blackQu0, blackPa3, null, null, null, null, whitePa3, whiteQu0},
            {_blackKi, blackPa4, null, null, null, null, whitePa4, _whiteKi},
            {blackBi1, blackPa5, null, null, null, null, whitePa5, whiteBi1},
            {blackKn1, blackPa6, null, null, null, null, whitePa6, whiteKn1},
            {blackRo1, blackPa7, null, null, null, null, whitePa7, whiteRo1} };
        _board = newBoard;
    }

    public int kingX(PieceColor color) {
        if (color == WHITE) {
            return _whiteKi.getX();
        } else {
            return _blackKi.getX();
        }
    }

    public int kingY(PieceColor color) {
        if (color == WHITE) {
            return _whiteKi.getY();
        } else {
            return _blackKi.getY();
        }
    }

    public void setSelectedX(int x) {
        _selectedX = x;
    }

    public void setSelectedY(int y) {
        _selectedY = y;
    }

    public int selectedX() {
        return _selectedX;
    }

    public int selectedY() {
        return _selectedY;
    }

    public Piece[][] board() {
        return _board;
    }

    public PieceColor turn() {
        return _turn;
    }

    private Piece[][] _board;

    private ChessGUI _gui;

    private PieceColor _turn;

    private List<Move> _moves;

    private King _blackKi;

    private King _whiteKi;

    private int _selectedX;

    private int _selectedY;

}

DISPLAY CLASS

package chess;

import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Rectangle;

import javax.imageio.ImageIO;

import java.io.InputStream;
import java.io.IOException;

class GameDisplay extends Pad {

    public static final double MULTIPLIER = 0.7;

    public static final int BOARD = (int) Math.round(700 * MULTIPLIER);

    public static final int CELL = (int) Math.round(74 * MULTIPLIER);

    public static final int MARGIN = (int) Math.round(53 * MULTIPLIER);

    public GameDisplay(Game game) {
        _game = game;
        setPreferredSize(BOARD, BOARD);
    }

    private Image getImage(String name) {
        InputStream in = getClass().getResourceAsStream("/chess/images/"
            + name);
        try {
            return ImageIO.read(in);
        } catch (IOException excp) {
            return null;
        }
    }

    private Image getPieceImage(Piece piece) {
        return getImage("pieces/" + piece.imageString() + ".png");
    }

    private void paintPiece(Graphics2D g, Piece piece, int x, int y) {
        if (piece != null) {
            g.drawImage(getPieceImage(piece), x, y, CELL, CELL, null);
        }
    }

    @Override
    public synchronized void paintComponent(Graphics2D g) {
        Rectangle b = g.getClipBounds();
        g.fillRect(0, 0, b.width, b.height);
        g.drawImage(getImage("chessboard.jpg"), 0, 0, BOARD, BOARD, null);
        g.setColor(Color.yellow);
        if (_game.inCheck(_game.turn())) {
            g.drawImage(getImage("inCheck.png"),
                CELL * _game.kingX(_game.turn()) + MARGIN,
                CELL * _game.kingY(_game.turn()) + MARGIN, CELL, CELL, null);
        }
        if (_game.selectedX() != -1) {
            g.drawImage(getImage("selected.png"),
                CELL * _game.selectedX() + MARGIN,
                CELL * _game.selectedY() + MARGIN, CELL, CELL, null);
        }
        for (int i = 0; i < 8; i++) {
            for (int j = 0; j < 8; j++) {
                paintPiece(g, _game.get(i, j),
                    CELL * i + MARGIN, CELL * j + MARGIN);
            }
        }
    }

    private final Game _game;

}
    
asked by ASASCED 04.04.2018 в 07:19
source

1 answer

3

After spending some time analyzing the game I have managed to mark the movements valid for each of the pieces.

The key steps are:

Modify the Piece interface so that the pieces that implement should incorporate the ArrayList method getValidMoves ():

import java.awt.Point;
import java.util.ArrayList;
public interface Piece {

    String imageString();
    PieceColor color();
    PieceType type();
    boolean makeValidMove(int a, int b);
    boolean hasMove();
    boolean canCapture(int a, int b);
    void setLocation(int x, int y);
    ArrayList<Point> getValidMoves();
}

The next step is to implement getValidMoves () on each of the pieces , as well as to incorporate some private auxiliary methods . I leave the example of Pawn, in the other pieces is similar:

public ArrayList<Point> getValidMoves(){
    ArrayList<Point> validMoves = new ArrayList<Point>();
    for (int x=0;x<8;x++)
    {
        for (int y=0;y<8;y++)
        {
            //System.out.println("x =" + x + ", y = " + y);
            if (isValidMove(x,y)) {
                //System.out.println("Is valid move");
                validMoves.add(new Point(x,y)); 
            }
        }
    }
    return validMoves;
}
public boolean isValidMove(int a, int b){
    if (_y == start()) {
        if (b == _y + 2 * direction()) {
            if (a == _x && _game.get(a, _y + direction()) == null
                && _game.get(a, b) == null) {
                Move move = new SingleMove(this, _x, _y,
                    _game.get(a, b), a, b);
                return simulateMoveCareful(move);
            } else {
                return false;
            }
        }
    }
    if (b == _y + direction()) {
        if (a == _x && _game.get(a, b) == null) {
            if (b == start() + 6 * direction()) {
                SingleMove move1 = new SingleMove(this, _x, _y,
                    _game.get(a, b), a, b);
                Piece newQu = new Queen(_color, _game, a, b);
                SingleMove move2 = new SingleMove(newQu, a, b, this, a, b);
                DoubleMove move = new DoubleMove(move1, move2);
                return simulateMoveCareful(move);
            } else {
                Move move = new SingleMove(this, _x, _y,
                    _game.get(a, b), a, b);
                return simulateMoveCareful(move);
            }
        } else if (Math.abs(a - _x) == 1 && _game.get(a, b) != null
            && _game.get(a, b).color() != _color) {
            if (b == start() + 6 * direction()) {
                SingleMove move1 = new SingleMove(this, _x, _y,
                    _game.get(a, b), a, b);
                Piece newQueen = new Queen(_color, _game, a, b);
                SingleMove move2 = new SingleMove(newQueen, a, b,
                    this, a, b);
                DoubleMove move = new DoubleMove(move1, move2);
                return simulateMoveCareful(move);
            } else {
                Move move = new SingleMove(this, _x, _y,
                    _game.get(a, b), a, b);
                return simulateMoveCareful(move);
            }
        } else if (Math.abs(a - _x) == 1 && _game.get(a, b) == null
            && _y == start() + 3 * direction() && _game.get(a, _y) != null
            && _game.get(a, _y).color() != _color
            && _game.get(a, _y).type() == PAWN
            && _game.get(a, _y) == _game.lastMover()) {
            return true;

        } else {
            return false;
        }
    } else {
        return false;
    }

}

private boolean simulateMoveCareful(Move move) {
    _game.makeMove(move);
    boolean moveSimulationResult = true;
    if (_game.inCheck(_game.turn().opposite())) {
        moveSimulationResult = false;
    }
    _game.undoMove();
    return moveSimulationResult;
}

As you can see, and as Kiko_L also pointed out, you must support the use of the makeValidMove method to create isValidMove. In addition to replacing makeValidMove with simulateValidMove to prevent movement (_game.undoMove ()).

Finally, it will only be necessary to slightly modify the paintComponent (Graphics2D g) method of the GameDisplay class as well as create a new png image that should serve to mark the valid positions :

public synchronized void paintComponent(Graphics2D g) {
    Rectangle b = g.getClipBounds();
    g.fillRect(0, 0, b.width, b.height);
    g.drawImage(getImage("chessboard.jpg"), 0, 0, BOARD, BOARD, null);
    if (_game.inCheck(_game.turn())) {
        g.drawImage(getImage("inCheck.png"),
            CELL * _game.kingX(_game.turn()) + MARGIN,
            CELL * _game.kingY(_game.turn()) + MARGIN, CELL, CELL, null);
    }
    if (_game.selectedX() != -1) {
        //Dibujamos un cuadrado sobre la pieza seleccionada
        g.drawImage(getImage("selected.png"),
            CELL * _game.selectedX() + MARGIN,
            CELL * _game.selectedY() + MARGIN, CELL, CELL, null);

        //Dibujamos cuadrados para cada uno de los movimientos validos de la pieza selecconada
        Piece p = _game.get(_game.selectedX(), _game.selectedY());
        for (java.awt.Point validMovementPoint:p.getValidMoves())
        {
            g.drawImage(getImage("validMovement.png"),
                    CELL * validMovementPoint.x + MARGIN,
                    CELL * validMovementPoint.y + MARGIN, CELL, CELL, null);
        }
    }
    for (int i = 0; i < 8; i++) {
        for (int j = 0; j < 8; j++) {
            paintPiece(g, _game.get(i, j),
                CELL * i + MARGIN, CELL * j + MARGIN);
        }
    }
}  

As a final comment, to say that there is a lot of common code in the classes and that this could be placed in a superclasse abstract called Piece that implemented IPiece, going to rename the Piece interface as IPiece.

Greetings,

David.

    
answered by 09.04.2018 / 13:17
source