From f789683100d1d40b5fc3c862982b8cfa476544a1 Mon Sep 17 00:00:00 2001 From: MasterPyo <olivier.pillods@gmail.com> Date: Sat, 13 May 2023 16:36:06 +0200 Subject: [PATCH] check and prevent self check --- .../src/main/java/controller/Game.java | 185 ++++++++++++++++-- .../src/main/java/controller/Log.java | 10 +- .../src/main/java/controller/Main.java | 5 +- .../MavenChess/src/main/java/model/Board.java | 10 + .../src/main/java/model/Kamikaze.java | 23 +-- .../MavenChess/src/main/java/model/Nwap.java | 80 ++++---- .../src/main/java/view/BoardView.java | 31 +-- 7 files changed, 236 insertions(+), 108 deletions(-) diff --git a/MavenChess/MavenChess/src/main/java/controller/Game.java b/MavenChess/MavenChess/src/main/java/controller/Game.java index 7d3ef8f..93f916b 100644 --- a/MavenChess/MavenChess/src/main/java/controller/Game.java +++ b/MavenChess/MavenChess/src/main/java/controller/Game.java @@ -7,7 +7,7 @@ import java.util.ArrayList; public class Game { private int status; - public static final int WHITE_TURN = 1, BLACK_TURN = 2, GAME_OVER = 3; + public static final int WHITE_TURN = 1, BLACK_TURN = 2, WHITE_WON = 3, BLACK_WON = 4; public Game() { status = WHITE_TURN; @@ -37,9 +37,9 @@ public class Game { public void nextTurn() { if(isWhiteTurn()) - setStatus(Game.BLACK_TURN); - else if(isBlackTurn()) - setStatus(Game.WHITE_TURN); + setStatus(BLACK_TURN); + else + setStatus(WHITE_TURN); } public void clickPiece(PieceView clickedPiece, Board board, BoardView boardView, CustomMaterial material, Custom3dModel model, Log log, HUD hud) { @@ -58,7 +58,7 @@ public class Game { // clicking a piece will ask her available moves Position position = clickedPiece.getPosition(); board.setSelected(position); - boardView.resetColor(material); + boardView.resetTileColorAll(material); boardView.setColor(material, position, CustomMaterial.SELECTED_TILE); ArrayList<Position> moves = board.getPiece(position).getAvailableMoves(board); @@ -73,23 +73,15 @@ public class Game { // shows all available moves on the tiles, with colors, each tile-color having a meaning for (Position move : moves) { - if (board.isFree(move)) { boardView.setColor(material, move, CustomMaterial.MOVABLE_TILE); // test for "en passant" - if (board.isPawn(position) || board.isNwap(position)) { + if (board.isPawn(position)) { Position enemy = new Position(move.getX(), position.getY()); boolean isEnPassant = false; - if (board.isEnemy(enemy, position)) { - if (board.isPawn(enemy)) { - if (((Pawn) board.getPiece(enemy)).isEnPassant()) { - isEnPassant = true; - } - } - if (board.isNwap(enemy)) { - if (((Nwap) board.getPiece(enemy)).isEnPassant()) { - isEnPassant = true; - } + if (board.isEnemy(enemy, position) && board.isPawn(enemy)) { + if (((Pawn) board.getPiece(enemy)).isEnPassant()) { + isEnPassant = true; } } if (isEnPassant) { @@ -106,10 +98,22 @@ public class Game { boardView.getPiece(move.getID()).setTargeted(material, CustomMaterial.SPECIAL_TILE); } // PROMOTION (attacking or not) - if ((board.isPawn(position) || board.isNwap(position)) && (move.getY() == 8 || move.getY() == 1)) { + if ((board.isPawn(position)) && (move.getY() == 8 || move.getY() == 1)) { boardView.setColor(material, move, CustomMaterial.SPECIAL_TILE); } } + + // Prevent available moves that let the king in check state + ArrayList<Position> toPrevent = new ArrayList<>(); + for (Position move : moves) { + boolean selfCheck = applyMoveAndCheckVerification(board, boardView, getStatus(), move); + if(selfCheck) { + toPrevent.add(move); // Prevents the move + } + } + for (Position elem : toPrevent) { + boardView.resetTileColor(material, elem); + } } } @@ -136,7 +140,7 @@ public class Game { } // --- ALL SPECIAL MOVES --- if(state == TileView.SPECIAL) { - if(board.isPawn(selected) || board.isNwap(selected)) { + if(board.isPawn(selected)) { // --- PROMOTION --- if(arrival.getY() == 8 || arrival.getY() == 1) { // --- ATTACK (while doing promotion) --- @@ -244,13 +248,154 @@ public class Game { } } + // --- Resets board coloring, doing any action or not --- - boardView.resetColor(material); + boardView.resetTileColorAll(material); + // updates game status if(moved) { nextTurn(); // change player turn log.save(board, boardView); // saves current board hud.rollbackShow(); // show rollback button (if not showed already) + + // signals if there is a check ! + boolean echec = checkVerification(board, getStatus()); // test the opponent check (turn just changed) + if(echec) { + if (isWhiteTurn()) { + System.out.println("echec white"); + } + if (isBlackTurn()) { + System.out.println("echec black"); + } + } + } + } + + public boolean checkVerification(Board board, int color){ + boolean isCheck = false; + for (int i = 0 ; i < 64 ; i++){ + Piece p = board.getPiece(i); + if(p != null && p.getColor() != color) { + // get all moves + ArrayList<Position> moves = p.getAvailableMoves(board); + // if kamikaze adds explosion moves + if(p.getClass() == Kamikaze.class) { + ArrayList<Position> explosions = ((Kamikaze) p).getExplosion(); + moves.addAll(explosions); + } + // if it kills the king of specified color, check ! + for (Position move : moves) { + if (board.isKing(move) && board.getPiece(move).getColor() == color) { + isCheck = true; + } + } + } } + return isCheck; + } + + public boolean applyMoveAndCheckVerification(Board originalBoard, BoardView boardView, int color, Position emulatedMove) { + + Board board = originalBoard.newInstanceCopy(); // create a copy, to do tests on it + board.setSelected(originalBoard.getSelected()); + TileView clickedTile = boardView.getTile(emulatedMove.getID()); + + // --- EMULATES THE MOVEMENT ----------------------------------------------- + + // --- Analyses the clicked tile type, and executes related actions --- + int state = clickedTile.getState(); + Position selected = board.getSelected(); + Position arrival = clickedTile.getPosition(); + if(state != TileView.NORMAL && state != TileView.SELECTED) { + // --- Resets enPassant --- + for(int j = 1 ; j <= 8 ; j++) { + for(int i = 1 ; i <= 8 ; i++) { + Position p = new Position(i, j); + if (board.isPawn(p)) { + ((Pawn) board.getPiece(p)).setEnPassant(false); + } + if (board.isNwap(p)) { + ((Nwap) board.getPiece(p)).setEnPassant(false); + } + } + } + // --- ALL SPECIAL MOVES --- + if(state == TileView.SPECIAL) { + if(board.isPawn(selected)) { + // --- PROMOTION --- + if(arrival.getY() == 8 || arrival.getY() == 1) { + // Promotion to Queen (by default, Queen for now) + board.mutationOfSelectedPiece(Board.QUEEN); + board.movePiece(selected, arrival); + } + // --- PRISE EN PASSANT --- + else { + Position enemy = new Position(arrival.getX(), selected.getY()); + board.killPiece(enemy.getID()); // because we don't move "on it", we need to kill it manually (model) + Position enPassantArrival = new Position(arrival.getX(), selected.getY()+1); + if(board.getSelectedPiece().getColor() == Piece.BLACK) { + enPassantArrival.setY(selected.getY()-1); + } + board.movePiece(selected, enPassantArrival); + } + } + // --- CASTLING (from king) --- + if(board.isKing(selected)) { + int x = Board.D; // king x arrival, for west-rook + if(arrival.getX() == Board.H) { + x = Board.F; // king x arrival, for east-rook + } + Position kingArrival = new Position(x, selected.getY()); + board.movePiece(selected, kingArrival); // move king + board.movePiece(arrival, selected); // move rook + } + // --- CASTLING (from rook) --- + else if(board.isRook(selected)) { + int x = Board.D; // king x arrival, for west-rook + if (selected.getX() == Board.H) { + x = Board.F; // king x arrival, for east-rook + } + Position kingArrival = new Position(x, arrival.getY()); + board.movePiece(arrival, kingArrival); // move king + board.movePiece(selected, arrival); // move rook + } + } + // --- EXPLOSION MOVES --- + else if (state == TileView.EXPLOSION) { + for(int n = 0 ; n < 64 ; n++) { + if(boardView.getTile(n).getState() == TileView.EXPLOSION) { + if(boardView.getPiece(n) != null) { + board.killPiece(n); + } + } + } + } + // --- STANDARD MOVES --- + else { + // --- ATTACK --- + if(state == TileView.ATTACK) { + // --- MAGICIAN CHANGE --- + if(board.isMagician(selected)) { + Magician magician = (Magician) board.getPiece(selected); + Piece enemy = board.getPiece(arrival); + magician.steal(enemy); // muahaha + } + } + // --- EN PASSANT activation --- + if(Math.abs(selected.getY() - arrival.getY()) == 2) { + if(board.isPawn(selected)) { + ((Pawn) board.getPiece(selected)).setEnPassant(true); + } + if(board.isNwap(selected)) { + ((Nwap) board.getPiece(selected)).setEnPassant(true); + } + } + // --- MOVE --- + board.movePiece(selected, arrival); // move piece + } + } + // --- END OF EMULATION ------------------------------------------------- + + return checkVerification(board, color); // we test the board after emulating a move } } diff --git a/MavenChess/MavenChess/src/main/java/controller/Log.java b/MavenChess/MavenChess/src/main/java/controller/Log.java index cf05e2a..c4c240b 100644 --- a/MavenChess/MavenChess/src/main/java/controller/Log.java +++ b/MavenChess/MavenChess/src/main/java/controller/Log.java @@ -19,14 +19,8 @@ public class Log { } public void save(Board board, BoardView boardView) { - Board copy = new Board(); - for(int n = 0 ; n < 64 ; n++) { - // we make a NEW COPY, not just getting pointer ! - Piece piece = board.getPiece(n); - if(piece != null) { - copy.setPiece(piece.newInstanceCopy()); - } - } + // we make a NEW COPY, not just getting pointer ! + Board copy = board.newInstanceCopy(); int id = logPieces.size(); logPieces.add(id, copy.getAllPieces()); // for graveyards, we don't need a copy, because pieces aren't moving at all once inside, so there will be no issues diff --git a/MavenChess/MavenChess/src/main/java/controller/Main.java b/MavenChess/MavenChess/src/main/java/controller/Main.java index 692df0b..5b5e304 100644 --- a/MavenChess/MavenChess/src/main/java/controller/Main.java +++ b/MavenChess/MavenChess/src/main/java/controller/Main.java @@ -3,8 +3,6 @@ package controller; import javafx.application.Application; import javafx.beans.value.ChangeListener; import javafx.scene.*; -import javafx.scene.input.KeyCode; -import javafx.scene.input.KeyEvent; import javafx.scene.input.MouseEvent; import javafx.scene.input.ScrollEvent; import javafx.scene.layout.AnchorPane; @@ -12,7 +10,6 @@ import javafx.stage.Stage; import model.*; import view.*; -import java.util.ArrayList; public class Main extends Application { @@ -136,7 +133,7 @@ public class Main extends Application { // event - rollback hud.getRollback().addEventHandler(MouseEvent.MOUSE_CLICKED, event -> { - boardView.resetColor(material); + boardView.resetTileColorAll(material); log.rollback(board, boardView, material, model, group3d, game, hud); }); diff --git a/MavenChess/MavenChess/src/main/java/model/Board.java b/MavenChess/MavenChess/src/main/java/model/Board.java index f8a24ae..00d23d1 100644 --- a/MavenChess/MavenChess/src/main/java/model/Board.java +++ b/MavenChess/MavenChess/src/main/java/model/Board.java @@ -209,4 +209,14 @@ public class Board { pieces[i] = null; } } + public Board newInstanceCopy() { + Board copy = new Board(); + for(int n = 0 ; n < 64 ; n++) { + Piece piece = getPiece(n); + if(piece != null) { + copy.setPiece(piece.newInstanceCopy()); + } + } + return copy; + } } diff --git a/MavenChess/MavenChess/src/main/java/model/Kamikaze.java b/MavenChess/MavenChess/src/main/java/model/Kamikaze.java index 2dfd29b..a3f0c96 100644 --- a/MavenChess/MavenChess/src/main/java/model/Kamikaze.java +++ b/MavenChess/MavenChess/src/main/java/model/Kamikaze.java @@ -2,31 +2,12 @@ package model; import java.util.ArrayList; -public class Kamikaze extends Pawn { // aka Trojan knight :P +public class Kamikaze extends Knight { // aka Trojan knight :P public Kamikaze(Position p, int color) { super(p, color); } - @Override - public ArrayList<Position> getAvailableMoves(Board b) { - - ArrayList<Position> moves = new ArrayList<>(); - Position arrival; - - // list of the 8 kamikaze-knight specific movements - int[] all_x = {1, 2, 2, 1, -1, -2, -2, -1}; - int[] all_y = {2, 1, -1, -2, -2, -1, 1, 2}; - - for(int n = 0 ; n < all_x.length ; n++) { // for each direction - int x = all_x[n]; - int y = all_y[n]; - arrival = new Position(p.getX() + x, p.getY() + y); - if (b.isEnemy(arrival, p) || b.isFree(arrival)) { - moves.add(arrival); - } - } - return moves; - } + // getAvailableMoves is in Knight already public ArrayList<Position> getExplosion() { diff --git a/MavenChess/MavenChess/src/main/java/model/Nwap.java b/MavenChess/MavenChess/src/main/java/model/Nwap.java index f7732c3..f952b40 100644 --- a/MavenChess/MavenChess/src/main/java/model/Nwap.java +++ b/MavenChess/MavenChess/src/main/java/model/Nwap.java @@ -13,71 +13,69 @@ public class Nwap extends Pawn { @Override public ArrayList<Position> getAvailableMoves(Board b) { - - ArrayList<Position> moves = new ArrayList<Position>(); + ArrayList<Position> moves = new ArrayList<>(); Position arrival; Position arrival2; if(color == Piece.WHITE) { // black and white have an opposite direction behavior - if(!hasBeenMoved){ - - // up left 2 - - - // up right 2 - - } - // up left 1 + // up left arrival = new Position(p.getX()-1, p.getY() +1); if(arrival.isCorrect() && b.isFree(arrival)) { + moves.add(arrival); + if(!hasBeenMoved) { + arrival2 = new Position(p.getX() - 2, p.getY() + 2); + if (arrival2.isCorrect() && b.isFree(arrival2)) { + moves.add(arrival2); + } + } + } - arrival2 = new Position(p.getX()-2, p.getY() +2); - if(arrival2.isCorrect() && b.isFree(arrival2)) { moves.add(arrival2); } - moves.add(arrival); } - - - // up right 1 + // up right arrival = new Position(p.getX()+1, p.getY() +1); if(arrival.isCorrect() && b.isFree(arrival)) { - arrival2 = new Position(p.getX()+2, p.getY() +2); - if(arrival2.isCorrect() && b.isFree(arrival2)) { moves.add(arrival2); } - moves.add(arrival); } + moves.add(arrival); + if (!hasBeenMoved) { + arrival2 = new Position(p.getX() + 2, p.getY() + 2); + if (arrival2.isCorrect() && b.isFree(arrival2)) { + moves.add(arrival2); + } + } + } + // up attack arrival = new Position(p.getX(),p.getY()+1); if(b.isEnemy(arrival,p)) {moves.add(arrival);} - } else { - - if(!hasBeenMoved){ - - - - - } - // up left 1 + // down left arrival = new Position(p.getX()-1, p.getY() -1); if(arrival.isCorrect() && b.isFree(arrival)) { - // up left 2 - arrival2 = new Position(p.getX()-2, p.getY() -2); - if(arrival2.isCorrect() && b.isFree(arrival2)) { moves.add(arrival2); } - moves.add(arrival); } - + moves.add(arrival); + if (!hasBeenMoved) { + arrival2 = new Position(p.getX() - 2, p.getY() - 2); + if (arrival2.isCorrect() && b.isFree(arrival2)) { + moves.add(arrival2); + } + } + } - // up left 1 + // down right arrival = new Position(p.getX()+1, p.getY() -1); if(arrival.isCorrect() && b.isFree(arrival)) { + moves.add(arrival); + if (!hasBeenMoved) { + arrival2 = new Position(p.getX() + 2, p.getY() - 2); + if (arrival2.isCorrect() && b.isFree(arrival2)) { + moves.add(arrival2); + } + } + } - // up left 2 - arrival2 = new Position(p.getX()+2, p.getY() -2); - if(arrival2.isCorrect() && b.isFree(arrival2)) { moves.add(arrival2); }moves.add(arrival); } - - + // down attack arrival = new Position(p.getX(),p.getY()-1); if(b.isEnemy(arrival,p)) {moves.add(arrival);} - } return moves; } diff --git a/MavenChess/MavenChess/src/main/java/view/BoardView.java b/MavenChess/MavenChess/src/main/java/view/BoardView.java index fcf0e98..92feb3d 100644 --- a/MavenChess/MavenChess/src/main/java/view/BoardView.java +++ b/MavenChess/MavenChess/src/main/java/view/BoardView.java @@ -6,8 +6,6 @@ import javafx.scene.shape.*; import model.*; import javafx.util.Duration; -import java.util.ArrayList; - public class BoardView { public static final int BOARD_SIZE = 16, CENTERED_ORIGIN = -BOARD_SIZE*7/2, BOARD_HEIGHT = -5, GRAVEYARD_HEIGHT = -1; @@ -46,7 +44,7 @@ public class BoardView { blackGraveyard = new PieceView[16]; // 16 is maximum kills whiteGraveyard = new PieceView[16]; - resetColor(material); // init/reset the board squares with black and white + resetTileColorAll(material); // init/reset the board squares with black and white // creates the board visual border border = new Box[4]; @@ -179,23 +177,28 @@ public class BoardView { piece.getObj().setTranslateY(GRAVEYARD_HEIGHT); // place at right height (Y axis) on table } - public void resetColor(CustomMaterial material) { + public void resetTileColorAll(CustomMaterial material) { for(int n = 0, j = 1 ; j <= 8 ; j++) { for (int i = 1; i <= 8; i++, n++) { - // resets board with black and white - bottom left (first case) is black, then alternates - if((i + j) % 2 == 0) { - getTileObj(n).setMaterial(material.get(CustomMaterial.BLACK_TILE)); // (visually) - } else { - getTileObj(n).setMaterial(material.get(CustomMaterial.WHITE_TILE)); // (visually) - } - getTile(n).setState(TileView.NORMAL); // (on 'state' attribute) - if(getPiece(n) != null) { - getPiece(n).resetTargeted(material); // reset the 3d pieces color too (visual) - } + resetTileColor(material, new Position(i, j)); } } } + public void resetTileColor(CustomMaterial material, Position p) { + int i = p.getX(), j = p.getY(), n = p.getID(); + // resets board with black and white - bottom left (first case) is black, then alternates + if((i + j) % 2 == 0) { + getTileObj(n).setMaterial(material.get(CustomMaterial.BLACK_TILE)); // (visually) + } else { + getTileObj(n).setMaterial(material.get(CustomMaterial.WHITE_TILE)); // (visually) + } + getTile(n).setState(TileView.NORMAL); // (on 'state' attribute) + if(getPiece(n) != null) { + getPiece(n).resetTargeted(material); // reset the 3d pieces color too (visual) + } + } + public void setColor(CustomMaterial material, Position position, int type) { int id = position.getID(); // set the new color-type (visually) -- GitLab