content: package com.chess.engine.player;
  
  import com.chess.engine.Alliance;
  import com.chess.engine.board.Board;
  import com.chess.engine.board.BoardUtils;
  import com.chess.engine.board.Move;
  import com.chess.engine.board.Move.MoveStatus;
  import com.chess.engine.board.MoveTransition;
  import com.chess.engine.pieces.King;
  
  import java.util.Collection;
  import java.util.Collections;
  
  
  public abstract class Player {
  
      protected final Board board;
      protected final King playerKing;
      protected final Collection<Move> legalMoves;
      protected final boolean isInCheck;
  
      Player(final Board board,
             final King playerKing,
             final Collection<Move> playerLegals,
             final Collection<Move> opponentLegals) {
          this.board = board;
          this.playerKing = playerKing;
          this.isInCheck = !BoardUtils.calculateAttacksOnTile(this.playerKing.getPiecePosition(), opponentLegals).isEmpty();
          playerLegals.addAll(calculateKingCastles(playerLegals, opponentLegals));
          this.legalMoves = Collections.unmodifiableCollection(playerLegals);
      }
  
      public Board getBoard() {
          return this.board;
      }
  
      public boolean isInCheck() {
          return this.isInCheck;
      }
  
      public boolean isInCheckMate() {
         return this.isInCheck && this.isTrapped();
      }
  
      public boolean isInStaleMate() {
          return !this.isInCheck && this.isTrapped();
      }
  
      public boolean isCastled() {
          return this.playerKing.isCastled();
      }
  
      public boolean isKingSideCastleCapable() {
          return this.playerKing.isKingSideCastleCapable();
      }
  
      public boolean isQueenSideCastleCapable() {
          return this.playerKing.isQueenSideCastleCapable();
      }
  
      public King getPlayerKing() {
          return this.playerKing;
      }
  
      private boolean isTrapped() {
          for (final Move move : this.legalMoves) {
              if (makeMove(move).getMoveStatus().isDone()) {
                  return false;
              }
          }
          return true;
      }
      public Collection<Move> getLegalMoves() {
          return this.legalMoves;
      }
  
      public MoveTransition makeMove(final Move move) {
          if (!this.legalMoves.contains(move)) {
              return new MoveTransition(this.board, this.board, move, MoveStatus.ILLEGAL_MOVE);
          } else {
              final Board transitionedBoard = move.execute();
              return transitionedBoard.currentPlayer().getOpponent().isInCheck() ?
                  new MoveTransition(this.board, this.board, move, MoveStatus.LEAVES_PLAYER_IN_CHECK) :
                  new MoveTransition(this.board, transitionedBoard, move, MoveStatus.DONE);
          }
      }
  
      public MoveTransition unMakeMove(final Move move) {
          return new MoveTransition(this.board, move.undo(), move, MoveStatus.DONE);
      }
  
      public abstract int[] getActivePieces();
      public abstract Alliance getAlliance();
      public abstract Player getOpponent();
      protected abstract Collection<Move> calculateKingCastles(Collection<Move> playerLegals,
                                                               Collection<Move> opponentLegals);
      public boolean hasCastlingRights() {
          return !this.isInCheck && !this.playerKing.isCastled() &&
                  (this.playerKing.isKingSideCastleCapable() || this.playerKing.isQueenSideCastleCapable());
      }
  
  }
  