Java_Chess

.idea
    .name 5 B
    artifacts
       Chess_jar.xml 371 B
    compiler.xml 734 B
    copyright
    description.html 97 B
    encodings.xml 171 B
    libraries
       jansi_1_11.xml 214 B
    misc.xml 5 KB
    modules.xml 261 B
    project-template.xml 91 B
    scopes
       scope_settings.xml 143 B
    uiDesigner.xml 8 KB
    vcs.xml 176 B
    workspace.xml 61 KB
Chess.iml 1 KB
Doxyfile 101 KB
GUI_Manual_Testplan.pdf 437 KB
Graphics
    blackBerolinaPawn.png 1 KB
    blackBishop.png 5 KB
    blackKing.png 8 KB
    blackKnight.png 6 KB
    blackPawn.png 2 KB
    blackQueen.png 8 KB
    blackRook.png 3 KB
    blackWazir.png 1 KB
    whiteBerolinaPawn.png 2 KB
    whiteBishop.png 7 KB
    whiteKing.png 8 KB
    whiteKnight.png 7 KB
    whitePawn.png 4 KB
    whiteQueen.png 10 KB
    whiteRook.png 4 KB
    whiteWazir.png 2 KB
README 342 B
jansi-1.11.jar 111 KB
src
    CHANGES 1001 B
    GUI
       Controller.java 15 KB
       Main.java 360 B
       View.java 14 KB
       textPanel.java 776 B
    Game
       Board.java 5 KB
       CLI.java 5 KB
       Command.java 1022 B
       GameManager.java 11 KB
       GameType.java 74 B
       MoveHandler.java 1 KB
       Player.java 133 B
    META-INF
       MANIFEST.MF 53 B
    Main.java 154 B
    Pieces
       BerolinaPawn.java 1 KB
       Bishop.java 480 B
       BoardSquare.java 4 KB
       King.java 470 B
       Knight.java 846 B
       MoveType.java 530 B
       Pawn.java 1 KB
       Queen.java 474 B
       Rook.java 471 B
       Wazir.java 627 B
    TODO 176 B
    Tests
       BoardTest.java 2 KB
       GameManagerTest.java 21 KB
Controller.java
package GUI;

import Game.*;
import Pieces.BoardSquare;

import java.awt.event.*;
import java.awt.*;
import java.util.Scanner;
import javax.swing.*;

/**
 * Controller for MVC
 */
public class Controller implements MouseListener, MouseMotionListener, ActionListener  {

    /**
     * Reference for the view.
     */
    View view;

    /**
     * The game instance being controlled.
     */
    GameManager game;

    /**
     * Score of white.
     */
    int whiteScore = 0;

    /**
     * Score of black.
     */
    int blackScore = 0;

    /**
     * Current piece being held by the mouse.
     */
    JLabel chessPiece;
    int xAdjustment;
    int yAdjustment;

    /**
     * X value of the piece being held, used to show possible moves.
     */
    int currX;

    /**
     * Y value of the piece being held, used to show possible moves.
     */
    int currY;

    /**
     * Flag to show possible moves when updating board.
     */
    boolean showPossibleMoves;

    /**
     * Controller constructor.
     */
    Controller(){
        newWindow(GameType.STANDARD);
    }

