| /********************************************************************* |
| * Copyright (c) 2011, 2019 SAP SE |
| * |
| * This program and the accompanying materials are made |
| * available under the terms of the Eclipse Public License 2.0 |
| * which is available at https://www.eclipse.org/legal/epl-2.0/ |
| * |
| * Contributors: |
| * SAP SE - initial API, implementation and documentation |
| * |
| * SPDX-License-Identifier: EPL-2.0 |
| **********************************************************************/ |
| package org.eclipse.graphiti.examples.chess; |
| |
| import org.eclipse.graphiti.examples.mm.chess.Board; |
| import org.eclipse.graphiti.examples.mm.chess.Colors; |
| import org.eclipse.graphiti.examples.mm.chess.Files; |
| import org.eclipse.graphiti.examples.mm.chess.Piece; |
| import org.eclipse.graphiti.examples.mm.chess.Ranks; |
| import org.eclipse.graphiti.examples.mm.chess.Square; |
| import org.eclipse.graphiti.examples.mm.chess.Types; |
| |
| public final class MoveUtil { |
| |
| public static final String PROPERTY_MOVE = "move"; //$NON-NLS-1$ |
| |
| private MoveUtil() { |
| super(); |
| } |
| |
| public static boolean isMoveAllowed(Piece piece, Square sourceSquare, Square targetSquare) { |
| // Moving onto a square occupied by another own piece is not allowed |
| if (targetSquare.getPiece() != null && targetSquare.getPiece().getOwner().equals(piece.getOwner())) { |
| return false; |
| } |
| |
| // Determine number of steps taken in file and rank direction |
| int fileSteps = targetSquare.getFile().getValue() - sourceSquare.getFile().getValue(); |
| int rankSteps = targetSquare.getRank().getValue() - sourceSquare.getRank().getValue(); |
| |
| // Check type specific moving rules |
| if (Types.PAWN.equals(piece.getType())) { |
| // Same file |
| if (fileSteps == 0) { |
| // White pawns move upwards to higher ranks |
| if (Colors.LIGHT.equals(piece.getOwner())) { |
| if (rankSteps == 1 || (rankSteps == 2 && Ranks.TWO.equals(sourceSquare.getRank()) && sourceSquare |
| .getBoard().getSquare(Ranks.THREE, sourceSquare.getFile()).getPiece() == null)) { |
| // Allow to move 1 to front or 2 to front in case of |
| // start position |
| return targetSquare.getPiece() == null; |
| } |
| } |
| // Black pawns move downwards to lower ranks |
| else { |
| if (rankSteps == -1 |
| || (rankSteps == -2 && Ranks.SEVEN.equals(sourceSquare.getRank()) && sourceSquare.getBoard() |
| .getSquare(Ranks.SIX, sourceSquare.getFile()).getPiece() == null)) { |
| // Allow to move 1 to front or 2 to front in case of |
| // start position |
| return targetSquare.getPiece() == null; |
| } |
| } |
| } |
| // Neighbour file |
| else if (fileSteps == 1 || fileSteps == -1) { |
| // White pawns move upwards to higher ranks |
| if (Colors.LIGHT.equals(piece.getOwner())) { |
| // Allow to move 1 to front |
| if (rankSteps == 1) { |
| // Allow taking diagonally |
| return targetSquare.getPiece() != null |
| && targetSquare.getPiece().getOwner() != piece.getOwner(); |
| } |
| } |
| // Black pawns move downwards to lower ranks |
| else { |
| // Allow to move 1 to front |
| if (rankSteps == -1) { |
| // Allow taking diagonally |
| return targetSquare.getPiece() != null |
| && targetSquare.getPiece().getOwner() != piece.getOwner(); |
| } |
| } |
| } |
| return false; |
| } else if (Types.KING.equals(piece.getType())) { |
| // Kings are allowed to move either horizontally, vertically or |
| // diagonally but just one step |
| if (rankSteps >= -1 && rankSteps <= 1 && fileSteps >= -1 && fileSteps <= 1) { |
| // Allow moving one to every side and diagonally and taking |
| // other owner's pieces |
| return targetSquare.getPiece() == null || targetSquare.getPiece().getOwner() != piece.getOwner(); |
| } |
| return false; |
| } else if (Types.ROOK.equals(piece.getType())) { |
| // Rooks are allowed to move either horizontally or vertically |
| return allowMovingToSides(sourceSquare, targetSquare, fileSteps, rankSteps); |
| } else if (Types.BISHOP.equals(piece.getType())) { |
| // Bishops are allowed to move diagonally |
| return allowDiagonalMoving(sourceSquare, targetSquare, fileSteps, rankSteps); |
| } else if (Types.QUEEN.equals(piece.getType())) { |
| // Queens are allowed to move either horizontally, vertically or |
| // diagonally |
| return allowMovingToSides(sourceSquare, targetSquare, fileSteps, rankSteps) |
| || allowDiagonalMoving(sourceSquare, targetSquare, fileSteps, rankSteps); |
| } else if (Types.KNIGHT.equals(piece.getType())) { |
| // For one direction the gap needs to be 1, for the other it |
| // needs to be 2. Jumping over other pieces is allowed for |
| // knights |
| if ((Math.abs(rankSteps) == 2 && Math.abs(fileSteps) == 1) |
| || (Math.abs(rankSteps) == 1 && Math.abs(fileSteps) == 2)) { |
| return true; |
| } |
| return false; |
| } |
| |
| // Should never get here |
| throw new IllegalStateException("Invalid Piece type: " + piece.getType()); //$NON-NLS-1$ |
| } |
| |
| private static boolean allowMovingToSides(Square sourceSquare, Square targetSquare, int fileGap, int rankGap) { |
| Board board = sourceSquare.getBoard(); |
| |
| // Same rank --> horizontal move |
| if (rankGap == 0) { |
| // Check if any square in between is occupied, if yes the move is |
| // not allowed |
| int from = Math.min(sourceSquare.getFile().getValue(), targetSquare.getFile().getValue()); |
| int to = Math.max(sourceSquare.getFile().getValue(), targetSquare.getFile().getValue()); |
| for (int i = from + 1; i < to; i++) { |
| if (board.getSquare(sourceSquare.getRank(), Files.get(i)).getPiece() != null) { |
| // Move over occupied square |
| return false; |
| } |
| } |
| // No occupied square in between --> allow |
| return true; |
| } |
| |
| // Same file --> vertical move |
| if (fileGap == 0) { |
| // Check if any square in between is occupied, if yes the move is |
| // not allowed |
| int from = Math.min(sourceSquare.getRank().getValue(), targetSquare.getRank().getValue()); |
| int to = Math.max(sourceSquare.getRank().getValue(), targetSquare.getRank().getValue()); |
| for (int i = from + 1; i < to; i++) { |
| if (board.getSquare(Ranks.get(i), sourceSquare.getFile()).getPiece() != null) { |
| // Move over occupied square |
| return false; |
| } |
| } |
| // No occupied square in between --> allow |
| return true; |
| } |
| return false; |
| } |
| |
| private static boolean allowDiagonalMoving(Square sourceSquare, Square targetSquare, int fileGap, int rankGap) { |
| Board board = sourceSquare.getBoard(); |
| if (Math.abs(rankGap) == Math.abs(fileGap)) { |
| // Allow moving diagonally |
| int fromRank = Math.min(sourceSquare.getRank().getValue(), targetSquare.getRank().getValue()); |
| int toRank = Math.max(sourceSquare.getRank().getValue(), targetSquare.getRank().getValue()); |
| |
| // Determine if the rank and file directions are the same (upward or |
| // downwards); in case not we need to reverse file direction |
| // counting |
| int fileDirection = 1; |
| if (sourceSquare.getFile().getValue() > targetSquare.getFile().getValue()) { |
| fileDirection = -1; |
| } |
| |
| // Check if any square in between is occupied, if yes the move is |
| // not allowed |
| for (int i = 1; i < toRank - fromRank; i++) { |
| if (board |
| .getSquare(Ranks.get(fromRank + i), |
| Files.get(sourceSquare.getFile().getValue() + (i * fileDirection))) |
| .getPiece() != null) { |
| // Move over occupied square |
| return false; |
| } |
| } |
| // Move is ok |
| return true; |
| } |
| // Move is not diagonal, not ok |
| return false; |
| } |
| } |