├── src ├── Color.java ├── Game.java ├── Knight.java ├── Game_Test.java ├── Rook.java ├── Bishop.java ├── Queen.java ├── Pawn.java ├── Piece.java ├── King.java └── Board.java ├── .gitignore ├── tests ├── game3.text ├── game2.text ├── game.text └── game4.text ├── pics ├── Chess1.png ├── Chess2.png └── Chess3.png ├── .vscode └── settings.json ├── README.md └── LICENSE /src/Color.java: -------------------------------------------------------------------------------- 1 | 2 | public enum Color {WHITE,BLACK} 3 | 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.class 2 | .classpath 3 | .project 4 | .vscode 5 | 6 | -------------------------------------------------------------------------------- /tests/game3.text: -------------------------------------------------------------------------------- 1 | pawnF f3 2 | pawnE e5 3 | pawnG g4 4 | queen h4 -------------------------------------------------------------------------------- /pics/Chess1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bglaws/Chess/HEAD/pics/Chess1.png -------------------------------------------------------------------------------- /pics/Chess2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bglaws/Chess/HEAD/pics/Chess2.png -------------------------------------------------------------------------------- /pics/Chess3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bglaws/Chess/HEAD/pics/Chess3.png -------------------------------------------------------------------------------- /tests/game2.text: -------------------------------------------------------------------------------- 1 | pawnE e4 2 | pawnE e5 3 | queen h5 4 | knightQ c6 5 | bishopK c4 6 | pawnD d6 7 | queen f7 8 | king f7 -------------------------------------------------------------------------------- /tests/game.text: -------------------------------------------------------------------------------- 1 | pawnD d4 2 | pawnD d5 3 | knightQ a3 4 | knightQ a6 5 | bishopQ f4 6 | bishopQ f5 7 | queen d3 8 | queen d6 9 | castle Q 10 | castle Q 11 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "files.exclude": { 3 | "**/.classpath": true, 4 | "**/.project": true, 5 | "**/.settings": true, 6 | "**/.factorypath": true 7 | } 8 | } -------------------------------------------------------------------------------- /tests/game4.text: -------------------------------------------------------------------------------- 1 | pawnE e3 2 | pawnA a5 3 | queen h5 4 | rookQ a6 5 | queen a5 6 | pawnH h5 7 | pawnH h4 8 | rookQ h6 9 | queen c7 10 | pawnF f6 11 | queen d7 12 | king f7 13 | queen b7 14 | queen d3 15 | queen b8 16 | queen h7 17 | queen c8 18 | king g6 19 | queen e6 -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Terminal chess program written in Java 2 | This is a terminal chess game I made to better understand object oriented programming. 3 | 4 | 5 | This program is a local two player chess game with only a few features left out: 6 | Firstly, instead of having the option to promote pawns to any piece, pawns auto-promote to a queen. 7 | Secondly, *en passant* has not yet been integrated. 8 | Thirdly, I omitted a few of the less common stalemate rules including, threefold repetiton, fifty-move rule. 9 | 10 | If you are using a terminal with a dark background the color of the pieces will appear to be flipped. 11 | Make sure your terminal is displaying UTF-8 properly, otherwise the chess pieces will print as ? 12 | 13 | 14 | ## How to build and run 15 | ```sh 16 | $ git clone https://github.com/Bglaws/Chess 17 | $ cd Chess/src 18 | $ javac Game.java 19 | $ java Game 20 | ``` 21 | 22 | ### Pictures 23 | ![Overview](pics/Chess1.png) 24 | 25 | ![Overview](pics/Chess2.png) 26 | 27 | ![Overview](pics/Chess3.png) 28 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Bglaws 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/Game.java: -------------------------------------------------------------------------------- 1 | 2 | import java.util.Scanner; 3 | 4 | public class Game { 5 | 6 | // TODO en passant 7 | public static void main(String[] args) { 8 | Scanner moveChoice = new Scanner(System.in); 9 | 10 | while (true) { 11 | Board.startGame(); 12 | 13 | int turns = 0; 14 | Color color; 15 | 16 | while (true) { 17 | Board.printBoard(); 18 | // check for check 19 | if (turns % 2 == 0) { 20 | color = Color.WHITE; 21 | } else 22 | color = Color.BLACK; 23 | 24 | if (Board.staleMate(color) == true) { 25 | System.out.println("game over, stalemate"); 26 | break; 27 | } 28 | if (Board.checkForCheck(color) == true) { 29 | if (Board.mate(color) == true) { 30 | 31 | System.out.printf("Checkmate, %s wins \n", color == Color.WHITE ? "Black" : "White"); 32 | break; 33 | } 34 | System.out.printf("%s is in Check! \n", color == Color.WHITE ? "White" : "Black"); 35 | } 36 | 37 | // move choice 38 | System.out.printf("%s's turn \n", color == Color.WHITE ? "White" : "Black"); 39 | 40 | String move = moveChoice.nextLine(); 41 | // process move 42 | if (Board.processMove(move, color) == 0) { 43 | turns++; 44 | } else { 45 | System.out.println("illegal move"); 46 | } 47 | 48 | } 49 | System.out.println("would you like to play again? y/n"); 50 | if (moveChoice.next().equals("y")) { 51 | continue; 52 | } else 53 | System.exit(0); 54 | } 55 | } 56 | 57 | } 58 | -------------------------------------------------------------------------------- /src/Knight.java: -------------------------------------------------------------------------------- 1 | 2 | public class Knight extends Piece { 3 | 4 | public Knight(Color color, String ID, int startX, int startY) { 5 | super(color, ID, startX, startY); 6 | } 7 | 8 | @Override 9 | public boolean possibleMove(int x, int y) { 10 | // cannot capture own piece 11 | if (this.sameColor(Board.getPiece(x, y)) == true) { 12 | return false; 13 | } 14 | 15 | if (Math.abs(this.getY() - y) == 2 && Math.abs(this.getX() - x) == 1 16 | || Math.abs(this.getY() - y) == 1 && Math.abs(this.getX() - x) == 2) { 17 | return true; 18 | } 19 | 20 | return false; 21 | } 22 | 23 | @Override 24 | public String toString() { 25 | if (this.getColor() == Color.WHITE) { 26 | return "♘"; 27 | } 28 | return "♞"; 29 | } 30 | 31 | @Override 32 | public boolean canMove() { 33 | 34 | int x = this.getX(); 35 | int y = this.getY(); 36 | 37 | // left & up 38 | if (this.testMove(x - 2, y - 1)) { 39 | return true; 40 | } 41 | if (this.testMove(x - 1, y - 2)) { 42 | return true; 43 | } 44 | 45 | // right & up 46 | if (this.testMove(x + 2, y - 1)) { 47 | return true; 48 | } 49 | if (this.testMove(x + 1, y - 2)) { 50 | return true; 51 | } 52 | 53 | // left & down 54 | if (this.testMove(x - 2, y + 1)) { 55 | return true; 56 | } 57 | if (this.testMove(x - 1, y + 2)) { 58 | return true; 59 | } 60 | 61 | // right & down 62 | if (this.testMove(x + 2, y + 1)) { 63 | return true; 64 | } 65 | if (this.testMove(x + 1, y + 2)) { 66 | return true; 67 | } 68 | 69 | return false; 70 | } 71 | 72 | } 73 | -------------------------------------------------------------------------------- /src/Game_Test.java: -------------------------------------------------------------------------------- 1 | import java.io.File; 2 | import java.io.FileNotFoundException; 3 | import java.util.Scanner; 4 | 5 | public class Game_Test { 6 | 7 | public static void main(String[] args) throws FileNotFoundException { 8 | Scanner moveChoice = new Scanner(new File("./tests/game2.text")); 9 | 10 | while (true) { 11 | Board.startGame(); 12 | 13 | int turns = 0; 14 | Color color; 15 | 16 | while (true/* while checkMate = false */) { 17 | Board.printBoard(); 18 | // check for check 19 | if (turns % 2 == 0) { 20 | color = Color.WHITE; 21 | } else 22 | color = Color.BLACK; 23 | 24 | if (Board.staleMate(color) == true) { 25 | System.out.println("game over, stalemate"); 26 | break; 27 | } 28 | if (Board.checkForCheck(color) == true) { 29 | if (Board.mate(color) == true) { 30 | 31 | System.out.printf("Checkmate, %s wins \n", color == Color.WHITE ? "Black" : "White"); 32 | break; 33 | } 34 | System.out.printf("%s is in Check! \n", color == Color.WHITE ? "White" : "Black"); 35 | } 36 | 37 | // move choice 38 | System.out.printf("%s's turn \n", color == Color.WHITE ? "White" : "Black"); 39 | 40 | String move = moveChoice.nextLine(); 41 | System.out.println(move); 42 | // process move 43 | if (Board.processMove(move, color) == 0) { 44 | turns++; 45 | } else { 46 | System.out.println("illegal move"); 47 | } 48 | 49 | } 50 | System.out.println("would you like to play again? y/n"); 51 | if (moveChoice.next().equals("y")) { 52 | continue; 53 | } else 54 | System.exit(0); 55 | } 56 | } 57 | 58 | } 59 | -------------------------------------------------------------------------------- /src/Rook.java: -------------------------------------------------------------------------------- 1 | 2 | public class Rook extends Piece { 3 | 4 | public Rook(Color color, String ID, int startX, int startY) { 5 | super(color, ID, startX, startY); 6 | } 7 | 8 | boolean isFirstMove = true; 9 | 10 | 11 | @Override 12 | public boolean possibleMove(int x, int y) { 13 | // cannot capture own piece 14 | if (this.sameColor(Board.getPiece(x, y)) == true) { 15 | return false; 16 | } 17 | // invalid move for rook 18 | if (Math.abs(getX() - x) != 0 && Math.abs(getY() - y) != 0) { 19 | return false; 20 | } 21 | 22 | if (Board.isPathClear(getX(), getY(), x, y)) { 23 | return true; 24 | } 25 | return false; 26 | } 27 | 28 | @Override 29 | public String toString() { 30 | if (this.getColor() == Color.WHITE) { 31 | return "♖"; 32 | } 33 | return "♜"; 34 | } 35 | 36 | @Override 37 | public boolean canMove() { 38 | int x = this.getX(); 39 | int y = this.getY(); 40 | 41 | // left 42 | while ((--x) >= 0 && y >= 0) { 43 | if (this.testMove(x, y)) { 44 | return true; 45 | } 46 | } 47 | x = this.getX(); 48 | y = this.getY(); 49 | // right 50 | while ((++x) <= 7 && y >= 0) { 51 | if (this.testMove(x, y)) { 52 | return true; 53 | } 54 | } 55 | x = this.getX(); 56 | y = this.getY(); 57 | // down 58 | while (x >= 0 && (++y) <= 7) { 59 | if (this.testMove(x, y)) { 60 | return true; 61 | } 62 | } 63 | x = this.getX(); 64 | y = this.getY(); 65 | // up 66 | while (x <= 7 && (--y) >= 0) { 67 | if (this.testMove(x, y)) { 68 | return true; 69 | } 70 | } 71 | 72 | return false; 73 | } 74 | 75 | } 76 | -------------------------------------------------------------------------------- /src/Bishop.java: -------------------------------------------------------------------------------- 1 | 2 | public class Bishop extends Piece { 3 | 4 | public Bishop(Color color, String ID, int startX, int startY) { 5 | super(color, ID, startX, startY); 6 | } 7 | 8 | @Override 9 | public boolean possibleMove(int x, int y) { 10 | // cannot capture own piece 11 | if (this.sameColor(Board.getPiece(x, y)) == true) { 12 | return false; 13 | } 14 | // invalid move for bishop 15 | if (Math.abs(getX() - x) != Math.abs(getY() - y)) { 16 | return false; 17 | } 18 | 19 | if (Board.isPathClear(getX(), getY(), x, y)) { 20 | return true; 21 | } 22 | return false; 23 | } 24 | 25 | @Override 26 | public String toString() { 27 | if (this.getColor() == Color.WHITE) { 28 | return "♗"; 29 | } 30 | return "♝"; 31 | } 32 | 33 | @Override 34 | public boolean canMove() { 35 | 36 | int originX = this.getX(); 37 | int originY = this.getY(); 38 | 39 | // reset x and y to original position after each while loop 40 | int x = originX; 41 | int y = originY; 42 | 43 | // top left 44 | while ((--x) >= 0 && (--y) >= 0) { 45 | if (this.testMove(x, y)) { 46 | return true; 47 | } 48 | } 49 | x = originX; 50 | y = originY; 51 | // top right 52 | while ((++x) <= 7 && (--y) >= 0) { 53 | if (this.testMove(x, y)) { 54 | return true; 55 | } 56 | } 57 | x = originX; 58 | y = originY; 59 | // bottom left 60 | while ((--x) >= 0 && (++y) <= 7) { 61 | if (this.testMove(x, y)) { 62 | return true; 63 | } 64 | } 65 | x = originX; 66 | y = originY; 67 | // bottom right 68 | while ((++x) <= 7 && (++y) <= 7) { 69 | if (this.testMove(x, y)) { 70 | return true; 71 | } 72 | } 73 | return false; 74 | } 75 | 76 | } 77 | -------------------------------------------------------------------------------- /src/Queen.java: -------------------------------------------------------------------------------- 1 | 2 | public class Queen extends Piece { 3 | 4 | public Queen(Color color, String ID, int startX, int startY) { 5 | super(color, ID, startX, startY); 6 | } 7 | 8 | @Override 9 | public boolean possibleMove(int x, int y) { 10 | // cannot capture own piece 11 | if (this.sameColor(Board.getPiece(x, y)) == true) { 12 | return false; 13 | } 14 | // obstruction 15 | if (Board.isPathClear(getX(), getY(), x, y) != true) { 16 | return false; 17 | } 18 | // bishop 19 | if (Math.abs(getX() - x) == Math.abs(getY() - y)) { // bishop 20 | return true; 21 | } 22 | // rook 23 | if (Math.abs(getX() - x) != 0 && Math.abs(getY() - y) == 0 24 | || Math.abs(getX() - x) == 0 && Math.abs(getY() - y) != 0) { 25 | return true; 26 | } 27 | return false; 28 | } 29 | 30 | @Override 31 | public String toString() { 32 | if (this.getColor() == Color.WHITE) { 33 | return "♕"; 34 | } 35 | return "♛"; 36 | } 37 | 38 | @Override 39 | public boolean canMove() { 40 | 41 | int x = this.getX(); 42 | int y = this.getY(); 43 | 44 | // bishop 45 | // top left 46 | while ((--x) >= 0 && (--y) >= 0) { 47 | if (this.testMove(x, y)) { 48 | return true; 49 | } 50 | } 51 | 52 | x = this.getX(); 53 | y = this.getY(); 54 | // top right 55 | while ((++x) <= 7 && (--y) >= 0) { 56 | if (this.testMove(x, y)) { 57 | return true; 58 | } 59 | } 60 | 61 | x = this.getX(); 62 | y = this.getY(); 63 | // bottom left 64 | while ((--x) >= 0 && (++y) <= 7) { 65 | if (this.testMove(x, y)) { 66 | return true; 67 | } 68 | } 69 | 70 | x = this.getX(); 71 | y = this.getY(); 72 | // bottom right 73 | while ((++x) <= 7 && (++y) <= 7) { 74 | if (this.testMove(x, y)) { 75 | return true; 76 | } 77 | } 78 | 79 | x = this.getX(); 80 | y = this.getY(); 81 | // rook 82 | // left 83 | while ((--x) >= 0 && y >= 0) { 84 | if (this.testMove(x, y)) { 85 | return true; 86 | } 87 | } 88 | 89 | x = this.getX(); 90 | y = this.getY(); 91 | // right 92 | while ((++x) <= 7 && y >= 0) { 93 | if (this.testMove(x, y)) { 94 | return true; 95 | } 96 | } 97 | 98 | x = this.getX(); 99 | y = this.getY(); 100 | // down 101 | while (x >= 0 && (++y) <= 7) { 102 | if (this.testMove(x, y)) { 103 | return true; 104 | } 105 | } 106 | 107 | x = this.getX(); 108 | y = this.getY(); 109 | // up 110 | while (x <= 7 && (--y) >= 0) { 111 | if (this.testMove(x, y)) { 112 | return true; 113 | } 114 | } 115 | return false; 116 | } 117 | 118 | } 119 | -------------------------------------------------------------------------------- /src/Pawn.java: -------------------------------------------------------------------------------- 1 | 2 | public class Pawn extends Piece { 3 | 4 | public Pawn(Color color, String ID, int startX, int startY) { 5 | super(color, ID, startX, startY); 6 | } 7 | 8 | boolean isFirstMove = true; 9 | 10 | @Override 11 | public boolean possibleMove(int x, int y) { 12 | // TODO en passant 13 | 14 | if (this.getColor() == Color.WHITE) { 15 | 16 | // 2 spaces forward 17 | if (this.isFirstMove == true && this.getY() - y == 2 && this.getX() - x == 0 18 | && Board.isPathClear(getX(), getY(), x, y) && Board.getPiece(x, y) == null) { 19 | return true; 20 | } 21 | // 1 space forward 22 | if (this.getY() - y == 1 && this.getX() - x == 0 && Board.getPiece(x, y) == null) { 23 | return true; 24 | } 25 | 26 | // diagonal 27 | if (this.getY() - y == 1 && Math.abs(this.getX() - x) == 1 && Board.getPiece(x, y) != null 28 | && this.sameColor(Board.getPiece(x, y)) == false) { 29 | return true; 30 | } 31 | } 32 | 33 | if (this.getColor() == Color.BLACK) { 34 | // 2 spaces forward 35 | if (this.isFirstMove == true && this.getY() - y == -2 && this.getX() - x == 0 36 | && Board.isPathClear(getX(), getY(), x, y) && Board.getPiece(x, y) == null) { 37 | return true; 38 | } 39 | // 1 space forward 40 | if (this.getY() - y == -1 && this.getX() - x == 0 && Board.getPiece(x, y) == null) { 41 | return true; 42 | } 43 | 44 | // diagonal 45 | if (this.getY() - y == -1 && Math.abs(this.getX() - x) == 1 && Board.getPiece(x, y) != null 46 | && this.sameColor(Board.getPiece(x, y)) == false) { 47 | return true; 48 | } 49 | } 50 | return false; 51 | } 52 | 53 | @Override 54 | public String toString() { 55 | if (this.getColor() == Color.WHITE) { 56 | return "♙"; 57 | } 58 | return "♟"; 59 | } 60 | 61 | @Override 62 | public boolean canMove() { 63 | int x = this.getX(); 64 | int y = this.getY(); 65 | 66 | if (this.getColor() == Color.WHITE) { 67 | 68 | if (this.testMove(x, y - 1)) { 69 | return true; 70 | } 71 | 72 | if (this.testMove(x, y - 2)) { 73 | return true; 74 | } 75 | 76 | if (this.testMove(x - 1, y - 1)) { 77 | return true; 78 | } 79 | 80 | if (this.testMove(x + 1, y - 1)) { 81 | return true; 82 | } 83 | 84 | } 85 | if (this.getColor() == Color.BLACK) { 86 | 87 | if (this.testMove(x, y + 1)) { 88 | return true; 89 | } 90 | 91 | if (this.testMove(x, y + 2)) { 92 | return true; 93 | } 94 | 95 | if (this.testMove(x - 1, y - 1)) { 96 | return true; 97 | } 98 | 99 | if (this.testMove(x + 1, y + 1)) { 100 | return true; 101 | } 102 | } 103 | 104 | return false; 105 | } 106 | 107 | } 108 | -------------------------------------------------------------------------------- /src/Piece.java: -------------------------------------------------------------------------------- 1 | 2 | public abstract class Piece { 3 | 4 | private final Color color; 5 | 6 | private final String ID; 7 | 8 | private int x, y; 9 | 10 | public boolean isFirstMove; 11 | 12 | public Piece(Color color, String ID, int startX, int startY) { 13 | this.color = color; 14 | this.ID = ID; 15 | this.x = startX; 16 | this.y = startY; 17 | 18 | if (this.getColor() == Color.WHITE) { 19 | Board.white.add(this); 20 | } else if (this.getColor() == Color.BLACK) { 21 | Board.black.add(this); 22 | } 23 | Board.setPiece(x, y, this); 24 | } 25 | 26 | public String getID() { 27 | return this.ID; 28 | } 29 | 30 | public boolean matchID(String ID) { 31 | return this.ID.equals(ID); 32 | } 33 | 34 | public Color getColor() { 35 | return this.color; 36 | } 37 | 38 | public boolean sameColor(Piece otherPiece) { 39 | if (otherPiece == null) { 40 | return false; 41 | } 42 | return (this.color == otherPiece.getColor()); 43 | } 44 | 45 | public int getX() { 46 | return this.x; 47 | } 48 | 49 | void setX(int newX) { 50 | this.x = newX; 51 | } 52 | 53 | public int getY() { 54 | return this.y; 55 | } 56 | 57 | void setY(int newY) { 58 | this.y = newY; 59 | } 60 | 61 | public abstract boolean possibleMove(int x, int y); 62 | 63 | public int move(int x, int y, Piece other) { 64 | if (this.possibleMove(x, y) != true) { 65 | return -1; 66 | } 67 | 68 | Color color = this.getColor(); 69 | int originX = this.getX(); 70 | int originY = this.getY(); 71 | 72 | if (this.getColor() == Color.WHITE) { 73 | Board.black.remove(other); 74 | } else { 75 | Board.white.remove(other); 76 | } 77 | 78 | Board.setPiece(originX, originY, null); 79 | Board.setPiece(x, y, this); 80 | 81 | boolean isFirstMoveOG = this.isFirstMove; 82 | this.isFirstMove = false; 83 | 84 | if (Board.checkForCheck(color) == true) { 85 | if (other != null) { 86 | if (this.getColor() == Color.WHITE) { 87 | Board.black.add(other); 88 | } else { 89 | Board.white.add(other); 90 | } 91 | } 92 | Board.setPiece(originX, originY, this); 93 | Board.setPiece(x, y, other); 94 | this.isFirstMove = isFirstMoveOG; 95 | 96 | return -1; 97 | } 98 | 99 | if (this instanceof Pawn) { 100 | char file = this.getID().charAt(4); 101 | if (this.getColor() == Color.WHITE && y == 0) { 102 | Board.setPiece(x, y, null); 103 | Board.white.remove(this); 104 | Queen yasQueen = new Queen(Color.WHITE, "queen" + file, x, y); 105 | System.out.println("Pawn promoted!"); 106 | } else if (this.getColor() == Color.BLACK && y == 7) { 107 | Board.setPiece(x, y, null); 108 | Board.black.remove(this); 109 | Queen yasQueen = new Queen(Color.BLACK, "queen" + file, x, y); 110 | System.out.println("Pawn promoted!"); 111 | } 112 | } 113 | 114 | return 0; 115 | } 116 | 117 | public boolean testMove(int x, int y) { 118 | int originX = this.getX(); 119 | int originY = this.getY(); 120 | Piece other; 121 | boolean isFirst = this.isFirstMove; 122 | 123 | if (x >= 0 && y >= 0 && x <= 7 && y <= 7) { 124 | other = Board.getPiece(x, y); 125 | if (this.move(x, y, other) == 0) { 126 | // captured piece set to original position 127 | Board.setPiece(x, y, other); 128 | // selected piece set to original position 129 | Board.setPiece(originX, originY, this); 130 | isFirstMove = isFirst; 131 | if (other != null) { 132 | if (other.getColor() == Color.WHITE) { 133 | Board.white.add(other); 134 | } else 135 | Board.black.add(other); 136 | } 137 | return true; 138 | } 139 | } 140 | return false; 141 | } 142 | 143 | public String nullToString() { 144 | return " "; 145 | } 146 | 147 | public abstract String toString(); 148 | 149 | public abstract boolean canMove(); 150 | } 151 | -------------------------------------------------------------------------------- /src/King.java: -------------------------------------------------------------------------------- 1 | 2 | public class King extends Piece { 3 | 4 | public King(Color color, String ID, int startX, int startY) { 5 | super(color, ID, startX, startY); 6 | } 7 | 8 | boolean isFirstMove = true; 9 | 10 | @Override 11 | public boolean possibleMove(int x, int y) { 12 | // cannot capture own piece 13 | if (this.sameColor(Board.getPiece(x, y)) == true) { 14 | return false; 15 | } 16 | // bishop 17 | else if (Math.abs(getX() - x) == 1 && Math.abs(getY() - y) == 1) { 18 | return true; 19 | } 20 | // rook 21 | else if (Math.abs(getX() - x) == 1 && Math.abs(getY() - y) == 0 22 | || Math.abs(getX() - x) == 0 && Math.abs(getY() - y) == 1) { 23 | return true; 24 | } 25 | return false; 26 | } 27 | 28 | @Override 29 | public String toString() { 30 | if (this.getColor() == Color.WHITE) { 31 | return "♔"; 32 | } 33 | return "♚"; 34 | } 35 | 36 | public int castle(String side) { 37 | Rook rook = (Rook) Board.getPiece("rook" + side, this.getColor()); 38 | int originX = this.getX(); 39 | int originY = this.getY(); 40 | 41 | if (this.isFirstMove != true || rook.isFirstMove != true) { 42 | System.out.println("Cannot castle if king or rook has already moved"); 43 | return -1; 44 | } 45 | if (Board.isPathClear(this.getX(), this.getY(), rook.getX(), rook.getY()) != true) { 46 | System.out.println("Cannot castle across a line of check"); 47 | return -1; 48 | } 49 | 50 | if (this.getColor() == Color.WHITE) { 51 | 52 | if (side.equals("K")) { 53 | // cant castle accross a line of check 54 | if (this.move(5, 7, null) == 0 && this.move(6, 7, null) == 0) { 55 | Board.setPiece(rook.getX(), rook.getY(), null); 56 | Board.setPiece(5, 7, rook); 57 | return 0; 58 | } else { 59 | Board.setPiece(this.getX(), this.getY(), null); 60 | Board.setPiece(originX, originY, this); 61 | return -1; 62 | } 63 | } 64 | 65 | else if (side.equals("Q")) { 66 | if (this.move(3, 7, null) == 0 && this.move(2, 7, null) == 0) { 67 | Board.setPiece(rook.getX(), rook.getY(), null); 68 | Board.setPiece(3, 7, rook); 69 | return 0; 70 | } else { 71 | Board.setPiece(this.getX(), this.getY(), null); 72 | Board.setPiece(originX, originY, this); 73 | return -1; 74 | } 75 | } 76 | } 77 | 78 | if (this.getColor() == Color.BLACK) { 79 | if (side.equals("K")) { 80 | if (this.move(5, 0, null) == 0 && this.move(6, 0, null) == 0) { 81 | Board.setPiece(rook.getX(), rook.getY(), null); 82 | Board.setPiece(5, 0, rook); 83 | return 0; 84 | } else { 85 | Board.setPiece(this.getX(), this.getY(), null); 86 | Board.setPiece(originX, originY, this); 87 | return -1; 88 | } 89 | } 90 | 91 | else if (side.equals("Q")) { 92 | if (this.move(3, 0, null) == 0 && this.move(2, 0, null) == 0) { 93 | Board.setPiece(rook.getX(), rook.getY(), null); 94 | Board.setPiece(3, 0, rook); 95 | return 0; 96 | } else { 97 | Board.setPiece(this.getX(), this.getY(), null); 98 | Board.setPiece(originX, originY, this); 99 | return -1; 100 | } 101 | } 102 | } 103 | return -1; 104 | } 105 | 106 | @Override 107 | public boolean canMove() { 108 | int x = this.getX(); 109 | int y = this.getY(); 110 | 111 | // bishop 112 | // top left 113 | if (this.testMove(x - 1, y - 1)) { 114 | return true; 115 | } 116 | // top right 117 | if (this.testMove(x + 1, y - 1)) { 118 | return true; 119 | } 120 | // bottom left 121 | if (this.testMove(x - 1, y + 1)) { 122 | return true; 123 | } 124 | // bottom right 125 | if (this.testMove(x + 1, y + 1)) { 126 | return true; 127 | } 128 | 129 | // rook 130 | // left 131 | if (this.testMove(x - 1, y)) { 132 | return true; 133 | } 134 | // right 135 | if (this.testMove(x + 1, y)) { 136 | return true; 137 | } 138 | // down 139 | if (this.testMove(x, y + 1)) { 140 | return true; 141 | } 142 | // up 143 | if (this.testMove(x, y - 1)) { 144 | return true; 145 | } 146 | return false; 147 | } 148 | 149 | } 150 | -------------------------------------------------------------------------------- /src/Board.java: -------------------------------------------------------------------------------- 1 | import java.util.ArrayList; 2 | 3 | public class Board { 4 | public static ArrayList black = new ArrayList(); 5 | public static ArrayList white = new ArrayList(); 6 | 7 | static Piece board[][] = new Piece[8][8]; 8 | 9 | static void printBoard() { 10 | System.out.println(" a b c d e f g h"); 11 | 12 | System.out.println(" ---------------------------------"); 13 | int count = 8; 14 | for (int i = 0; i < 8; i++) { 15 | System.out.print(count + " "); 16 | System.out.print("| "); 17 | for (int j = 0; j < 8; j++) { 18 | if (board[i][j] == null) { 19 | System.out.print(" | "); 20 | } else { 21 | System.out.print(board[i][j] + " | "); 22 | } 23 | } 24 | System.out.print(count); 25 | count--; 26 | System.out.println(); 27 | System.out.println(" ---------------------------------"); 28 | } 29 | System.out.println(" a b c d e f g h"); 30 | System.out.println(); 31 | } 32 | 33 | static void startGame() { 34 | System.out.println("How to play:"); 35 | System.out.println("For pawns, type in \"pawn\" followed by the file letter. For example, \"pawnA\""); 36 | System.out.println("For bishops, knights and rooks, put \"Q\" or \"K\" to specify Queen's or King's side"); 37 | System.out.println("provide a space and then enter a valid tile. For example, \"bishopK c4\""); 38 | System.out.println( 39 | "Pawns auto-promote to queens. The new queens are referenced by what the pawns file was. \"queenH\""); 40 | System.out.println( 41 | "To castle, type castle, followed by a space and then a capital K or Q to specify a side. \"castle Q\"\n"); 42 | 43 | // black 44 | new Rook(Color.BLACK, "rookQ", 0, 0); 45 | new Knight(Color.BLACK, "knightQ", 1, 0); 46 | new Bishop(Color.BLACK, "bishopQ", 2, 0); 47 | new Queen(Color.BLACK, "queen", 3, 0); 48 | new King(Color.BLACK, "king", 4, 0); 49 | new Bishop(Color.BLACK, "bishopK", 5, 0); 50 | new Knight(Color.BLACK, "knightK", 6, 0); 51 | new Rook(Color.BLACK, "rookK", 7, 0); 52 | 53 | new Pawn(Color.BLACK, "pawnA", 0, 1); 54 | new Pawn(Color.BLACK, "pawnB", 1, 1); 55 | new Pawn(Color.BLACK, "pawnC", 2, 1); 56 | new Pawn(Color.BLACK, "pawnD", 3, 1); 57 | new Pawn(Color.BLACK, "pawnE", 4, 1); 58 | new Pawn(Color.BLACK, "pawnF", 5, 1); 59 | new Pawn(Color.BLACK, "pawnG", 6, 1); 60 | new Pawn(Color.BLACK, "pawnH", 7, 1); 61 | 62 | // white 63 | new Rook(Color.WHITE, "rookQ", 0, 7); 64 | new Knight(Color.WHITE, "knightQ", 1, 7); 65 | new Bishop(Color.WHITE, "bishopQ", 2, 7); 66 | new Queen(Color.WHITE, "queen", 3, 7); 67 | new King(Color.WHITE, "king", 4, 7); 68 | new Bishop(Color.WHITE, "bishopK", 5, 7); 69 | new Knight(Color.WHITE, "knightK", 6, 7); 70 | new Rook(Color.WHITE, "rookK", 7, 7); 71 | 72 | new Pawn(Color.WHITE, "pawnA", 0, 6); 73 | new Pawn(Color.WHITE, "pawnB", 1, 6); 74 | new Pawn(Color.WHITE, "pawnC", 2, 6); 75 | new Pawn(Color.WHITE, "pawnD", 3, 6); 76 | new Pawn(Color.WHITE, "pawnE", 4, 6); 77 | new Pawn(Color.WHITE, "pawnF", 5, 6); 78 | new Pawn(Color.WHITE, "pawnG", 6, 6); 79 | new Pawn(Color.WHITE, "pawnH", 7, 6); 80 | } 81 | 82 | // set piece to provided coordinates 83 | public static void setPiece(int x, int y, Piece piece) { 84 | if (piece != null) { 85 | piece.setX(x); 86 | piece.setY(y); 87 | } 88 | board[y][x] = piece; 89 | } 90 | 91 | // check spot on board 92 | public static Piece getPiece(int x, int y) { 93 | return board[y][x]; 94 | } 95 | 96 | // match String piece from user with Piece on board 97 | public static Piece getPiece(String piece, Color color) { 98 | 99 | if (color == Color.WHITE) { 100 | 101 | for (int i = 0; i < white.size(); i++) { 102 | Piece p = white.get(i); 103 | if (p.matchID(piece)) { 104 | return p; 105 | } 106 | } 107 | } 108 | 109 | else if (color == Color.BLACK) { 110 | 111 | for (int i = 0; i < black.size(); i++) { 112 | Piece p = black.get(i); 113 | if (p.matchID(piece)) { 114 | return p; 115 | } 116 | } 117 | } 118 | 119 | return null; 120 | 121 | } 122 | 123 | public static boolean isPathClear(int x1, int y1, int x2, int y2) { 124 | 125 | int xDistance = x2 - x1; 126 | int yDistance = y2 - y1; 127 | int xDir = 0; 128 | int yDir = 0; 129 | int size = 0; 130 | 131 | if (xDistance < 0) { 132 | xDir = -1; 133 | } else if (xDistance > 0) { 134 | xDir = 1; 135 | } 136 | 137 | if (yDistance < 0) { 138 | yDir = -1; 139 | } else if (yDistance > 0) { 140 | yDir = 1; 141 | } 142 | 143 | if (xDistance != 0) { 144 | size = Math.abs(xDistance) - 1; 145 | } else { 146 | size = Math.abs(yDistance) - 1; 147 | } 148 | // change on x and y 149 | 150 | for (int i = 0; i < size; i++) { 151 | x1 += xDir; 152 | y1 += yDir; 153 | 154 | if (getPiece(x1, y1) != null) { 155 | return false; 156 | } 157 | } 158 | return true; 159 | 160 | } 161 | 162 | static int processMove(String move, Color color) { 163 | 164 | String[] splitStr = move.split(" "); 165 | String piece = splitStr[0]; 166 | 167 | if (piece.equals("castle")) { 168 | King king = (King) getPiece("king", color); 169 | return king.castle(splitStr[1]); 170 | } 171 | 172 | // piece selected to move 173 | Piece p = getPiece(piece, color); 174 | if (p == null) { 175 | System.out.println("invalid piece, please type in piece to move it."); 176 | return -1; 177 | } 178 | 179 | String coordinates = splitStr[1]; 180 | if (coordinates.length() != 2) { 181 | System.out.println("Invalid Tile please try again"); 182 | return -1; 183 | } 184 | 185 | int file = coordinates.charAt(0) - 'a'; // y 186 | int rank = 7 - (coordinates.charAt(1) - '1'); // x 187 | 188 | if (rank < 0 || rank > 7 || file < 0 || file > 7) { 189 | System.out.println("Invalid Tile please try again"); 190 | return -1; 191 | } 192 | 193 | // piece at destination 194 | Piece other = getPiece(file, rank); 195 | 196 | return p.move(file, rank, other); 197 | 198 | } 199 | 200 | public static boolean checkForCheck(Color color) { 201 | 202 | Piece king = getPiece("king", color); 203 | 204 | if (color == Color.WHITE) { 205 | for (int i = 0; i < black.size(); i++) { 206 | Piece p = black.get(i); 207 | if (p.possibleMove(king.getX(), king.getY())) { 208 | return true; 209 | } 210 | } 211 | } 212 | 213 | else if (color == Color.BLACK) { 214 | for (int i = 0; i < white.size(); i++) { 215 | Piece p = white.get(i); 216 | if (p.possibleMove(king.getX(), king.getY())) { 217 | return true; 218 | } 219 | } 220 | } 221 | 222 | return false; 223 | } 224 | 225 | public static boolean mate(Color color) { 226 | 227 | if (color == Color.WHITE) { 228 | for (int i = 0; i < white.size(); i++) { 229 | Piece p = white.get(i); 230 | if (p.canMove()) { 231 | return false; 232 | } 233 | } 234 | } else if (color == Color.BLACK) { 235 | for (int i = 0; i < black.size(); i++) { 236 | Piece p = black.get(i); 237 | if (p.canMove()) { 238 | return false; 239 | } 240 | } 241 | } 242 | 243 | return true; 244 | } 245 | 246 | public static boolean staleMate(Color color) { 247 | 248 | // insufficient material stalemate 249 | Piece knightK = getPiece("knightK", color); 250 | Piece knightQ = getPiece("knightQ", color); 251 | Piece bishopK = getPiece("bishopK", color); 252 | Piece bishopQ = getPiece("bishopQ", color); 253 | 254 | if (white.size() == 2 && black.size() == 2) { 255 | if (white.contains(bishopK) || white.contains(bishopQ) || white.contains(knightK) 256 | || white.contains(knightQ)) { 257 | return true; 258 | } 259 | if (black.contains(bishopK) || black.contains(bishopQ) || black.contains(knightK) 260 | || white.contains(knightQ)) { 261 | return true; 262 | } 263 | 264 | } 265 | if (white.size() == 1 && white.get(0) instanceof King && black.size() == 1 && black.get(0) instanceof King) { 266 | return true; 267 | } 268 | 269 | // no legal moves stalemate 270 | if (mate(color) == true && checkForCheck(color) == false) { 271 | return true; 272 | } 273 | 274 | return false; 275 | 276 | } 277 | 278 | } 279 | --------------------------------------------------------------------------------