    /**
     * Event handler for button presses.
     * @param e the ActionEvent captured.
     */
    @Override
    public void actionPerformed(ActionEvent e) {

        if (e.getActionCommand().equals("About")) {
            JOptionPane.showMessageDialog(view.getWindow(),
                    "Chess by Nicholas Lochner\nVersion 1.2 for CS242\n",
                    "About", JOptionPane.INFORMATION_MESSAGE);
        }


        if (e.getActionCommand().equals("New Window")) {
            int result = JOptionPane.showConfirmDialog(view.getWindow(),
                    "Are you sure you want to start a new game?\nThis will reset all statistics.",
                    "New Window", JOptionPane.YES_NO_OPTION);
            if (result == JOptionPane.YES_OPTION) {
                view.quit();
                newWindow(GameType.STANDARD);
            }
        }

        if (e.getActionCommand().equals("New Window (Custom)")) {
            int result = JOptionPane.showConfirmDialog(view.getWindow(),
                    "Are you sure you want to start a new game?\nThis will reset all statistics.",
                    "New Window", JOptionPane.YES_NO_OPTION);
            if (result == JOptionPane.YES_OPTION) {
                view.quit();
                newWindow(GameType.CUSTOM);
            }
        }


        if (e.getActionCommand().equals("Exit")) {
            int result = JOptionPane.showConfirmDialog(view.getWindow(),
                    "Are you sure you want to exit?",
                    "Exit", JOptionPane.YES_NO_OPTION);
            if (result == JOptionPane.YES_OPTION)
                view.quit();
        }

        if (e.getActionCommand().equals("Propose Takeback")) {
            int result = JOptionPane.showConfirmDialog(view.getWindow(),
                    "An undo of the last move was proposed. Do both players agree?",
                    "Propose Takeback", JOptionPane.YES_NO_OPTION);
            if (result == JOptionPane.YES_OPTION)
                takeback();

        }

        if (e.getActionCommand().equals("Resign")) {

            int result = JOptionPane.showConfirmDialog(view.getWindow(),
                    "Are you sure you want to resign?",
                    "Resign", JOptionPane.YES_NO_OPTION);
            if (result == JOptionPane.YES_OPTION) {
                resign();
            }

        }

        if (e.getActionCommand().equals("Offer Draw")) {
            int result = JOptionPane.showConfirmDialog(view.getWindow(),
                    "A draw was proposed. Do both players agree?",
                    "Offer Draw", JOptionPane.YES_NO_OPTION);
            if (result == JOptionPane.YES_OPTION){
                gameOver(Player.NONE);
            }
        }

    }

    /**
     * Helper function to process resigning.
     */
    private void resign() {
        Player current = game.currentTurn();
        view.setHistory("");
        if (current == Player.WHITE) {
            gameOver(Player.BLACK);
        } else {
            gameOver(Player.WHITE);
        }
    }

    /**
     * Helper function to process a confirmed takeback/undo.
     */
    public void takeback() {
        game.undo();//@todo refactor coordinates.

        String history = view.getHistory();
        Scanner histScanner = new Scanner(history);

        String line = null;
        while (histScanner.hasNextLine()) {
            line = histScanner.nextLine();
            System.out.println(line);

        }

        history = history.replace(line + "\n", "");

        view.setHistory(history);

        updateBoard();
    }

    /**
     * Launches a new window, resetting all statistics.
     *
     * @param type type of game.
     */
    void newWindow(GameType type){

        game = new GameManager(type);
        view = new View(1300, 1020, this);

        updateBoard();

        setPlayers();

    }

    /**
     * Get player's names and set them into view.
     */
    void setPlayers(){

        String whiteName = JOptionPane.showInputDialog(
                view.getWindow(),
                "Enter White's name.",
                "What is your name?",
                JOptionPane.PLAIN_MESSAGE);



        String blackName = JOptionPane.showInputDialog(
                view.getWindow(),
                "Enter Black's name.",
                "What is your name?",
                JOptionPane.PLAIN_MESSAGE);


        view.setNames(whiteName, blackName, whiteScore, blackScore);


    }

    /**
     * Game over, add a point to the winner and start a new game.
     * @param winner the player who won the game.
     */
    void gameOver(Player winner){
        view.setHistory("");

        if(winner == Player.WHITE)
            whiteScore++;

        if(winner == Player.BLACK)
            blackScore++;


        game = new GameManager(GameType.STANDARD);

        view.setScore(whiteScore, blackScore);
        updateBoard();

        view.controller.winMessage(winner, view);
    }

    /**
     * Update the board
     *
     * Read in the model from gameManager and call public functions in View to set up the board.
     *
     */
    public void updateBoard() {

        view.setTurn(game.currentTurn());

        view.clearAndResetBoard();

        //Build the Chess Board squares

        view.buildDefaultSquares();

        //Add pieces to the board

        for (int i = 8 * 8; i > 0; i--) {
            int x = (64 - i) % 8;
            int y = (i - 1) / 8;

            //Highlight squares where the player can move with his currently selected piece.
            if (showPossibleMoves && game.validMove(currX, currY, x, y) != GameManager.MoveStatus.ERROR) {
                view.buildHighlightedSquare(i, x, y);
            }

            BoardSquare piece = game.gameBoard.getPiece(x, y);

            Player owner = piece.owner;

            view.placePiece(i, owner, piece.imagename);

        }

        showPossibleMoves = false;

        view.setBoardVisible();
    }

    /**
     * Helper function used to find the X and Y values representing the piece in the model of Component c.
     *
     * Get's model's x and y coordinates for the Component c. This function works by comparing all components to the current piece held by the mouse.
     *
     * @param c component to get coordinates for.
     */
    void findModelXandY(Component c) {

        for (int i = 8 * 8; i > 0; i--) {
            int x = (64 - i) % 8;
            int y = (i - 1) / 8;

            Component panel = view.getPiece(i);

            if (c instanceof JLabel) {

                try {
                    if (c == ((JPanel) panel).getComponent(0)) {
                        currX = x;
                        currY = y;

                        return;
                    }

                } catch (Exception e) {
                    //silently ignore exception caught if the piece is not layered over the square.
                }
            }

            if (panel == c) {
                currX = x;
                currY = y;
            }
        }
    }

    /**
    * Add the selected chess piece to the dragging layer so it can be moved.
    * @param e Event captured.
    */
    public void mousePressed(MouseEvent e) {

        chessPiece = null;
        Component c = view.findPieceAt(e.getX(), e.getY());

        findModelXandY(c);

        if (c instanceof JPanel) return;

        Point parentLocation = c.getParent().getLocation();
        xAdjustment = parentLocation.x - e.getX();
        yAdjustment = parentLocation.y - e.getY();
        chessPiece = (JLabel) c;
        chessPiece.setLocation(e.getX() + xAdjustment, e.getY() + yAdjustment);

        view.addPieceToCursor(this);
    }

    /**
    *  Move the chess piece around
     *  @param me Event captured.
    */
    public void mouseDragged(MouseEvent me) {
        if (chessPiece == null) return;

        //The drag location should be within the bounds of the chess board

        int x = me.getX() + xAdjustment;
        int xMax = view.boardWidth() - chessPiece.getWidth();
        x = Math.min(x, xMax);
        x = Math.max(x, 0);

        int y = me.getY() + yAdjustment;
        int yMax = view.boardHeight() - chessPiece.getHeight();
        y = Math.min(y, yMax);
        y = Math.max(y, 0);

        chessPiece.setLocation(x, y);
    }

    /**
    *  Drop the chess piece back onto the chess board
    */
    public void mouseReleased(MouseEvent e) {


        view.hideCursor();

        if (chessPiece == null) return;

        //  Make sure the chess piece is no longer painted on the layered pane

        chessPiece.setVisible(false);
        view.removePieceGraphic(chessPiece);
        chessPiece.setVisible(true);

        //  The drop location should be within the bounds of the chess board

        int xMax = view.boardWidth()  - chessPiece.getWidth();
        int x = Math.min(e.getX(), xMax);
        x = Math.max(x, 0);

        int yMax = view.boardHeight() - chessPiece.getHeight();
        int y = Math.min(e.getY(), yMax);
        y = Math.max(y, 0);

        Component c = view.findPieceAt(x, y);

        int sourceX = currX;
        int sourceY = currY;

        //Set currX and currY to destination square. (The square which the player dropped the piece.)
        findModelXandY(c);


        //check move logic and attempt to move
        checkMoveLogic(sourceX, sourceY);

    }

