Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /*
- * Author: KV from ITSE 2421 course (Final Project)
- * Description:
- * This program is an implementation of the board game Chess. It supports a
- * human vs. human mode and a human vs. computer mode.
- */
- import java.util.*;
- public class P4ChessBL
- {
- //----------------------------------------------------------------------------------------
- // Copyright © 2006 - 2015 Tangible Software Solutions Inc.
- // This class can be used by anyone provided that the copyright notice remains intact.
- //
- // This class provides the ability to initialize array elements with the default
- // constructions for the array type.
- //----------------------------------------------------------------------------------------
- public final class Arrays
- {
- public static ClassicMap[] initializeWithDefaultClassicMapInstances(int length)
- {
- ClassicMap[] array = new ClassicMap[length];
- for (int i = 0; i < length; i++)
- {
- array[i] = new ClassicMap();
- }
- return array;
- }
- public static std_pair[] initializeWithDefaultpairInstances(int length)
- {
- std_pair[] array = new std_pair[length];
- for (int i = 0; i < length; i++)
- {
- array[i] = new std_pair();
- }
- return array;
- }
- }
- //----------------------------------------------------------------------------------------
- // Copyright © 2006 - 2015 Tangible Software Solutions Inc.
- // This class can be used by anyone provided that the copyright notice remains intact.
- //
- // This class provides the ability to simulate the behavior of the C/C++ functions for
- // generating random numbers.
- // 'rand' converts to the parameterless overload of NextNumber
- // 'random' converts to the single-parameter overload of NextNumber
- // 'randomize' converts to the parameterless overload of Seed
- // 'srand' converts to the single-parameter overload of Seed
- //----------------------------------------------------------------------------------------
- public final class RandomNumbers
- {
- private static Random r;
- public static int nextNumber()
- {
- if (r == null)
- Seed();
- return r.nextInt();
- }
- public static int nextNumber(int ceiling)
- {
- if (r == null)
- Seed();
- return r.nextInt(ceiling);
- }
- public static void seed()
- {
- r = new Random();
- }
- public static void seed(int seed)
- {
- r = new Random(seed);
- }
- }
- /* These const values are used for identifying whether the "piece" occupying
- * a chess board space is black, white, or in the case of a blank spot,
- * "clear."
- */
- public static final int BLACK = 0;
- public static final int WHITE = 1;
- public static final int CLEAR = 2;
- public static final int CHECK_MOVE = 1; // this is a piece move "mode" designating an AI board evaluation
- public static final int REAL_MOVE = 2; // this is a piece move "mode" designating an actual AI move
- public class Coord
- {
- public int m_X;
- public int m_Y;
- }
- /* This is the class to handle the layout of the chess board.
- */
- public class ChessBoard
- {
- /* The ctor fills the chess board grid with a proper starting setup.
- */
- public ChessBoard()
- {
- this.m_capturelessMoves = 0;
- m_lastMoves[P4ChessBL.BLACK].first = 8; // beginning "last move" of the black piece as "nothing"
- m_lastMoves[P4ChessBL.BLACK].second = 8; // ^-- in this case, not a valid move at all
- m_lastMoves[P4ChessBL.WHITE].first = 8; // similarly, we set the white pieces' last move.
- m_lastMoves[P4ChessBL.WHITE].second = 8;
- m_lastMoveRepeats[P4ChessBL.BLACK] = 0; // here we note that there has been no repetition of moves yet
- m_lastMoveRepeats[P4ChessBL.WHITE] = 0; // ^-- for either black or white pieces.
- m_locations = new ChessPiece[8][];
- for (int i = 0; i < 8; ++i) // this loop creates a chess board grid for holding piece objects
- {
- m_locations[i] = new ChessPiece[8];
- }
- ChessPiece piece;
- piece = new ChessPiece(CPiece.Type.ROOK, P4ChessBL.BLACK); // following lines set up some pieces on the board for black
- m_locations[0][0] = piece;
- piece = new ChessPiece(CPiece.Type.ROOK, P4ChessBL.BLACK);
- m_locations[7][0] = piece;
- piece = new ChessPiece(CPiece.Type.KNIGHT, P4ChessBL.BLACK);
- m_locations[1][0] = piece;
- piece = new ChessPiece(CPiece.Type.KNIGHT, P4ChessBL.BLACK);
- m_locations[6][0] = piece;
- piece = new ChessPiece(CPiece.Type.BISHOP, P4ChessBL.BLACK);
- m_locations[2][0] = piece;
- piece = new ChessPiece(CPiece.Type.BISHOP, P4ChessBL.BLACK);
- m_locations[5][0] = piece;
- piece = new ChessPiece(CPiece.Type.QUEEN, P4ChessBL.BLACK);
- m_locations[3][0] = piece;
- piece = new ChessPiece(CPiece.Type.KING, P4ChessBL.BLACK);
- m_locations[4][0] = piece;
- for (int i = 0; i < 8; ++i) // this loop creates black pawn pieces to setup the board
- {
- piece = new ChessPiece(CPiece.Type.PAWN, P4ChessBL.BLACK);
- m_locations[i][1] = piece;
- }
- piece = new ChessPiece(CPiece.Type.ROOK, P4ChessBL.WHITE); // setting up the white king's row here
- m_locations[0][7] = piece;
- piece = new ChessPiece(CPiece.Type.ROOK, P4ChessBL.WHITE);
- m_locations[7][7] = piece;
- piece = new ChessPiece(CPiece.Type.KNIGHT, P4ChessBL.WHITE);
- m_locations[1][7] = piece;
- piece = new ChessPiece(CPiece.Type.KNIGHT, P4ChessBL.WHITE);
- m_locations[6][7] = piece;
- piece = new ChessPiece(CPiece.Type.BISHOP, P4ChessBL.WHITE);
- m_locations[2][7] = piece;
- piece = new ChessPiece(CPiece.Type.BISHOP, P4ChessBL.WHITE);
- m_locations[5][7] = piece;
- piece = new ChessPiece(CPiece.Type.QUEEN, P4ChessBL.WHITE);
- m_locations[3][7] = piece;
- piece = new ChessPiece(CPiece.Type.KING, P4ChessBL.WHITE);
- m_locations[4][7] = piece;
- for (int i = 0; i < 8; ++i) // and now we place white pawns
- {
- piece = new ChessPiece(CPiece.Type.PAWN, P4ChessBL.WHITE);
- m_locations[i][6] = piece;
- }
- for (int i = 0; i < 8; ++i) // the rest of the board is represented by "blank" pieces of "clear" color
- {
- for (int j = 2; j < 6; ++j)
- {
- piece = new ChessPiece(CPiece.Type.BLANK, P4ChessBL.CLEAR);
- m_locations[i][j] = piece;
- }
- }
- for (int i = 0; i < 2; ++i) // we set up our piece map that records which pieces a player has left
- {
- m_pieceMaps[i].put(CPiece.Type.PAWN.getValue(), 8);
- m_pieceMaps[i].put(CPiece.Type.ROOK.getValue(), 2);
- m_pieceMaps[i].put(CPiece.Type.KNIGHT.getValue(), 2);
- m_pieceMaps[i].put(CPiece.Type.BISHOP.getValue(), 2);
- m_pieceMaps[i].put(CPiece.Type.QUEEN.getValue(), 1);
- m_pieceMaps[i].put(CPiece.Type.KING.getValue(), 1);
- }
- }
- /* Copy ctor for the ChessBoard class.
- */
- public ChessBoard(ChessBoard src)
- {
- m_locations = new ChessPiece[8][];
- for (int i = 0; i < 8; ++i)
- {
- m_locations[i] = new ChessPiece[8];
- }
- copy(src);
- }
- /* The ChessBoard class dtor frees memory allocated for the board grid.
- */
- public void dispose()
- {
- for (int i = 0; i < 8; ++i)
- {
- for (int j = 0; j < 8; ++j)
- {
- if (m_locations[i][j] != null)
- m_locations[i][j].dispose();
- }
- m_locations[i] = null;
- }
- m_locations = null;
- }
- /* Overloaded operator= for the ChessBoard class.
- */
- public final ChessBoard copyFrom(ChessBoard rhs)
- {
- if (this == rhs)
- {
- return this;
- }
- copy(rhs);
- return this;
- }
- /* This member function is used to display the board to the screen with the
- * current chess piece locations. Extended ASCII is used to draw the lines of
- * the board grid itself.
- */
- public final void display()
- {
- byte c;
- byte cc;
- boolean rightWhite;
- System.out.print('\n');
- System.out.print(32);
- for (int i = 0; i < 8; ++i)
- {
- System.out.print(32);
- System.out.print(32);
- System.out.print(97 + i);
- System.out.print(32);
- }
- System.out.print('\n');
- System.out.print(32);
- System.out.print(218);
- for (int i = 0; i < 8; ++i)
- {
- System.out.print(196);
- System.out.print(196);
- System.out.print(196);
- if (i < 7)
- {
- System.out.print(194);
- }
- else
- {
- System.out.print(191);
- }
- }
- System.out.print('\n');
- cc = (byte)'8';
- rightWhite = false;
- for (int i = 0; i < 8; ++i)
- {
- System.out.print(cc--);
- System.out.print(179);
- for (int j = 0; j < 8; ++j)
- {
- if (!rightWhite && (((j + i % 2) % 2) != 0))
- {
- System.out.print(32);
- }
- else
- {
- if (!rightWhite && (((j + i % 2) % 2) != 0))
- {
- System.out.print(32);
- }
- else
- {
- if (m_locations[j][i].getType() != CPiece.Type.BLANK)
- {
- System.out.print(221);
- }
- else
- {
- System.out.print(219);
- }
- }
- }
- switch (m_locations[j][i].getType().toString)
- {
- case "PAWN":
- c = (byte)'p';
- break;
- case "ROOK":
- c = (byte)'r';
- break;
- case "KNIGHT":
- c = (byte)'n';
- break;
- case "BISHOP":
- c = (byte)'b';
- break;
- case "QUEEN":
- c = (byte)'q';
- break;
- case "KING":
- c = (byte)'k';
- break;
- default:
- if ((rightWhite) && (((j + i % 2) % 2) != 0 ))
- {
- c = (byte)32;
- }
- else
- {
- if (!(rightWhite) && (((j + i % 2) % 2) != 0 ))
- {
- c = (byte)32;
- }
- else
- {
- c = (byte)219;
- }
- }
- }
- if (c != (byte)32 && c != (byte)219) // we're drawing the pieces, and this if statement will generate
- {
- c = c - (32 * m_locations[j][i].getColor()); // capital letters for the white ones
- }
- System.out.print(c);
- if (rightWhite && (((j + i % 2) % 2) != 0))
- {
- System.out.print(32);
- }
- else
- {
- if (!rightWhite && (((j + i % 2) % 2) != 0))
- {
- System.out.print(32);
- }
- else
- {
- if (m_locations[j][i].getType() != CPiece.Type.BLANK)
- {
- System.out.print(222);
- }
- else
- {
- System.out.print(219);
- }
- }
- }
- System.out.print(179);
- rightWhite = !rightWhite;
- }
- System.out.print('\n');
- System.out.print(32);
- if (i < 7)
- {
- System.out.print(195);
- for (int j = 0; j < 8; ++j)
- {
- System.out.print(196);
- System.out.print(196);
- System.out.print(196);
- if (j < 7)
- {
- System.out.print(197);
- }
- else
- {
- System.out.print(180);
- }
- }
- }
- else
- {
- System.out.print(192);
- for (int j = 0; j < 8; ++j)
- {
- System.out.print(196);
- System.out.print(196);
- System.out.print(196);
- if (j < 7)
- {
- System.out.print(193);
- }
- else
- {
- System.out.print(217);
- }
- }
- }
- System.out.print('\n');
- }
- }
- /* This function is used to reposition the pieces in a configuration reflecting
- * a board that has been "flipped" or turned around for a perspective from
- * the opposite side of the board. It is mainly used before displaying the
- * board prior to a piece move.
- */
- public final void flip()
- {
- ChessPiece piece;
- for (int i = 0; i < 4; ++i)
- {
- for (int j = 0; j < 8; ++j)
- {
- piece = m_locations[j][i];
- m_locations[j][i] = m_locations[7 - j][7 - i];
- m_locations[7 - j][7 - i] = piece;
- }
- }
- }
- /* This function returns a pointer to the piece located at the given chess
- * board coordinates.
- */
- public final ChessPiece at(int x, int y)
- {
- return m_locations[x][y];
- }
- /* This function is used to relocate a piece on the chess board.
- */
- public final void move(int bX, int bY, int eX, int eY)
- {
- move(bX, bY, eX, eY, 0);
- }
- public final void move(int bX, int bY, int eX, int eY, int mode)
- { // purposes such as AI, or if this is an actual piece move for play
- if (bX == eX && bY == eY)
- return;
- java.lang.Class tempType = new java.lang.Class();
- if (mode == 0 || mode == P4ChessBL.REAL_MOVE) // if !mode or REAL_MOVE, we're moving pieces, we will determine if a player
- { // has just lost a piece from their arsenal
- tempType = m_locations[eX][eY].getType();
- if (tempType != CPiece.Type.BLANK)
- {
- m_capturelessMoves = 0; // here we're accounting for a capture made, so the count for 50 capturless
- --m_pieceMaps[m_locations[eX][eY].getColor()].get(tempType); // moves starts over (we're far from be able to call a DRAW here)
- if (m_pieceMaps[m_locations[eX][eY].getColor()].get(tempType) == 0)
- {
- m_pieceMaps[m_locations[eX][eY].getColor()].remove(tempType);
- }
- }
- if (at(bX, bY).getType() != CPiece.Type.PAWN) // if that piece just moved wasn't a pawn, we increment the move count since
- {
- ++m_capturelessMoves; // no capture was made on this move
- }
- else
- {
- m_capturelessMoves = 0; // yet, here is WAS a pawn... pawns reset the counter
- }
- }
- ChessPiece piece;
- piece = new ChessPiece(CPiece.Type.BLANK, P4ChessBL.CLEAR); // we create a blank space to leave behind when we move this piece
- if (m_locations[eX][eY] != null)
- m_locations[eX][eY].dispose(); // erase the piece object at the target move location
- m_locations[eX][eY] = m_locations[bX][bY]; // replace the target piece location with the piece what was moved
- m_locations[bX][bY] = piece; // the old position is replaced with out blank/clear piece object
- m_locations[eX][eY].incrementMoves(); // we increment the number of times this piece has been moved now
- if (at(eX, eY).getType() == CPiece.Type.PAWN && eX != bX && (mode == 0 || mode == P4ChessBL.REAL_MOVE)) // here we check if this move is an en Passant capture. if it is, we need
- {
- if (7 - m_lastMoveX == eX && 7 - m_lastMoveY == eY + 1) // ^-- to handle how the pieces are arranged on the board in a special manner
- {
- piece = new ChessPiece(CPiece.Type.BLANK, P4ChessBL.CLEAR);
- if (m_locations[7 - m_lastMoveX][7 - m_lastMoveY] != null)
- m_locations[7 - m_lastMoveX][7 - m_lastMoveY].dispose();
- m_locations[7 - m_lastMoveX][7 - m_lastMoveY] = piece;
- System.out.print("\nEn passant capture.");
- System.out.print("\n");
- }
- }
- if (eY == 0 && at(eX, eY).getType() == CPiece.Type.PAWN && mode == 0) // did a pawn make it all the way to the enemie's king's row?
- { // ^-- if so, this is a PAWN PROMOTION
- String choice;
- byte c;
- c = (byte)0;
- do
- {
- System.out.print("\nPawn promotion!\nChoose Q)ueen, R)ook, B)ishop, or N) " + "Knight: ");
- choice = new Scanner(System.in).nextLine();
- if (choice.length() != 0)
- {
- c = Character.toUpperCase(choice.charAt(0));
- }
- } while (c != 'Q' && c != 'R' && c != 'B' && c != 'N');
- switch (c) // this switch will create a promotion piece to replace the pawn with
- {
- case 'N':
- piece = new ChessPiece(CPiece.Type.KNIGHT, at(eX, eY).getColor());
- break;
- case 'B':
- piece = new ChessPiece(CPiece.Type.BISHOP, at(eX, eY).getColor());
- break;
- case 'R':
- piece = new ChessPiece(CPiece.Type.ROOK, at(eX, eY).getColor());
- break;
- default:
- piece = new ChessPiece(CPiece.Type.QUEEN, at(eX, eY).getColor());
- }
- if (m_locations[eX][eY] != null)
- m_locations[eX][eY].dispose(); // we need to get rid of that promoted pawn
- m_locations[eX][eY] = piece; // we need to replace it with the promotion piece
- if (mode == 0) // if this is a real move, then we need to update the player's pieces arsenal
- {
- --m_pieceMaps[piece.getColor()].get(CPiece.Type.PAWN.getValue());
- if (m_pieceMaps[piece.getColor()].get(CPiece.Type.PAWN.getValue()) == 0)
- {
- m_pieceMaps[piece.getColor()].remove(CPiece.Type.PAWN);
- }
- java.util.Iterator<java.lang.Class, int> it;
- it.copyFrom(m_pieceMaps[piece.getColor()].find(piece.getType()));
- if (it != m_pieceMaps[piece.getColor()].end())
- {
- ++it.second;
- }
- else
- {
- m_pieceMaps[piece.getColor()].put(piece.getType(), 1);
- }
- }
- }
- else
- {
- if (eY == 0 && at(eX, eY).getType() == CPiece.Type.PAWN && mode == P4ChessBL.REAL_MOVE) // this is a special mode, handling pawn promotion for the computer
- { // the computer always chooses a QUEEN for its new piece
- System.out.print("\nPawn promotion!\nComputer chooses a Queen.");
- System.out.print("\n");
- piece = new ChessPiece(CPiece.Type.QUEEN, at(eX, eY).getColor());
- if (m_locations[eX][eY] != null)
- m_locations[eX][eY].dispose();
- m_locations[eX][eY] = piece;
- if (mode == 0)
- {
- --m_pieceMaps[piece.getColor()].get(CPiece.Type.PAWN.getValue());
- if (m_pieceMaps[piece.getColor()].get(CPiece.Type.PAWN.getValue()) == 0)
- {
- m_pieceMaps[piece.getColor()].remove(CPiece.Type.PAWN);
- }
- java.util.Iterator<java.lang.Class, int> it;
- it.copyFrom(m_pieceMaps[piece.getColor()].find(CPiece.Type.QUEEN));
- if (it != m_pieceMaps[piece.getColor()].end())
- {
- ++it.second;
- }
- else
- {
- m_pieceMaps[piece.getColor()].put(CPiece.Type.QUEEN.getValue(), 1);
- }
- }
- }
- }
- if (mode == 0 || mode == P4ChessBL.REAL_MOVE) // here we are tracking the last moves made to see if there is a
- { // ^-- three-fold repetition in moves.
- m_lastMoveX = eX;
- m_lastMoveY = eY;
- if (m_lastMoves[at(eX, eY).getColor()].first == bX && m_lastMoves[at(eX, eY).getColor()].second == bY)
- {
- ++m_lastMoveRepeats[at(eX, eY).getColor()]; // back-and-forth piece movements will inrement the repeated moves counter
- m_lastMoves[at(eX, eY).getColor()].first = eX;
- m_lastMoves[at(eX, eY).getColor()].second = eY;
- }
- else
- {
- m_lastMoves[at(eX, eY).getColor()].first = eX;
- m_lastMoves[at(eX, eY).getColor()].second = eY;
- m_lastMoveRepeats[at(eX, eY).getColor()] = 1;
- }
- }
- }
- /* This function checks to see if the last move made was to X,Y passed in,
- * from the perspective of a flipped board, it is used for AI processing.
- */
- public final boolean lastMoveWas(int X, int Y)
- {
- return (7 - m_lastMoveX == X && 7 - m_lastMoveY == Y);
- }
- /* This function replaces a piece object on the board with a new one supplied
- */
- public final void replace(ChessPiece piece, int X, int Y)
- {
- if (m_locations[X][Y] != null)
- m_locations[X][Y].dispose();
- m_locations[X][Y] = piece;
- }
- /* This boolean function returns true if there is an option to call DRAW
- */
- public final boolean isPotentialDraw(int turn)
- {
- return m_capturelessMoves >= 50 || (m_lastMoveRepeats[turn] > 2 && m_lastMoveRepeats[(turn + 1) % 2] > 3);
- }
- //C++ TO JAVA CONVERTER TODO TASK: The implementation of the following method could not be found:
- // boolean callDraw(ushort NamelessParameter);
- /* If en Passant is a valid move, this is going to reset the 3-fold move c
- * counter because the board presents slightly different options than when
- * pieces are otherwise simply moved back and forth repeatedly
- */
- public final boolean enPassantOption(int color)
- {
- m_lastMoveRepeats[(color + 1) % 2] = 1;
- return true;
- }
- /* This function returns true if there are not enough pieces left on the board
- * to accomplish a check mate. It is used to determine if the game is a draw
- */
- public final boolean isInsufficientPieces(ChessBoard board)
- {
- if ((board.m_pieceMaps[P4ChessBL.BLACK].size() == 2 && board.m_pieceMaps[P4ChessBL.WHITE].size() == 2) && board.m_pieceMaps[P4ChessBL.BLACK].containsKey(CPiece.Type.BISHOP) && board.m_pieceMaps[P4ChessBL.WHITE].containsKey(CPiece.Type.BISHOP) && P4ChessBL.sameSquareColorBishops(board))
- {
- return true;
- }
- if (board.m_pieceMaps[P4ChessBL.BLACK].size() + board.m_pieceMaps[P4ChessBL.WHITE].size() > 3)
- {
- return false;
- }
- boolean[] insufficient = new boolean[2];
- insufficient[P4ChessBL.BLACK] = false;
- insufficient[P4ChessBL.WHITE] = false;
- for (int i = 0; i < 2; ++i)
- {
- if (board.m_pieceMaps[i].size() == 1)
- {
- insufficient[i] = true;
- continue;
- }
- if (board.m_pieceMaps[i].containsKey(CPiece.Type.KNIGHT).getValue() != 0)
- {
- insufficient[i] = true;
- continue;
- }
- if (board.m_pieceMaps[i].containsKey(CPiece.Type.BISHOP).getValue() != 0)
- {
- insufficient[i] = true;
- continue;
- }
- }
- return insufficient[P4ChessBL.BLACK] && insufficient[P4ChessBL.WHITE];
- }
- public boolean callDraw(int turn)
- {
- if (isPotentialDraw(turn))
- {
- System.out.print((turn == BLACK != false ? "Black " : "White "));
- if (m_capturelessMoves >= 50)
- {
- System.out.print("calls draw based on 50 move rule: No captures made or " + "pawns moved.");
- System.out.print("\n");
- return true;
- }
- System.out.print("calls draw based on threefold repetition of moves.");
- System.out.print("\n");
- return true;
- }
- return false;
- }
- /* This copy function is used by both the ChessBoard copy ctor and operator=
- * for creating a board copy.
- */
- private void copy(ChessBoard src)
- {
- for (int i = 0; i < 8; ++i)
- {
- for (int j = 0; j < 8; ++j)
- {
- m_locations[i][j] = new ChessPiece(src.m_locations[i][j]);
- }
- }
- }
- private ChessPiece[][] m_locations; // this will be an array to represent a chess board grid
- private java.util.TreeMap<java.lang.Class, int>[] m_pieceMaps = P4ChessBL.Arrays.initializeWithDefaultClassicMapInstances(2); // this map tracks number of pieces left in a player's arsenal
- private Arrays.std_pair<int, int>[] m_lastMoves = P4ChessBL.Arrays.initializeWithDefaultpairInstances(2); // this pair is used in determining if there is a repetition of moves
- private int[] m_lastMoveRepeats = new int[2]; // this counts the number of times the same moves have been repeated
- private int m_lastMoveX; // this is the last move made, used for checking if en Passant is valid
- private int m_lastMoveY; // this is the 'Y' coordinate of the last move (see above)
- private int m_capturelessMoves; // this variable counts moves where no pawns are moved or captures made
- } // ^-- it will be used to determine if the game can be called a draw
- /* If a player calls draw, here we handle the output for the specific game
- * draw conditions that were met.
- */
- /* This is the chess piece class to represent the occupation of a space on the
- * chess board.
- */
- public class ChessBoard
- {
- }
- public class ChessPiece
- {
- /* The ctor for ChessPiece takes a piece type and color.
- */
- public ChessPiece(java.lang.Class type, int color)
- {
- this.m_type = type;
- this.m_color = color;
- this.m_moves = 0;
- }
- public void dispose()
- {
- }
- /* This member function returns the chess piece type.
- */
- public final java.lang.Class getType()
- {
- return m_type;
- }
- /* This member function returns the chess piece color.
- */
- public final int getColor()
- {
- return m_color;
- }
- /* This function is used to record a new movement of a piece. Movement tracking
- * is necessary for evaluating validity of special piece moves like en passant
- * capture and castling.
- */
- public final void incrementMoves()
- {
- ++m_moves;
- }
- /* Reduces the number of times a piece has been moved. Used for adjustment when
- * a function incidentally increments the movement of a piece in a case where
- * a board evaluation is taking place, and is not intended as an actual move.
- */
- public final void decrementMoves()
- {
- --m_moves;
- }
- /* Returns the number of times a piece has been moved.
- */
- public final int getMoves()
- {
- return m_moves;
- }
- private java.lang.Class m_type = new java.lang.Class(); // this variable holds the type of piece this object represents
- private int m_color; // this variable holds the color of the piece, white or black
- private int m_moves; // this variable holds the number of moves the piece has made
- }
- /* This enum represents values for each of the possible "pieces" that can
- * occupy a space on the chess board, including "blank" for a vacant space.
- */
- public class CPiece
- {
- public static enum Type
- {
- BLANK,
- PAWN,
- BISHOP,
- KNIGHT,
- ROOK,
- QUEEN,
- KING;
- public int getValue()
- {
- return this.ordinal();
- }
- public static Type forValue(int value)
- {
- return values()[value];
- }
- }
- }
- /* This is the game play loop, it governs the the player's turns or delegates
- * a move to the computer to play.
- */
- public static void play()
- {
- boolean gameOver = false; // game-play sentinel boolean variable
- boolean computerPlay; // will the computer be playing? this bool hold the answer.
- boolean skipTurn = false; // do we need to skip a color's turn? it depends on who moves first
- String move; // this string is used for input of move coordinates as well as game options
- int turn; // this holds the "color" of whose turn it is
- ChessBoard board = new ChessBoard(); // we create the ChessBoard object
- turn = WHITE;
- System.out.print("\nWelcome to the game of Chess!\n");
- System.out.print("\n");
- do
- { // We need to get some info about how the game will be played, first.
- System.out.print("Enter 1 for computer play, 2 for human vs. human: ");
- move = new Scanner(System.in).nextLine();
- } while (!(move.length() != 0) || (move.charAt(0) != '1' && move.charAt(0) != '2'));
- if (move.charAt(0) == '1')
- {
- computerPlay = true;
- do
- {
- System.out.print("Enter W to play white pieces, or B to play black: ");
- move = new Scanner(System.in).nextLine();
- } while (!(move.length() != 0) || (!(Character.toUpperCase(move.charAt(0)) == 'W') && !(Character.toUpperCase(move.charAt(0)) == 'B')));
- if (Character.toUpperCase(move.charAt(0)) == 'B')
- {
- skipTurn = true;
- turn = BLACK;
- board.flip();
- }
- else
- {
- skipTurn = false;
- }
- }
- else
- {
- computerPlay = false;
- }
- System.out.print((computerPlay ? "\nComputer competitor mode." : "\nHuman vs. " + "human mode."));
- System.out.print("\n");
- if (computerPlay)
- {
- System.out.print((skipTurn ? "Playing black pieces." : "Playing white pieces."));
- System.out.print("\n");
- }
- System.out.print("Enter ? for help.");
- System.out.print("\n");
- do
- { // here we enter the game-play loop
- if (!skipTurn)
- do
- {
- board.display(); // show the board
- if (P4ChessBL.putInCheck(board, turn)) // the loop checks the board configuration for certain scenarios
- {
- if (P4ChessBL.isCheckMate(board, turn))
- {
- System.out.print("Check Mate!");
- System.out.print("\n");
- gameOver = true;
- break;
- }
- System.out.print("You are in check.");
- System.out.print("\n");
- }
- else
- {
- if (P4ChessBL.isStalemate(board, turn))
- {
- System.out.print("Stalemate!");
- System.out.print("\n");
- gameOver = true;
- break;
- }
- else
- {
- if (P4ChessBL.isDraw(board))
- {
- System.out.print("Draw!");
- System.out.print("\n");
- gameOver = true;
- break;
- }
- }
- }
- if (board.isPotentialDraw(turn))
- {
- System.out.print("CPiece.Type \"DRAW\" to declare Draw. ");
- }
- System.out.print(':');
- move = new Scanner(System.in).nextLine();
- if ((move.length() != 0) && Character.toUpperCase(move.charAt(0)) == 'Q')
- {
- gameOver = true;
- break;
- }
- if (board.isPotentialDraw(turn) && P4ChessBL.allCaps(move).equals("DRAW"))
- {
- gameOver = board.callDraw(turn);
- if (gameOver)
- {
- System.out.print("Draw!");
- System.out.print("\n");
- }
- break;
- }
- if (move.equals("?"))
- {
- P4ChessBL.displayHelp();
- }
- } while (!P4ChessBL.goodMove(board, move, turn));
- else
- {
- skipTurn = false;
- }
- board.flip();
- if (turn == WHITE)
- {
- turn = BLACK;
- }
- else
- {
- turn = WHITE;
- }
- if (computerPlay && !gameOver) // if the computer is playing, it will make its move here
- {
- if (P4ChessBL.isCheckMate(board, turn))
- {
- System.out.print("Check Mate!");
- System.out.print("\n");
- gameOver = true;
- break;
- }
- else
- {
- if (P4ChessBL.isStalemate(board, turn))
- {
- System.out.print("Stalemate!");
- System.out.print("\n");
- gameOver = true;
- break;
- }
- else
- {
- if (P4ChessBL.isDraw(board))
- {
- System.out.print("Draw!");
- System.out.print("\n");
- gameOver = true;
- break;
- }
- else
- {
- if (board.isPotentialDraw(turn))
- {
- gameOver = board.callDraw(turn);
- if (gameOver)
- {
- System.out.print("Draw!");
- System.out.print("\n");
- }
- break;
- }
- }
- }
- }
- P4ChessBL.computerMove(board, turn);
- if (turn == WHITE)
- {
- turn = BLACK;
- }
- else
- {
- turn = WHITE;
- }
- board.flip();
- }
- } while (!gameOver);
- }
- /* This function evaluates whether or not the move coordinates entered are
- * valid, and if they are it will go ahead and make function calls to make that
- * move
- */
- public static boolean goodMove(ChessBoard board, String move, int turn)
- {
- if (move.equals("?"))
- {
- return false;
- }
- if (move.length() != 5)
- {
- System.out.print("\nErroneous input.");
- System.out.print("\n");
- return false;
- }
- byte beginCoordX;
- byte beginCoordY;
- byte endCoordX;
- byte endCoordY;
- beginCoordX = (byte)(move.charAt(0)); // we're converting the text input into numerical coordinates
- beginCoordY = (byte)(move.charAt(1));
- endCoordX = (byte)(move.charAt(3));
- endCoordY = (byte)(move.charAt(4));
- beginCoordX = (byte)(Character.toUpperCase(beginCoordX));
- endCoordX = (byte)(Character.toUpperCase(endCoordX));
- beginCoordX -= 65;
- endCoordX -= 65;
- beginCoordY -= 49;
- endCoordY -= 49;
- beginCoordY = (byte)(7 - beginCoordY);
- endCoordY = (byte)(7 - endCoordY);
- if (!((beginCoordX >= 0 && beginCoordX < 8) && (beginCoordY >= 0 && beginCoordY < 8) && (endCoordX >= 0 && endCoordX < 8) && (endCoordY >= 0 && endCoordY < 8))) // we respond to some potential errors in input for this turn
- {
- System.out.print("\nErroneous input.");
- System.out.print("\n");
- return false;
- }
- ChessPiece piece;
- piece = new ChessPiece(board.at(beginCoordX, beginCoordY));
- if (piece.getColor() != turn || piece.getType() == CPiece.Type.BLANK)
- {
- System.out.print("\nYou need to move one of your pieces.\nInvalid move.");
- System.out.print("\n");
- if (piece != null)
- piece.dispose();
- return false;
- }
- if (beginCoordX == endCoordX && beginCoordY == endCoordY)
- {
- System.out.print("\nInvalid move.");
- System.out.print("\n");
- if (piece != null)
- piece.dispose();
- return false;
- }
- if (P4ChessBL.inRange(board, piece, beginCoordX, beginCoordY, endCoordX, endCoordY) && P4ChessBL.pathClear(board, piece, beginCoordX, beginCoordY, endCoordX, endCoordY)) // we're checking to see if a move is possible given the coordinates
- {
- if (piece.getType().equals(CPiece.Type.KING) && P4ChessBL.putInCheck(board, piece.getColor()) && beginCoordY == endCoordY && (beginCoordX - 2 == endCoordX || beginCoordX + 2 == endCoordX)) // handling an attempt to castle out of check here
- {
- System.out.print("\nYou may not castle out of check.");
- }
- else
- {
- if (piece.getType().equals(CPiece.Type.KING) && beginCoordY == endCoordY && (beginCoordX - 2 == endCoordX || beginCoordX + 2 == endCoordX) && ((beginCoordX - 2 == endCoordX && P4ChessBL.putInCheck(board, piece.getColor(), beginCoordX, beginCoordY, beginCoordX - 1, endCoordY)) || (beginCoordX + 2 == endCoordX && P4ChessBL.putInCheck(board, piece.getColor(), beginCoordX, beginCoordY, beginCoordX + 1, endCoordY)))) // handling an attempt to castle THROUGH check, here
- {
- System.out.print("\nYou may not castle through check.");
- }
- else
- {
- if (!P4ChessBL.putInCheck(board, piece.getColor(), beginCoordX, beginCoordY, endCoordX, endCoordY)) // handling a successful move
- {
- board.move(beginCoordX, beginCoordY, endCoordX, endCoordY);
- if (piece.getType().equals(CPiece.Type.KING) && beginCoordY == endCoordY && (beginCoordX - 2 == endCoordX || beginCoordX + 2 == endCoordX)) // ...and handling a castle move, if that's the case
- {
- System.out.print("\nCastle move.");
- System.out.print("\n");
- if (beginCoordX > endCoordX)
- {
- board.move(0, 7, 2 + piece.getColor(), 7);
- }
- else
- {
- board.move(7, 7, 4 + piece.getColor(), 7);
- }
- }
- if (piece != null)
- piece.dispose();
- return true;
- }
- else
- {
- System.out.print("\nThat move would leave you in check.");
- }
- }
- }
- }
- System.out.print("\nInvalid move.");
- System.out.print("\n");
- if (piece != null)
- piece.dispose();
- return false;
- }
- /* This function is used for checking whether or not a piece is capable of
- * making a move to the coordinate supplied.
- */
- public static boolean inRange(ChessBoard board, ChessPiece piece, int bX, int bY, int eX, int eY)
- {
- ChessPiece target;
- target = board.at(eX, eY);
- switch (piece.getType().toString)
- {
- case "PAWN":
- if ((bY - eY == 1 && bX == eX) || (piece.getMoves() == 0 && bY - eY == 2 && bX == eX))
- {
- return true;
- }
- if (bY - eY == 1 && ((eX - 1 == bX || eX + 1 == bX) && target.getType().equals(CPiece.Type.BLANK) && target.getColor() != piece.getColor()))
- {
- return true;
- }
- if (bY - eY == 1 && eX != bX && board.at(eX, eY + 1).getType().equals(CPiece.Type.PAWN) && board.at(eX, eY + 1).getMoves() == 1 && eY == 2 && board.lastMoveWas(eX, eY + 1))
- {
- return board.enPassantOption(piece.getColor());
- }
- return false;
- case "ROOK":
- if ((bX == eX && bY != eY) || (bX != eX && bY == eY))
- {
- return true;
- }
- return false;
- case "KNIGHT":
- if ((bX == eX - 2 || bX == eX + 2) && (bY == eY - 1 || bY == eY + 1))
- {
- return true;
- }
- if ((bY == eY - 2 || bY == eY + 2) && (bX == eX - 1 || bX == eX + 1))
- {
- return true;
- }
- return false;
- case "BISHOP":
- if (bX > eX && (bY - eY == bX - eX || eY - bY == bX - eX))
- {
- return true;
- }
- if (bX < eX && (bY - eY == eX - bX || eY - bY == eX - bX))
- {
- return true;
- }
- return false;
- case "QUEEN":
- if ((bX == eX && bY != eY) || (bX != eX && bY == eY))
- {
- return true;
- }
- if (bX > eX && (bY - eY == bX - eX || eY - bY == bX - eX))
- {
- return true;
- }
- if (bX < eX && (bY - eY == eX - bX || eY - bY == eX - bX))
- {
- return true;
- }
- return false;
- case "KING":
- if (bX <= eX + 1 && bX >= eX - 1 && bY <= eY + 1 && bY >= eY - 1)
- {
- return true;
- }
- if (bY == eY && ((bX - 2 == eX && board.at(0, eY).getMoves() == 0) || (bX + 2 == eX && board.at(7, eY).getMoves() == 0)) && piece.getMoves() == 0 && eY == 7)
- {
- return true;
- }
- return false;
- }
- return false;
- }
- /* This function checks whether or not a piece is blocked by other pieces
- * while it tries to move to a location that is otherwise "in range"
- */
- public static boolean pathClear(ChessBoard board, ChessPiece piece, int bX, int bY, int eX, int eY)
- {
- switch (piece.getType().toString)
- {
- case "PAWN":
- if (bX == eX && board.at(eX, eY).getType() != CPiece.Type.BLANK)
- {
- return false;
- }
- if (bX == eX && bY - 2 == eY && board.at(eX, eY + 1).getType() != CPiece.Type.BLANK)
- {
- return false;
- }
- return true;
- case "ROOK":
- if (bX == eX)
- {
- if (bY < eY)
- {
- for (int i = bY + 1; i <= eY; ++i)
- {
- if ((board.at(eX, i).getType() != CPiece.Type.BLANK && i != eY) || board.at(eX, i).getColor() == piece.getColor())
- {
- return false;
- }
- }
- }
- else
- {
- for (int i = bY - 1; i >= eY; --i)
- {
- if ((board.at(eX, i).getType() != CPiece.Type.BLANK && i != eY) || board.at(eX, i).getColor() == piece.getColor())
- {
- return false;
- }
- }
- }
- }
- else
- {
- if (bX < eX)
- {
- for (int i = bX + 1; i <= eX; ++i)
- {
- if ((board.at(i, eY).getType() != CPiece.Type.BLANK && i != eX) || board.at(i, eY).getColor() == piece.getColor())
- {
- return false;
- }
- }
- }
- else
- {
- for (int i = bX - 1; i >= eX; --i)
- {
- if ((board.at(i, eY).getType() != CPiece.Type.BLANK && i != eX) || board.at(i, eY).getColor() == piece.getColor())
- {
- return false;
- }
- }
- }
- }
- return true;
- case "KNIGHT":
- if (board.at(eX, eY).getColor() == piece.getColor())
- {
- return false;
- }
- return true;
- case "BISHOP":
- if (bX < eX)
- {
- if (bY < eY)
- {
- for (int i = bX + 1, j = bY + 1; i <= eX && j <= eY; ++i, ++j)
- {
- if ((board.at(i, j).getType() != CPiece.Type.BLANK && i != eX && j != eY) || board.at(i, j).getColor() == piece.getColor())
- {
- return false;
- }
- }
- }
- else
- {
- for (int i = bX + 1, j = bY - 1; i <= eX && j >= eY; ++i, --j)
- {
- if ((board.at(i, j).getType() != CPiece.Type.BLANK && i != eX && j != eY) || board.at(i, j).getColor() == piece.getColor())
- {
- return false;
- }
- }
- }
- }
- else
- {
- if (bY < eY)
- {
- for (int i = bX - 1, j = bY + 1; i >= eX && j <= eY; --i, ++j)
- {
- if ((board.at(i, j).getType() != CPiece.Type.BLANK && i != eX && j != eY) || board.at(i, j).getColor() == piece.getColor())
- {
- return false;
- }
- }
- }
- else
- {
- for (int i = bX - 1, j = bY - 1; i >= eX && j >= eY; --i, --j)
- {
- if ((board.at(i, j).getType() != CPiece.Type.BLANK && i != eX && j != eY) || board.at(i, j).getColor() == piece.getColor())
- {
- return false;
- }
- }
- }
- }
- return true;
- case "QUEEN":
- if (bX == eX)
- {
- if (bY < eY)
- {
- for (int i = bY + 1; i <= eY; ++i)
- {
- if ((board.at(eX, i).getType() != CPiece.Type.BLANK && i != eY) || board.at(eX, i).getColor() == piece.getColor())
- {
- return false;
- }
- }
- }
- else
- {
- for (int i = bY - 1; i >= eY; --i)
- {
- if ((board.at(eX, i).getType() != CPiece.Type.BLANK && i != eY) || board.at(eX, i).getColor() == piece.getColor())
- {
- return false;
- }
- }
- }
- }
- else
- {
- if (bY == eY)
- {
- if (bX < eX)
- {
- for (int i = bX + 1; i <= eX; ++i)
- {
- if ((board.at(i, eY).getType() != CPiece.Type.BLANK && i != eX) || board.at(i, eY).getColor() == piece.getColor())
- {
- return false;
- }
- }
- }
- else
- {
- for (int i = bX - 1; i >= eX; --i)
- {
- if ((board.at(i, eY).getType() != CPiece.Type.BLANK && i != eX) || board.at(i, eY).getColor() == piece.getColor())
- {
- return false;
- }
- }
- }
- }
- }
- if (bX < eX)
- {
- if (bY < eY)
- {
- for (int i = bX + 1, j = bY + 1; i <= eX && j <= eY; ++i, ++j)
- {
- if ((board.at(i, j).getType() != CPiece.Type.BLANK && i != eX && j != eY) || board.at(i, j).getColor() == piece.getColor())
- {
- return false;
- }
- }
- }
- else
- {
- for (int i = bX + 1, j = bY - 1; i <= eX && j >= eY; ++i, --j)
- {
- if ((board.at(i, j).getType() != CPiece.Type.BLANK && i != eX && j != eY) || board.at(i, j).getColor() == piece.getColor())
- {
- return false;
- }
- }
- }
- }
- else
- {
- if (bY < eY)
- {
- for (int i = bX - 1, j = bY + 1; i >= eX && j <= eY; --i, ++j)
- {
- if ((board.at(i, j).getType() != CPiece.Type.BLANK && i != eX && j != eY) || board.at(i, j).getColor() == piece.getColor())
- {
- return false;
- }
- }
- }
- else
- {
- for (int i = bX - 1, j = bY - 1; i >= eX && j >= eY; --i, --j)
- {
- if ((board.at(i, j).getType() != CPiece.Type.BLANK && i != eX && j != eY) || board.at(i, j).getColor() == piece.getColor())
- {
- return false;
- }
- }
- }
- }
- return true;
- case "KING":
- if (board.at(eX, eY).getColor() == piece.getColor())
- {
- return false;
- }
- if (bX + 1 < eX || bX - 1 > eX)
- {
- if (bX > eX)
- {
- for (int i = bX - 1; i > 0; --i)
- {
- if (board.at(i, 7).getColor() != CLEAR)
- {
- return false;
- }
- }
- }
- if (bX < eX)
- {
- for (int i = bX + 1; i < 7; ++i)
- {
- if (board.at(i, 7).getColor() != CLEAR)
- {
- return false;
- }
- }
- }
- }
- return true;
- }
- return false;
- }
- /* This function checks whether or not a player will be in check if he makes
- * a certain move.
- */
- public static boolean putInCheck(ChessBoard board, int color, int bX, int bY, int eX, int eY)
- {
- int[] kingLoc = new int[2];
- int enemy;
- if (color == BLACK)
- {
- enemy = WHITE;
- }
- else
- {
- enemy = BLACK;
- }
- ChessPiece target;
- target = new ChessPiece(board.at(eX, eY));
- board.move(bX, bY, eX, eY, CHECK_MOVE);
- if (bX != eX || bY != eY)
- {
- board.at(eX, eY).decrementMoves();
- }
- board.flip();
- P4ChessBL.getKingLocation(board, color, kingLoc);
- for (int i = 0; i < 8; ++i)
- {
- for (int j = 0; j < 8; ++j)
- {
- if (board.at(i, j).getColor() == enemy && P4ChessBL.inRange(board, board.at(i, j), i, j, kingLoc[0], kingLoc[1]) && P4ChessBL.pathClear(board, board.at(i, j), i, j, kingLoc[0], kingLoc[1]))
- {
- board.flip();
- board.move(eX, eY, bX, bY, CHECK_MOVE);
- if (bX != eX || bY != eY)
- {
- board.at(bX, bY).decrementMoves();
- }
- board.replace(target, eX, eY);
- return true;
- }
- }
- }
- board.flip();
- board.move(eX, eY, bX, bY, CHECK_MOVE);
- if (bX != eX || bY != eY)
- {
- board.at(bX, bY).decrementMoves();
- }
- board.replace(target, eX, eY);
- return false;
- }
- /* This function overloads the previous, and calls the previous with the same
- * beginning and ending coordinates of the king. This determines if a player
- * is currently IN check.
- */
- public static boolean putInCheck(ChessBoard board, int color)
- {
- int[] kingLoc = new int[2];
- P4ChessBL.getKingLocation(board, color, kingLoc);
- return P4ChessBL.putInCheck(board, color, kingLoc[0], kingLoc[1], kingLoc[0], kingLoc[1]);
- }
- /* This function is used by the AI implementation to decide if a certain piece
- * at a location is at risk of being lost to the opponent.
- */
- public static boolean inJeopardy(ChessBoard board, int color, int bX, int bY, int eX, int eY)
- {
- int enemy;
- if (color == BLACK)
- {
- enemy = WHITE;
- }
- else
- {
- enemy = BLACK;
- }
- ChessPiece target;
- target = new ChessPiece(board.at(eX, eY));
- board.move(bX, bY, eX, eY, CHECK_MOVE);
- if (bX != eX || bY != eY)
- {
- board.at(eX, eY).decrementMoves();
- }
- board.flip();
- for (int i = 0; i < 8; ++i)
- {
- for (int j = 0; j < 8; ++j)
- {
- if (board.at(i, j).getColor() == enemy && P4ChessBL.inRange(board, board.at(i, j), i, j, 7 - eX, 7 - eY) && P4ChessBL.pathClear(board, board.at(i, j), i, j, 7 - eX, 7 - eY))
- {
- board.flip();
- board.move(eX, eY, bX, bY, CHECK_MOVE);
- if (bX != eX || bY != eY)
- {
- board.at(bX, bY).decrementMoves();
- }
- board.replace(target, eX, eY);
- return true;
- }
- }
- }
- board.flip();
- board.move(eX, eY, bX, bY, CHECK_MOVE);
- if (bX != eX || bY != eY)
- {
- board.at(bX, bY).decrementMoves();
- }
- board.replace(target, eX, eY);
- return false;
- }
- /* This function returns true if a player cannot move any pieces without
- * putting himself in check.
- */
- public static boolean isStalemate(ChessBoard board, int color)
- {
- for (int i = 0; i < 8; ++i)
- {
- for (int j = 0; j < 8; ++j)
- {
- if (board.at(i, j).getColor() == color)
- {
- for (int k = 0; k < 8; ++k)
- {
- for (int m = 0; m < 8; ++m)
- {
- if (P4ChessBL.inRange(board, board.at(i, j), i, j, k, m) && P4ChessBL.pathClear(board, board.at(i, j), i, j, k, m) && !P4ChessBL.putInCheck(board, color, i, j, k, m))
- {
- return false;
- }
- }
- }
- }
- }
- }
- return true;
- }
- /* This function checks if the player is IN check, and uses the stalemate
- * function to determine whether or not there is a way out of it. If there
- * is no way out, it is a check mate.
- */
- public static boolean isCheckMate(ChessBoard board, int color)
- {
- return P4ChessBL.putInCheck(board, color) && P4ChessBL.isStalemate(board, color);
- }
- /* This function finds a player's king piece and fills the array "loc" with
- * its location
- */
- public static void getKingLocation(ChessBoard board, int color, int[] loc)
- {
- for (int i = 0; i < 8; ++i)
- {
- for (int j = 0; j < 8; ++j)
- {
- if (board.at(i, j).getType() == CPiece.Type.KING && board.at(i, j).getColor() == color)
- {
- loc[0] = i;
- loc[1] = j;
- }
- }
- }
- }
- /* Returns true if the game is a draw by way of insufficient pieces.
- */
- public static boolean isDraw(ChessBoard board)
- {
- if (isInsufficientPieces(board))
- {
- System.out.print("Insufficient pieces to win game.");
- System.out.print("\n");
- return true;
- }
- return false;
- }
- /* This function is used to determine if the players both have bishops on the
- * same colored square. It is used to determine if there are sufficient
- * pieces to accomplish a check mate. 2 kings and 2 bishops of the same color
- * square do not allow check mate.
- */
- public static boolean sameSquareColorBishops(ChessBoard board)
- {
- int xpos = -1;
- int ypos;
- for (int i = 0; i < 8; ++i)
- {
- for (int j = 0; j < 8; ++j)
- {
- if (board.at(i, j).getType() == CPiece.Type.BISHOP)
- {
- if (xpos == -1)
- {
- xpos = i;
- ypos = j;
- }
- else
- {
- if ((i % 2 == j % 2 && xpos % 2 == ypos % 2) || (i % 2 != j % 2 && xpos % 2 != ypos % 2))
- {
- return true;
- }
- }
- }
- }
- }
- return false;
- }
- /* Here is the artificial intelligence function for the computer to make moves
- */
- public void computerMove(ChessBoard boardIn, int color)
- {
- java.util.ArrayList<Arrays.std_pair<Coord, Coord>> choices = new java.util.ArrayList<Arrays.std_pair<Coord, Coord>>(); // this vector stores possible moves
- java.util.ArrayList<Arrays.std_pair<Coord, Coord>> appealing = new java.util.ArrayList<Arrays.std_pair<Coord, Coord>>(); // this vector stores the most appealing moves to make
- Arrays.std_pair<Coord, Coord> movement = new Arrays.std_pair<Coord, Coord>();
- Coord coord = new Coord();
- ChessPiece piece;
- ChessBoard board = new ChessBoard(boardIn); // we make a copy of the passed-in board to manipulate for evaluation
- int appeal; // this variable is used to record the appeal of a possible move
- int maxAppeal = -10; // the max appeal variable will represent the most appealing move strength
- int checks = 0;
- int lastbX;
- int lastbY;
- int lasteX;
- int lasteY;
- boolean firstPass = true; // the computer will make an invisible "hypthetical" move on the
- do // ^-- first pass, then see if it can come up with an appealing move to
- { // follow with, it is only looking 1 move ahead.
- for (int i = 0; i < 8; ++i) // on each pass, the computer looks at all possible moves it could make on
- {
- for (int j = 0; j < 8; ++j) // the board, and then tries to judge the best choices to randomly use
- {
- if (board.at(i, j).getColor() == color) // we're scanning the whole board, this checks if we can even move from here
- {
- coord.m_X = i;
- coord.m_Y = j;
- piece = new ChessPiece(board.at(i, j)); // we're making a copy of the piece at the location for properties
- movement.first = coord;
- for (int k = 0; k < 8; ++k) // these are the loops to handle potential target coordinates for the
- {
- for (int m = 0; m < 8; ++m) // next move to make
- {
- if (k == i && m == j) // if we're looking at moving to the same spot we're at, we just go
- continue; // on to the next evalutation
- appeal = 0;
- if (P4ChessBL.inRange(board, piece, i, j, k, m) && P4ChessBL.pathClear(board, piece, i, j, k, m)) // here we check if a certain move is valid...
- {
- if (piece.getType().equals(CPiece.Type.KING) && P4ChessBL.putInCheck(board, piece.getColor()) && j == m && (i - 2 == k || i + 2 == k))
- {
- ; // we check if a castle is possible based on if we're in check, if in check
- }
- else // ^-- we do nothing with a castle move
- {
- if (piece.getType().equals(CPiece.Type.KING) && j == m && (i - 2 == k || i + 2 == k) && ((i - 2 == k && P4ChessBL.putInCheck(board, piece.getColor(), i, j, i - 1, m)) || (i + 2 == k && P4ChessBL.putInCheck(board, piece.getColor(), i, j, i + 1, m))))
- {
- ; // ^-- we do nothing with a castle move if trying to move through check - we check if a castle is possible based on if we'll move THROUGH check
- }
- else
- {
- if (!P4ChessBL.putInCheck(board, piece.getColor(), i, j, k, m)) // we've determined that was could make this move, now we see if we should
- {
- if (firstPass && P4ChessBL.inJeopardy(board, piece.getColor(), i, j, i, j) && !P4ChessBL.inJeopardy(board, piece.getColor(), i, j, k, m)) // we're checking if moves will put the computer in jeopardy afterwards
- {
- appeal += 10 * piece.getType(); // we're grading moves based on what we will accomplish by moving there
- }
- appeal += 10 * board.at(k, m).getType();
- if (board.at(i, j).getType().equals(CPiece.Type.PAWN) && m == 0)
- {
- appeal += 10 * CPiece.Type.QUEEN.getValue(); // appeal scores are greater for higher ranking pieces in the piece enum
- }
- if ((!firstPass && P4ChessBL.inJeopardy(board, piece.getColor(), i, j, i, j)) || P4ChessBL.inJeopardy(board, piece.getColor(), i, j, k, m))
- {
- appeal -= 10 * piece.getType();
- if (piece.getType().equals(CPiece.Type.QUEEN))
- {
- appeal -= 20;
- }
- }
- else
- {
- if (firstPass)
- {
- appeal += 10;
- }
- }
- coord.m_X = k;
- coord.m_Y = m;
- movement.second = coord;
- if (firstPass)
- {
- choices.add(movement); // this potential movement is now considered a "choice" for appeal checks
- }
- if (appeal > maxAppeal) // if we've found a move that is most appealing over previous judgements,
- { // ^-- we clear the appealing vector and add new "more appealing" choices
- maxAppeal = appeal;
- appealing.clear();
- }
- if (appeal == maxAppeal) // if the appeal of the current potential move matches the highest appeal
- { // found, we're going to add it to the appeal vector
- if (firstPass)
- {
- movement.second.m_X = k;
- movement.second.m_Y = m;
- }
- else
- {
- movement.first.m_X = lastbX;
- movement.first.m_Y = lastbY;
- movement.second.m_X = lasteX;
- movement.second.m_Y = lasteY;
- }
- appealing.add(movement); // we only push appealing moves onto the appropriate vector on 2nd pass
- }
- }
- }
- }
- }
- }
- }
- if (piece != null)
- piece.dispose();
- }
- }
- }
- firstPass = false; // we've looped over the board once, now we can perform 2nd pass operations
- if (checks < choices.size())
- {
- board.copyFrom(boardIn);
- lastbX = choices.get(checks).first.m_X;
- lastbY = choices.get(checks).first.m_Y;
- lasteX = choices.get(checks).second.m_X;
- lasteY = choices.get(checks).second.m_Y;
- board.move(lastbX, lastbY, lasteX, lasteY, CHECK_MOVE); // here's a call the the ChessBoard move function for a "test move"
- } // this sets up a hypothetical new board situation to further evaluate
- ++checks;
- } while (checks < choices.size());
- if (appealing.size() == 0)
- {
- appealing = new java.util.ArrayList<Arrays.std_pair<Coord, Coord>>(choices);
- }
- if (appealing.size() != 0) // once we have looked over the board, it's time to make a move
- {
- int z;
- z = RandomNumbers.nextNumber() % (appealing.size());
- boardIn.move(appealing.get(z).first.m_X, appealing.get(z).first.m_Y, appealing.get(z).second.m_X, appealing.get(z).second.m_Y, REAL_MOVE); // calling ChessBoard move function with a real move, not hypothetical
- System.out.print("\nComputer Move: ");
- System.out.print((byte)(104 - appealing.get(z).first.m_X));
- System.out.print((byte)(49 + appealing.get(z).first.m_Y));
- System.out.print(" to ");
- System.out.print((byte)(104 - appealing.get(z).second.m_X));
- System.out.print((byte)(49 + appealing.get(z).second.m_Y));
- System.out.print("\n");
- piece = new ChessPiece(board.at(appealing.get(z).first.m_X, appealing.get(z).first.m_Y));
- if (piece.getType().equals(CPiece.Type.KING) && appealing.get(z).first.m_Y == appealing.get(z).second.m_Y && (appealing.get(z).first.m_X - 2 == appealing.get(z).second.m_X || appealing.get(z).first.m_X + 2 == appealing.get(z).second.m_X))
- {
- if (appealing.get(z).first.m_X > appealing.get(z).second.m_X)
- {
- board.move(0, 7, 2 + piece.getColor(), 7);
- }
- else
- {
- board.move(7, 7, 4 + piece.getColor(), 7);
- }
- }
- if (piece != null)
- piece.dispose();
- }
- }
- /* This function just returns an all-caps representation of an input string
- */
- public static String allCaps(String str)
- {
- return str.toUpperCase();
- }
- /* This function gives a quick introduction to the game instructions.
- */
- public static void displayHelp()
- {
- System.out.print("\nThis is a simple game of Chess. You make moves by entering " + "piece coordinates\nin the format: \"a2 a4\", where a2 represents the " + "beginning coordinate of a piece\nand a4 represents the desired placement. " + "Normal chess rules apply.\nEnter 'Q' by itself to quit the game.");
- System.out.print("\n");
- }
- /* Program entry point. We just seed the random number generator and call the
- * game play function which will loop over our game.
- */
- public static void Main()
- {
- RandomNumbers.seed((time(0)));
- P4ChessBL.play();
- return;
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement