Как проверить, безопасен ли ход в шахматах для шахматной игры на Java? [закрыто]JAVA

Программисты JAVA общаются здесь
Ответить Пред. темаСлед. тема
Anonymous
 Как проверить, безопасен ли ход в шахматах для шахматной игры на Java? [закрыто]

Сообщение Anonymous »

Сейчас я программирую игру в шахматы. Я хочу отметить все возможные ходы фигуры, если щелкну по ней. Чтобы ход был законным, он должен следовать за движением фигуры, находиться в границах шахматной доски и быть безопасным для собственного короля. Моя проблема связана с последним. Потому что, чтобы определить, атакует ли фигура короля после хода, вам придется смоделировать ее, а затем проверить, может ли что-то атаковать короля. но если просто обновить все возможные ходы и посмотреть, не атакует ли что-нибудь короля после симуляции, вы получите бесконечную рекурсию. Мой единственный способ заключался в том, чтобы иметь дополнительную переменную (canAttackKing // после хода) и метод, подобный тому, который определяет возможные ходы, только без проверки, безопасно ли это. По этой причине у меня есть методы canAttack и canAttack2 и так далее. Это просто раздражает и с этим трудно справиться. Постоянно возникают какие-то ошибки и т. д. Итак, мой вопрос: есть ли лучший способ определить, безопасен ли ход, чем просто просмотреть список всех вражеских фигур и посмотреть, может ли что-нибудь атаковать короля в точках x, y, как я это делаю? прямо сейчас?
Все Pieces имеют разные классы, которые наследуют класс Piece следующим образом:
import lombok.Getter;
import javafx.scene.image.Image;
import schach.SchachScreen.Chessboard;
import lombok.Setter;

import java.util.Objects;

@Getter
public abstract class Piece {
private final boolean white;
protected int x,y;
private final Image image;
protected Chessboard c;

@Setter
protected int[][] possibleMoves = new int[8][8]; // 0 = no move, 1 = move, 2 = capture

@Setter
protected boolean canAttackKing = false; // If something else Moves

public Piece(boolean white) {
this.white = white;
this.image = loadImage();
}

private Image loadImage() {
String color = white ? "white" : "black";
String className = this.getClass().getSimpleName().toLowerCase();
String imagePath = "/Images/figuren/" + color + "_" + className + ".png";
return new Image(Objects.requireNonNull(getClass().getResourceAsStream(imagePath)));
}

public void setPosition(int x, int y) {
this.x = x;
this.y = y;
}

public abstract void setPossibleMoves();

public abstract void updateCanAttackKing2();

public abstract String getFenNotation();

public boolean canAttackKing() {
return canAttackKing;
}

protected void addMoveIfSafe(int x, int y) {
if (c.simMovePiece(x, y, this)) {
possibleMoves[x][y] = c.getPiece(x, y) == null ? 1 : 2;
}
}

protected void checkDiagonals() {
c = Chessboard.getInstance();
int originalX = x;
int originalY = y;

checkLine(originalX, originalY, 1, 1); // Top-right
checkLine(originalX, originalY, -1, -1); // Bottom-left
checkLine(originalX, originalY, -1, 1); // Top-left
checkLine(originalX, originalY, 1, -1); // Bottom-right
}

protected void checkStraights() {
c = Chessboard.getInstance();
int originalX = x;
int originalY = y;

checkLine(originalX, originalY, 1, 0); // Right
checkLine(originalX, originalY, -1, 0); // Left
checkLine(originalX, originalY, 0, 1); // Up
checkLine(originalX, originalY, 0, -1); // Down
}

private void checkLine(int startX, int startY, int xIncrement, int yIncrement) {
for (int i = 1; startX + i * xIncrement < 8 && startX + i * xIncrement >= 0
&& startY + i * yIncrement < 8 && startY + i * yIncrement >= 0; i++) {
int newX = startX + i * xIncrement;
int newY = startY + i * yIncrement;
if (c.check(newX, newY, this) == 0) break;
addMoveIfSafe(newX, newY);
if (c.check(newX, newY, this) == 2) break;
}
}

// 2cnd Step (It doesn't have to check if its safe,
// if it attacks the King its over before the other player can move)
protected void checkDiagonals2() {
c = Chessboard.getInstance();
int originalX = x;
int originalY = y;

checkLine2(originalX, originalY, 1, 1); // Top-right
checkLine2(originalX, originalY, -1, -1); // Bottom-left
checkLine2(originalX, originalY, -1, 1); // Top-left
checkLine2(originalX, originalY, 1, -1); // Bottom-right
}

protected void checkStraights2() {
c = Chessboard.getInstance();
int originalX = x;
int originalY = y;

checkLine2(originalX, originalY, 1, 0); // Right
checkLine2(originalX, originalY, -1, 0); // Left
checkLine2(originalX, originalY, 0, 1); // Up
checkLine2(originalX, originalY, 0, -1); // Down
}

private void checkLine2(int startX, int startY, int xIncrement, int yIncrement) {
for (int i = 1; startX + i * xIncrement < 8 && startX + i * xIncrement >= 0
&& startY + i * yIncrement < 8 && startY + i * yIncrement >= 0; i++) {
int newX = startX + i * xIncrement;
int newY = startY + i * yIncrement;
if (c.check(newX, newY, this) == 2) {
if (c.getBoard()[newX][newY] instanceof King) {
canAttackKing = true;
}
break;
}
}
}

}

import schach.SchachScreen.Chessboard;
import schach.SchachScreen.SchachScreenPresenter;
import lombok.Getter;
import lombok.Setter;

@Setter
@Getter
public class Pawn extends Piece {
private boolean moved = false;
private int direction;

public Pawn(boolean white) {
super(white);
direction = isWhite() ? -1 : 1; // White moves up (negative), Black moves down (positive)
}

@Override
public String getFenNotation() {
return isWhite() ? "P" : "p"; // Return "P" for white, "p" for black
}

@Override
public void setPossibleMoves() {
c = Chessboard.getInstance();
possibleMoves = new int[8][8]; // Initialize the move matrix

checkMoveForward(); // Regular move forward by one
checkInitialDoubleMove(); // First move double-step
checkEnPassant(); // En Passant
checkDiagonalCaptures(); // Diagonal captures
}

private void checkMoveForward() {
if (c.check(x, y + direction, this) == 1) {
addMoveIfSafe(x, y + direction); // Regular forward move if the square is empty
}
}

private void checkInitialDoubleMove() {
if (!moved && c.check(x, y + 2 * direction, this) == 1
&& c.check(x, y + direction, this) == 1) {
addMoveIfSafe(x, y + 2 * direction); // Double move on first move if both squares are free
}
}

private void checkDiagonalCaptures() {
if (c.getPiece(x + 1, y + direction) != null
&& c.check(x + 1, y + direction, this) == 2) {
addMoveIfSafe(x + 1, y + direction); // Capture to the right
}
if (c.getPiece(x - 1, y + direction) != null
&& c.check(x - 1, y + direction, this) == 2) {
addMoveIfSafe(x - 1, y + direction); // Capture to the left
}
}

private void checkEnPassant() {
// En Passant to the right (if valid)
if (SchachScreenPresenter.convertToChessNotation(x + 1, y + direction)
.equals(c.getPossibleEnPassant()) && c.getPiece(x + 1, y) instanceof Pawn) {
addEnPassantIfSafe(true); // Right side en passant
}
// En Passant to the left (if valid)
else if (SchachScreenPresenter.convertToChessNotation(x - 1, y + direction)
.equals(c.getPossibleEnPassant()) && c.getPiece(x - 1, y) instanceof Pawn) {
addEnPassantIfSafe(false); // Left side en passant
}
}

private void addEnPassantIfSafe(boolean right) {
if (c.simEnPassant(this, right)) {
// En Passant capture move is represented as `5` in the move matrix
possibleMoves[x + (right ? 1 : -1)][y + direction] = 5;
}
}

@Override
public void updateCanAttackKing2() {
canAttackKing = false;
c = Chessboard.getInstance();
int x = getX();
int y = getY();

checkKingAttack(x + 1, y + direction); // Check for possible attack on the right diagonal
checkKingAttack(x - 1, y + direction); // Check for possible attack on the left diagonal
}

private void checkKingAttack(int x, int y) {
if (c.check(x, y, this) == 2 && c.getPiece(x, y) instanceof King) {
canAttackKing = true; // Mark as can attack king if the square is occupied by the opposing king
}
}
}

import schach.figuren.*;
import javafx.scene.shape.MoveTo;
import lombok.Getter;
import lombok.Setter;

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

@Getter
@Setter
public class Chessboard {

private boolean gameRunning = true;

private Piece[][] board = new Piece[8][8];
private List whitePieces = new ArrayList();
private List blackPieces = new ArrayList();

private int moveCounter;
private boolean whiteTurn;
private King whiteKing, blackKing;
private Piece selectedPiece = null;

private static Chessboard instance;

private String possibleEnPassant;

//fifty move rule and threefold repetition rule
private int fiftyMoveCounter; // 1 Move consists of both Players making a move, therefore this variable has to reach 100 for a draw
private List boardStates;

private Chessboard() {
fiftyMoveCounter = 0;
possibleEnPassant = "-";
moveCounter = 0;
whiteTurn = true;

boardStates = new ArrayList();
}

public static Chessboard getInstance() {
if (instance == null) {
instance = new Chessboard();
}
return instance;
}

public static void resetInstance() {
instance = new Chessboard();
}

public void initializeBoard() {
board = new Piece[8][8];
whiteTurn = true;
moveCounter = 0;
selectedPiece = null;

// Place white pieces at the bottom
addPiece(new Rook(true), 0, 7);
addPiece(new Knight(true), 1, 7);
addPiece(new Bishop(true), 2, 7);
addPiece(new Queen(true), 3, 7);
addPiece(new King(true), 4, 7);
addPiece(new Bishop(true), 5, 7);
addPiece(new Knight(true), 6, 7);
addPiece(new Rook(true), 7, 7);
for (int i = 0; i < 8; i++) {
addPiece(new Pawn(true), i, 6);
}

// Place black pieces at the top
addPiece(new Rook(false), 0, 0);
addPiece(new Knight(false), 1, 0);
addPiece(new Bishop(false), 2, 0);
addPiece(new Queen(false), 3, 0);
addPiece(new King(false), 4, 0);
addPiece(new Bishop(false), 5, 0);
addPiece(new Knight(false), 6, 0);
addPiece(new Rook(false), 7, 0);
for (int i = 0; i < 8; i++) {
addPiece(new Pawn(false), i, 1);
}

whiteKing = (King) board[4][7];
blackKing = (King) board[4][0];
updatePossibleMoves();
}

// Generates a valid FEN string for UCI compatibility
public String getFen() {
StringBuilder fen = new StringBuilder();
fen.append(getBoardState());
fen.append(' ').append(isWhiteTurn() ? 'w' : 'b');
fen.append(' ').append(getCastlingRights());
fen.append(' ').append(possibleEnPassant);
fen.append(' ').append(fiftyMoveCounter);
fen.append(' ').append((moveCounter / 2) + 1);
return fen.toString();
}

private String getCastlingRights() {
StringBuilder rights = new StringBuilder();
if (!whiteKing.isMoved()) {
if (!isRookMoved(7, 7)) rights.append('K');
if (!isRookMoved(0, 7)) rights.append('Q');
}
if (!blackKing.isMoved()) {
if (!isRookMoved(7, 0)) rights.append('k');
if (!isRookMoved(0, 0)) rights.append('q');
}
return rights.length() > 0 ? rights.toString() : "-";
}

private boolean isRookMoved(int x, int y) {
Piece rook = board[x][y];
return !(rook instanceof Rook) || ((Rook) rook).isMoved();
}

public void updateGameState(Piece piece, Piece capturedPiece, boolean doubleMove) {
whiteTurn = !whiteTurn;
moveCounter++;
selectedPiece = null;

switch (piece) {
case Pawn pawn -> {
pawn.setMoved(true);
if (doubleMove) {
possibleEnPassant = SchachScreenPresenter.convertToChessNotation(piece.getX(),
piece.getY() + (pawn.isWhite() ? 1 : -1));
}
else {
possibleEnPassant = "-";
}
}

case King king -> {
king.setMoved(true);
possibleEnPassant = "-";
}
case Rook rook -> {
rook.setMoved(true);
possibleEnPassant = "-";
}
default -> { possibleEnPassant = "-";
}
}

updatePossibleMoves();

if (piece instanceof Pawn || capturedPiece != null) {
fiftyMoveCounter = 0;
} else {
fiftyMoveCounter++;
}
boardStates.add(getBoardState());
}

public String getBoardState() {
StringBuilder boardState = new StringBuilder();
for (int y = 0; y < 8; y++) {
int emptyCount = 0;
for (int x = 0; x < 8; x++) {
Piece piece = board[x][y];
if (piece == null) {
emptyCount++;
} else {
if (emptyCount > 0) {
boardState.append(emptyCount);
emptyCount = 0;
}
boardState.append(piece.getFenNotation());
}
}
if (emptyCount > 0) {
boardState.append(emptyCount);
}
if (y < 7) {
boardState.append('/');
}
}
return boardState.toString();
}

private boolean checkThreefoldRepetition() {
int count = 0;
String currentState = getBoardState();
for (String state : boardStates) {
if (state.equals(currentState)) {
count++;
}
}
return count >= 3;
}

public void addPiece(Piece piece, int x, int y) {
board[x][y] = piece;
piece.setPosition(x, y);
if(piece.isWhite()){
whitePieces.add(piece);
}else{
blackPieces.add(piece);
}
}
public void removePiece(Piece piece) {
int x = piece.getX();
int y = piece.getY();
piece.setPosition(-1, -1);
board[x][y] = null;
if(piece.isWhite()){
whitePieces.remove(piece);
}else{
blackPieces.remove(piece);
}
}

//returns 0 if the move is invalid, 1 if the move is valid, 2 if the move is a valid capture
public int check(int x, int y, Piece piece) {
if (x < 0 || x >= 8 || y < 0 || y >= 8) {
return 0; // Out of bounds
}
Piece targetPiece = board[x][y];
if (targetPiece == null) {
return 1; // Empty square
} else if (targetPiece.isWhite() != piece.isWhite()) {
return 2; // Opponent's piece
} else {
return 0; // Own piece
}
}

public boolean isInCheck(King king, int i) {
if (i == 1) {
return canAttack(king.getX(), king.getY(), !king.isWhite());
} else {
return canAttack2(king.getX(), king.getY(), !king.isWhite());
}
}

public boolean canAttack(int targetX, int targetY, boolean isWhite) {
List pieces = isWhite ? whitePieces : blackPieces;
for (Piece piece : pieces) {
int cell = piece.getPossibleMoves()[targetX][targetY];
if (cell == 2) {
System.out.println("Piece: " + piece.getFenNotation() + SchachScreenPresenter.convertToChessNotation(piece.getX(), piece.getY())
+ " can attack: " + SchachScreenPresenter.convertToChessNotation(targetX, targetY));
return true;
}
}
return false;
}

public boolean isSquareSafe(int targetX, int targetY, boolean isWhite){
List pieces = isWhite ? whitePieces : blackPieces;
for (Piece piece : pieces) {
int cell = piece.getPossibleMoves()[targetX][targetY];
if (cell == 2 || (cell == 1) && !(piece instanceof Pawn)) {
System.out.println("Piece: " + piece.getFenNotation() + SchachScreenPresenter.convertToChessNotation(piece.getX(), piece.getY())
+ " can attack: " + SchachScreenPresenter.convertToChessNotation(targetX, targetY));
return false;
}
}
return true;
}

public boolean canAttack2(int x, int y, boolean isWhite) {
List pieces = isWhite ? whitePieces : blackPieces;
for (Piece piece : pieces) {
if (piece.canAttackKing()) {
return true;
}
}
return false;
}

public void movePiece(int x, int y, Piece piece) {
int[] originalPosition = new int[]{piece.getX(), piece.getY()};

Piece capturedPiece = null;

// Clear the target position
if (board[x][y] != null) {
capturedPiece = board[x][y];
removePiece(capturedPiece);
}

// Execute the move
addPiece(piece, x, y);
board[originalPosition[0]][originalPosition[1]] = null;

updateGameState(piece, capturedPiece,
y - originalPosition[1] == 2 || y - originalPosition[1] == -2);
}

public boolean simMovePiece(int x, int y, Piece piece) {
if (moveCounter < 3) return true;
boolean isSafe = true;

// Save original position
int[] originalPosition = new int[]{piece.getX(), piece.getY()};
Piece targetedPiece = board[x][y];

// Simulate move
addPiece(piece, x, y);
board[originalPosition[0]][originalPosition[1]] = null;
if (targetedPiece != null) {
removePiece(targetedPiece);
}

// Update possible King attacks for opponent pieces after the Move of the piece
updatePossibleMoves2(piece);

// Check if the king is in check
if (isInCheck(getKing(piece.isWhite()), 2)) {
isSafe = false;
}

// Revert move
addPiece(piece, originalPosition[0], originalPosition[1]);
if (targetedPiece != null) {
addPiece(targetedPiece, x, y);

} else {
board[x][y] = null;
}

return isSafe;
}

public boolean simEnPassant(Pawn pawn, boolean right) {
int startX = pawn.getX();
int startY = pawn.getY();
int endX = pawn.getX() + (right ? 1 : -1);
int endY = pawn.getY() + (pawn.isWhite() ? -1 : 1);

Pawn capturedPawn = (Pawn) board[endX][endY - (pawn.isWhite() ? -1 : 1)];

boolean isSafe = true;

// Simulate move
addPiece(pawn, endX, endY);
board[startX][startY] = null;
removePiece(capturedPawn);

// Update possible King attacks for opponent pieces after the move of the piece
updatePossibleMoves2(pawn);

// Check if the king is in check
if (isInCheck(getKing(pawn.isWhite()), 2)) {
isSafe = false;
}

// Revert move
addPiece(pawn, startX, startY);
addPiece(capturedPawn, endX,endY - (pawn.isWhite() ? -1 : 1)); // Restore the en passant captured pawn
board[endX][endY] = null;

return isSafe;
}

public String checkForEnd(){
//Check for fifty move rule
if(fiftyMoveCounter >= 100){
return "Fifty move rule";
}
if (checkThreefoldRepetition()) {
return "Threefold repetition rule";
}

//Check for checkmate or stalemate
boolean check = isInCheck(getKing(whiteTurn),1);
boolean possibleMoveExists = false;

for(int i = 0; i < 8; i++){
for(int j = 0; j < 8; j++){
Piece piece = board[j];
if(piece != null && piece.isWhite() == whiteTurn){
for(int k = 0; k < 8; k++){
for(int l = 0; l < 8; l++){
if(piece.getPossibleMoves()[k][l] != 0){
possibleMoveExists = true;
}
}
}
}
}
}
if(!possibleMoveExists){
if(check){
return "Checkmate";
}else{
return "Stalemate";
}
}
return "";
}

public void castle(King king, boolean kingside) {
int y = king.getY();
int x = king.getX();
int rookX = kingside ? 7 : 0;
int newKingX = kingside ? 6 : 2;
int newRookX = kingside ? 5 : 3;

// Move the king and rook to their new positions
addPiece(king, newKingX, y);
addPiece(board[rookX][y], newRookX, y);

// Clear the old positions
board[x][y] = null;
board[rookX][y] = null;

updateGameState(king, null, false);
}

public void enPassant(Pawn pawn, int x, int y) {
int direction = pawn.isWhite() ? -1 : 1;
board[x][y - direction] = null;
movePiece(x, y, pawn);
}

public King getKing(boolean isWhite) {
return isWhite ? whiteKing : blackKing;
}

public void updatePossibleMoves() {
for (int i = 0; i < 8; i++) {
for (int j = 0; j < 8; j++) {
Piece piece = board[j];
if (piece != null) {
piece.setPossibleMoves();
}
}
}

}
public void updatePossibleMoves2(Piece exception) {
for (int i = 0; i < 8; i++) {
for (int j = 0; j < 8; j++) {
Piece piece = board[j];
if (piece != null) {
if (piece.isWhite() != exception.isWhite()) {
piece.updateCanAttackKing2();
}
}
}
}
}

public Piece getPiece(int x, int y) {
if(x > 7 || x < 0 || y > 7 || y < 0) return null;
return board[x][y];
}
public void setPiece(int x, int y, Piece piece) {
board[x][y] = piece;
}

public Piece promotePawn(Pawn pawn, String pieceType, int newX, int newY) {
Piece capturedPiece = board[newX][newY];

Piece newPiece = switch (pieceType) {
case "Queen" -> new Queen(pawn.isWhite());
case "Rook" -> new Rook(pawn.isWhite());
case "Bishop" -> new Bishop(pawn.isWhite());
case "Knight" -> new Knight(pawn.isWhite());
default -> null;
};
if (newPiece != null) {
removePiece(pawn);
addPiece(newPiece, newX, newY);
}
updateGameState(pawn, capturedPiece, false);

return newPiece;
}
}



Подробнее здесь: https://stackoverflow.com/questions/793 ... me-in-java
Реклама
Ответить Пред. темаСлед. тема

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

  • Похожие темы
    Ответы
    Просмотры
    Последнее сообщение

Вернуться в «JAVA»