    /**
     * Attempt to move by calling GameManager.Move
     *
     * Test if the game situation is check or checkmate, and send messages appropriately.
     *
     * @param sourceX source X
     * @param sourceY source Y
     */
    public void checkMoveLogic(int sourceX, int sourceY) {
        System.out.println("Attempt move from: " + sourceX + " " + sourceY + ", to:" + currX + " " + currY);

        if (game.Move(sourceX, sourceY, currX, currY) != GameManager.MoveStatus.ERROR) {
            System.out.println("Move valid!");

            Command cmd = (Command) (game.MoveHist.peek());

            view.addToHistory(cmd.histStr + "\n");


            updateBoard();

            Player inCheck = game.testCheck(false);//test check

            if(inCheck != Player.NONE) {
                checkMessage(inCheck);

                inCheck = game.testCheck(true);//test checkMate

                if (inCheck == Player.WHITE) {
                    System.out.println("White is in checkmate.");
                    checkMateMessage(inCheck);
                    gameOver(Player.BLACK);//black wins.
                } else if (inCheck == Player.BLACK) {
                    System.out.println("Black is in checkmate.");
                    checkMateMessage(inCheck);
                    gameOver(Player.WHITE);//white wins.
                }
            }

            if(game.testStalemate()) {
                staleMateMessage();
                gameOver(Player.NONE);
            }

        } else if (sourceX == currX && sourceY == currY) {
            showPossibleMoves = true;
            updateBoard();
        } else {
            updateBoard();
            illegalMoveMessage();
        }
    }

    /**
     * Do nothing with a click.
     */
    public void mouseClicked(MouseEvent e) {
    }

    /**
     * Do nothing with a mouse move.
     */
    public void mouseMoved(MouseEvent e) {
    }

    /**
     * Do nothing when mouse enters view.
     */
    public void mouseEntered(MouseEvent e) {
    }

    /**
     * Do nothing when mouse exits view.
     */
    public void mouseExited(MouseEvent e) {
    }

    /**
     * Send a message if the player is in check.
     * @param playerInCheck the player in check
     */
    public void checkMessage(Player playerInCheck){
        if(playerInCheck == Player.BLACK) {
            JOptionPane.showMessageDialog(view.getWindow(),
                    "Black is in check!",
                    "Check!", JOptionPane.INFORMATION_MESSAGE);

        } else if (playerInCheck == Player.WHITE) {
            JOptionPane.showMessageDialog(view.getWindow(),
                    "White is in check!",
                    "Check!", JOptionPane.INFORMATION_MESSAGE);

        }
    }


    /**
     * Send a message if the player is in check mate.
     * @param playerInCheck the player in check mate
     */
    public void checkMateMessage(Player playerInCheck){
        if(playerInCheck == Player.BLACK) {
            JOptionPane.showMessageDialog(view.getWindow(),
                    "Black is in checkmate!",
                    "Checkmate!", JOptionPane.INFORMATION_MESSAGE);

        } else if (playerInCheck == Player.WHITE) {
            JOptionPane.showMessageDialog(view.getWindow(),
                    "White is in checkmate!",
                    "Checkmate!", JOptionPane.INFORMATION_MESSAGE);

        }
    }

    /**
     * Send message if the move is illegal.
     */
    public void illegalMoveMessage(){
        JOptionPane.showMessageDialog(view.getWindow(),
                "Move not allowed.",
                "Illegal Move!", JOptionPane.INFORMATION_MESSAGE);

    }

    /**
     * Notify user that the game has ended.
     * @param winner the player who won the game.
     * @param view the view.
     */
    public void winMessage(Player winner, View view){
        if(winner == Player.NONE){
            JOptionPane.showMessageDialog(view.getWindow(),
                    "The game was a draw!",
                    "Draw", JOptionPane.INFORMATION_MESSAGE);

        } else if(winner == Player.BLACK) {
            JOptionPane.showMessageDialog(view.getWindow(),
                    "Black wins!",
                    "Game Over", JOptionPane.INFORMATION_MESSAGE);

        } else if (winner == Player.WHITE) {
            JOptionPane.showMessageDialog(view.getWindow(),
                    "White wins!",
                    "Game Over", JOptionPane.INFORMATION_MESSAGE);

        }

    }

    private void staleMateMessage(){
            JOptionPane.showMessageDialog(view.getWindow(),
                    "The game was a draw due to stalemate!",
                    "Stalemate!", JOptionPane.INFORMATION_MESSAGE);
    }
}