chessai
college code for ai playing chess in java
git clone https://9o.is/git/chessai.git
commit 472514cbd71424caffa2da001002256eefb74926 parent 105148d8696e0aecb7a3efd36ae0fc506a5fe9a5 Author: Jul <jul@9o.is> Date: Mon, 3 Dec 2012 02:25:44 -0500 Lots of changes. Able to get all possible moves for each piece. Diffstat:
| M | src/chess/ChessBoard.java | | | 146 | ++++++++++++++++++++++++++----------------------------------------------------- |
| A | src/chess/ChessColor.java | | | 20 | ++++++++++++++++++++ |
| M | src/chess/ChessCoordinate.java | | | 111 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| A | src/chess/ChessDirection.java | | | 25 | +++++++++++++++++++++++++ |
| M | src/chess/ChessGame.java | | | 52 | ++++++++++++++++++++++++++++++++++++++++------------ |
| A | src/chess/ChessMove.java | | | 67 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| A | src/chess/ChessPiece.java | | | 53 | +++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| A | src/chess/ChessPlayer.java | | | 35 | +++++++++++++++++++++++++++++++++++ |
| M | src/chess/ChessRules.java | | | 385 | ++++++++++++++++++++++++++++++++++++++++++++++--------------------------------- |
| M | src/chess/ChessState.java | | | 26 | ++++++++++++++++---------- |
| A | src/chess/ChessType.java | | | 30 | ++++++++++++++++++++++++++++++ |
| D | src/chess/Player.java | | | 27 | --------------------------- |
| D | src/chess/piece/ChessColor.java | | | 20 | -------------------- |
| D | src/chess/piece/ChessMove.java | | | 15 | --------------- |
| D | src/chess/piece/ChessPiece.java | | | 53 | ----------------------------------------------------- |
| D | src/chess/piece/ChessType.java | | | 30 | ------------------------------ |
16 files changed, 671 insertions(+), 424 deletions(-)
diff --git a/src/chess/ChessBoard.java b/src/chess/ChessBoard.java @@ -10,79 +10,73 @@ import chess.piece.*; * To change this template use File | Settings | File Templates. */ public class ChessBoard { - private ChessState board; - private ChessRules rules; - private Player player; - private int moves; + private ChessState state; - public ChessBoard(Player player) { - rules = new ChessRules(player); - board = new ChessState(); - this.player = player; - this.moves = 0; + public ChessBoard() { + state = new ChessState(); + init(); } //CHECK public void init() { - board.set(new ChessCoordinate('a',8), ChessPiece.BLACK_ROOK); - board.set(new ChessCoordinate('b',8), ChessPiece.BLACK_KNIGHT); - board.set(new ChessCoordinate('c',8), ChessPiece.BLACK_BISHOP); - board.set(new ChessCoordinate('d',8), ChessPiece.BLACK_QUEEN); - board.set(new ChessCoordinate('e',8), ChessPiece.BLACK_KING); - board.set(new ChessCoordinate('f',8), ChessPiece.BLACK_BISHOP); - board.set(new ChessCoordinate('g',8), ChessPiece.BLACK_KNIGHT); - board.set(new ChessCoordinate('h',8), ChessPiece.BLACK_ROOK); + state.set(new ChessCoordinate('a',8), ChessPiece.BLACK_ROOK); + state.set(new ChessCoordinate('b',8), ChessPiece.BLACK_KNIGHT); + state.set(new ChessCoordinate('c',8), ChessPiece.BLACK_BISHOP); + state.set(new ChessCoordinate('d',8), ChessPiece.BLACK_QUEEN); + state.set(new ChessCoordinate('e',8), ChessPiece.BLACK_KING); + state.set(new ChessCoordinate('f',8), ChessPiece.BLACK_BISHOP); + state.set(new ChessCoordinate('g',8), ChessPiece.BLACK_KNIGHT); + state.set(new ChessCoordinate('h',8), ChessPiece.BLACK_ROOK); for(int i=1; i<= ChessCoordinate.MAX; i++) - board.set(new ChessCoordinate(i,7), ChessPiece.BLACK_PAWN); + state.set(new ChessCoordinate(i,7), ChessPiece.BLACK_PAWN); - board.set(new ChessCoordinate('a',1), ChessPiece.WHITE_ROOK); - board.set(new ChessCoordinate('b',1), ChessPiece.WHITE_KNIGHT); - board.set(new ChessCoordinate('c',1), ChessPiece.WHITE_BISHOP); - board.set(new ChessCoordinate('d',1), ChessPiece.WHITE_QUEEN); - board.set(new ChessCoordinate('e',1), ChessPiece.WHITE_KING); - board.set(new ChessCoordinate('f',1), ChessPiece.WHITE_BISHOP); - board.set(new ChessCoordinate('g',1), ChessPiece.WHITE_KNIGHT); - board.set(new ChessCoordinate('h',1), ChessPiece.WHITE_ROOK); + state.set(new ChessCoordinate('a',1), ChessPiece.WHITE_ROOK); + state.set(new ChessCoordinate('b',1), ChessPiece.WHITE_KNIGHT); + state.set(new ChessCoordinate('c',1), ChessPiece.WHITE_BISHOP); + state.set(new ChessCoordinate('d',1), ChessPiece.WHITE_QUEEN); + state.set(new ChessCoordinate('e',1), ChessPiece.WHITE_KING); + state.set(new ChessCoordinate('f',1), ChessPiece.WHITE_BISHOP); + state.set(new ChessCoordinate('g',1), ChessPiece.WHITE_KNIGHT); + state.set(new ChessCoordinate('h',1), ChessPiece.WHITE_ROOK); for(int i=1; i<= ChessCoordinate.MAX; i++) - board.set(new ChessCoordinate(i,2), ChessPiece.WHITE_PAWN); + state.set(new ChessCoordinate(i,2), ChessPiece.WHITE_PAWN); } - //CHECK - public void move( - ChessCoordinate coor, - ChessMove move, - int steps) { - move(coor, getCoordinate(coor, move, steps)); - } + public void move(ChessMove move) { + ChessCoordinate src = move.getCoordinate(); + move(src, src.getCoordinate(state, move)); + } //CHECK public void move( - ChessCoordinate coor, - ChessMove firstMove, - int steps1, - ChessMove secondMove, - int steps2) { - ChessCoordinate coor1 = getCoordinate(coor, firstMove, steps1); - ChessCoordinate coor2 = getCoordinate(coor1, secondMove, steps2); - move(coor, coor2); + ChessCoordinate src, + ChessDirection direction, + int steps) { + ChessMove move = new ChessMove(src, direction, steps); + move(src, src.getCoordinate(state, move)); } //CHECK - public void move(ChessCoordinate coor, ChessCoordinate coor1) { - if(rules.validMove(board, coor, coor1)) { - rules.applyCaptureRule(); - board.move(coor, coor1); - moves++; + public boolean move(ChessCoordinate src, ChessCoordinate dest) { + ChessRules.INSTANCE.setLog(true); + ChessRules.INSTANCE.setState(state); + ChessRules.INSTANCE.setSrc(src); + ChessRules.INSTANCE.setDest(dest); + + if(ChessRules.INSTANCE.validMove()) { + ChessRules.INSTANCE.applyCaptureRule(); + state.move(src, dest); + return true; } else - System.err.println("Invalid Move: "+coor+coor1); + return false; } //CHECK - public String getState() { - byte[][] state = board.getState(); - String result = "Moves: "+moves+"\n"; + public String printState() { + byte[][] state = this.state.getState(); + String result = ""; for(int i=0; i< ChessCoordinate.MAX; i++) { for(int j=0; j< ChessCoordinate.MAX; j++) @@ -92,53 +86,7 @@ public class ChessBoard { return result; } - //CHECK - private ChessCoordinate getCoordinate( - ChessCoordinate coor, - ChessMove move, - int steps) { - int x = coor.getFileNumber(); - int y = coor.getRank(); - - if(player.getColor() == ChessColor.WHITE) { - if(move == ChessMove.FORWARD) y += steps; - else if(move == ChessMove.BACK) y -= steps; - else if(move == ChessMove.LEFT) x -= steps; - else if(move == ChessMove.RIGHT) x += steps; - - else if(move == ChessMove.FORWARD_LEFT) { - x -= steps; - y += steps; - } else if(move == ChessMove.FORWARD_RIGHT) { - x += steps; - y += steps; - } else if(move == ChessMove.BACK_LEFT) { - x -= steps; - y -= steps; - } else if(move == ChessMove.BACK_RIGHT) { - x += steps; - y -= steps; - } - } else { - if(move == ChessMove.FORWARD) y -= steps; - else if(move == ChessMove.BACK) y += steps; - else if(move == ChessMove.LEFT) x += steps; - else if(move == ChessMove.RIGHT) x -= steps; - - else if(move == ChessMove.FORWARD_LEFT) { - x += steps; - y -= steps; - } else if(move == ChessMove.FORWARD_RIGHT) { - x -= steps; - y -= steps; - } else if(move == ChessMove.BACK_LEFT) { - x += steps; - y += steps; - } else if(move == ChessMove.BACK_RIGHT) { - x -= steps; - y += steps; - } - } - return new ChessCoordinate(x,y); + public ChessState getState() { + return state; } } diff --git a/src/chess/ChessColor.java b/src/chess/ChessColor.java @@ -0,0 +1,20 @@ +package chess; + +/** + * Check + */ +public enum ChessColor { + BLACK ("B"), + WHITE ("W"), + NA (" "); + + private String symbol; + + ChessColor(String symbol) { + this.symbol = symbol; + } + + public String toString() { + return symbol; + } +} diff --git a/src/chess/ChessCoordinate.java b/src/chess/ChessCoordinate.java @@ -1,5 +1,7 @@ package chess; +import chess.ChessPiece; + /** * Check */ @@ -37,6 +39,115 @@ public class ChessCoordinate { return file - 96; // 97 = 'a' } + //CHECK + public ChessCoordinate getCoordinate( + ChessState state, ChessMove move) { + + int file = getFileNumber(); + int rank = getRank(); + + int steps = move.getSteps(); + ChessDirection dir = move.getDirection(); + + final ChessPiece srcPiece = + ChessPiece.find(state.get(move.getCoordinate())); + + if(srcPiece.getColor() == ChessColor.WHITE) { + if(dir == ChessDirection.FORWARD) rank += steps; + else if(dir == ChessDirection.BACK) rank -= steps; + else if(dir == ChessDirection.LEFT) file -= steps; + else if(dir == ChessDirection.RIGHT) file += steps; + + else if(dir == ChessDirection.FORWARD_LEFT) { + file -= steps; + rank += steps; + } else if(dir == ChessDirection.FORWARD_RIGHT) { + file += steps; + rank += steps; + } else if(dir == ChessDirection.BACK_LEFT) { + file -= steps; + rank -= steps; + } else if(dir == ChessDirection.BACK_RIGHT) { + file += steps; + rank -= steps; + } else if(dir == ChessDirection.KNIGHT_FORWARD_LEFT) { + file -= steps; + rank += steps+1; + } else if(dir == ChessDirection.KNIGHT_FORWARD_RIGHT) { + file += steps; + rank += steps+1; + } else if(dir == ChessDirection.KNIGHT_BACK_LEFT) { + file -= steps; + rank -= steps+1; + } else if(dir == ChessDirection.KNIGHT_BACK_RIGHT) { + file += steps; + rank -= steps+1; + } else if(dir == ChessDirection.KNIGHT_LEFT_FORWARD) { + file -= steps+1; + rank += steps; + } else if(dir == ChessDirection.KNIGHT_LEFT_BACK) { + file -= steps+1; + rank -= steps; + } else if(dir == ChessDirection.KNIGHT_RIGHT_FORWARD) { + file += steps+1; + rank += steps; + } else if(dir == ChessDirection.KNIGHT_RIGHT_BACK) { + file += steps+1; + rank -= steps; + } + } else { + if(dir == ChessDirection.FORWARD) rank -= steps; + else if(dir == ChessDirection.BACK) rank += steps; + else if(dir == ChessDirection.LEFT) file += steps; + else if(dir == ChessDirection.RIGHT) file -= steps; + + else if(dir == ChessDirection.FORWARD_LEFT) { + file += steps; + rank -= steps; + } else if(dir == ChessDirection.FORWARD_RIGHT) { + file -= steps; + rank -= steps; + } else if(dir == ChessDirection.BACK_LEFT) { + file += steps; + rank += steps; + } else if(dir == ChessDirection.BACK_RIGHT) { + file -= steps; + rank += steps; + } else if(dir == ChessDirection.KNIGHT_FORWARD_LEFT) { + file += steps; + rank -= steps+1; + } else if(dir == ChessDirection.KNIGHT_FORWARD_RIGHT) { + file -= steps; + rank -= steps+1; + } else if(dir == ChessDirection.KNIGHT_BACK_LEFT) { + file += steps; + rank += steps+1; + } else if(dir == ChessDirection.KNIGHT_BACK_RIGHT) { + file -= steps; + rank += steps+1; + } else if(dir == ChessDirection.KNIGHT_LEFT_FORWARD) { + file += steps+1; + rank -= steps; + } else if(dir == ChessDirection.KNIGHT_LEFT_BACK) { + file += steps+1; + rank += steps; + } else if(dir == ChessDirection.KNIGHT_RIGHT_FORWARD) { + file -= steps+1; + rank -= steps; + } else if(dir == ChessDirection.KNIGHT_RIGHT_BACK) { + file -= steps+1; + rank += steps; + } + } + + return new ChessCoordinate(file,rank); + } + + public boolean invalid() { + return file > 'h' || file < 'a' || + rank > ChessCoordinate.MAX || rank < 1; + } + public String toString() { return ""+file+rank; } diff --git a/src/chess/ChessDirection.java b/src/chess/ChessDirection.java @@ -0,0 +1,25 @@ +package chess; + +/** + * Check + */ +public enum ChessDirection { + FORWARD, + BACK, + LEFT, + RIGHT, + FORWARD_LEFT, + FORWARD_RIGHT, + BACK_LEFT, + BACK_RIGHT, + + // exclusive knight moves + KNIGHT_LEFT_FORWARD, + KNIGHT_LEFT_BACK, + KNIGHT_RIGHT_FORWARD, + KNIGHT_RIGHT_BACK, + KNIGHT_FORWARD_LEFT, + KNIGHT_FORWARD_RIGHT, + KNIGHT_BACK_LEFT, + KNIGHT_BACK_RIGHT; +} diff --git a/src/chess/ChessGame.java b/src/chess/ChessGame.java @@ -1,25 +1,53 @@ package chess; -import chess.piece.ChessColor; -import chess.piece.ChessMove; +import java.util.List; /** - * Created with IntelliJ IDEA. - * User: julio - * Date: 11/29/12 - * Time: 2:06 PM - * To change this template use File | Settings | File Templates. + * */ public class ChessGame { public static void main(String[] args) { - Player player = new Player(ChessColor.WHITE); - ChessBoard game = new ChessBoard(player); + ChessPlayer player = new ChessPlayer(ChessColor.WHITE); + ChessPlayer opponent = new ChessPlayer(ChessColor.BLACK); + ChessColor turn = player.getColor(); + ChessBoard board = new ChessBoard(); - game.init(); - game.move(new ChessCoordinate('c',2), ChessMove.FORWARD, 1); - System.out.println(game.getState()); + /* + while (true) { + // our turn + while(turn == player.getColor()) { + } + + // opponent's turn + while(turn == opponent.getColor()) { + + } + } + */ + + board.move(new ChessCoordinate('b', 2), ChessDirection.FORWARD, 1); + board.move(new ChessCoordinate('d', 2), ChessDirection.FORWARD, 1); + ChessCoordinate src = new ChessCoordinate('b',1); + + ChessRules.INSTANCE.setLog(false); + + List<ChessMove> moves = + ChessMove.possibleMoves(src, board.getState()); + + for(ChessMove move : moves) + System.out.println(move.toString()); + + /* + board.move(new ChessCoordinate('d', 2), ChessDirection.FORWARD, 1); + board.move(new ChessCoordinate('d', 3), ChessDirection.FORWARD, 1); + board.move(new ChessCoordinate('d', 1), ChessDirection.FORWARD, 2); + board.move(new ChessCoordinate('d', 3), ChessDirection.FORWARD_LEFT, 2); + //game.move(new ChessCoordinate('d',4), ChessDirection.LEFT, 1); + */ + System.out.println("Moves: "+player.getMoves()+ + "\n"+board.printState()); } } diff --git a/src/chess/ChessMove.java b/src/chess/ChessMove.java @@ -0,0 +1,67 @@ +package chess; + +import java.util.ArrayList; +import java.util.List; + +/** + * + */ +public class ChessMove { + + private ChessCoordinate coordinate; + private ChessDirection direction; + private int steps; + + public ChessMove( + ChessCoordinate coordinate, + ChessDirection direction, + int steps) { + this.coordinate = coordinate; + this.direction = direction; + this.steps = steps; + } + + public int getSteps() { + return steps; + } + + public ChessDirection getDirection() { + return direction; + } + + public ChessCoordinate getCoordinate() { + return coordinate; + } + + public static List<ChessMove> possibleMoves( + ChessCoordinate src, ChessState state) { + + List<ChessMove> moves = new ArrayList<ChessMove>(); + ChessRules.INSTANCE.setState(state); + ChessRules.INSTANCE.setSrc(src); + + final ChessDirection[] directions = + ChessRules.INSTANCE.possibleDirections(); + + for(ChessDirection direction : directions) { + boolean valid = true; + int steps = 1; + while (valid) { + ChessMove move = new ChessMove(src, direction, steps); + ChessCoordinate dest = src; + dest = dest.getCoordinate(state, move); + ChessRules.INSTANCE.setDest(dest); + valid = ChessRules.INSTANCE.validMove(); + + if(valid) moves.add(move); + steps++; + } + } + + return moves; + } + + public String toString() { + return coordinate+" "+direction+" "+steps+" steps"; + } +} diff --git a/src/chess/ChessPiece.java b/src/chess/ChessPiece.java @@ -0,0 +1,53 @@ +package chess; + +/** + * Check + */ +public enum ChessPiece { + BLACK_KING (12, ChessColor.BLACK, ChessType.KING), + BLACK_QUEEN (11, ChessColor.BLACK, ChessType.QUEEN), + BLACK_BISHOP (10, ChessColor.BLACK, ChessType.BISHOP), + BLACK_KNIGHT (9, ChessColor.BLACK, ChessType.KNIGHT), + BLACK_ROOK (8, ChessColor.BLACK, ChessType.ROOK), + BLACK_PAWN (7, ChessColor.BLACK, ChessType.PAWN), + WHITE_KING (6, ChessColor.WHITE, ChessType.KING), + WHITE_QUEEN (5, ChessColor.WHITE, ChessType.QUEEN), + WHITE_BISHOP (4, ChessColor.WHITE, ChessType.BISHOP), + WHITE_KNIGHT (3, ChessColor.WHITE, ChessType.KNIGHT), + WHITE_ROOK (2, ChessColor.WHITE, ChessType.ROOK), + WHITE_PAWN (1, ChessColor.WHITE, ChessType.PAWN), + NA (-1, ChessColor.NA, ChessType.NA); + + private int num; + private ChessColor color; + private ChessType type; + + ChessPiece(int num, ChessColor color, ChessType type) { + this.num = num; + this.color = color; + this.type = type; + } + + public ChessType getType() { + return type; + } + + public ChessColor getColor() { + return color; + } + + public int getNum() { + return num; + } + + public String toString() { + return color.toString() + type.toString(); + } + + public static ChessPiece find(int num) { + for (ChessPiece piece : ChessPiece.values()) + if(piece.getNum() == num) return piece; + + return ChessPiece.NA; + } +} diff --git a/src/chess/ChessPlayer.java b/src/chess/ChessPlayer.java @@ -0,0 +1,35 @@ +package chess; + +/** + * Check + */ +public class ChessPlayer { + + private static final String ERROR_MSG = + ChessPlayer.class+": Invalid color."; + + private int points; + private ChessColor color; + private int moves; + + public ChessPlayer(ChessColor color) { + if(color == ChessColor.NA) + throw new IllegalArgumentException(ERROR_MSG); + + this.color = color; + points = 0; + moves = 0; + } + + public ChessColor getColor() { + return color; + } + + public int getPoints() { + return points; + } + + public int getMoves() { + return moves; + } +} diff --git a/src/chess/ChessRules.java b/src/chess/ChessRules.java @@ -1,35 +1,49 @@ package chess; -import chess.piece.*; +import java.util.Arrays; /** * Check */ -public class ChessRules { +public enum ChessRules { + + INSTANCE; private ChessState state; private ChessCoordinate src; private ChessCoordinate dest; - private static final String failurePrefix = - ChessRules.class + ": FAILED -> "; + private ChessPiece srcPiece; + private ChessPiece destPiece; + private ChessType srcType; + + private boolean log = true; + + public void setState(ChessState state) { + this.state = state; + } - private static final String capturePrefix = - ChessRules.class + ": CAPTURE -> "; + public void setSrc(ChessCoordinate src) { + this.src = src; + this.srcPiece = !src.invalid() ? + ChessPiece.find(state.get(src)) : null; + this.srcType = srcPiece != null ? srcPiece.getType() : null; + } - private Player player; + public void setDest(ChessCoordinate dest) { + this.dest = dest; + this.destPiece = !dest.invalid() ? + ChessPiece.find(state.get(dest)) : null; + } - public ChessRules(Player player) { - this.player = player; + public void setLog(boolean log) { + this.log = log; } // must be called after testing invalid is false // eg. if(validMove(...)) applyCaptureRule(); // CHECK public void applyCaptureRule() { - final ChessPiece srcPiece = ChessPiece.find(state.get(src)); - final ChessPiece destPiece = ChessPiece.find(state.get(dest)); - // are the source and destination pieces different colors? if(srcPiece.getColor() != destPiece.getColor() && srcPiece != ChessPiece.NA && @@ -38,95 +52,78 @@ public class ChessRules { // CAPTURE! // TODO handle player points here - System.out.println(capturePrefix + - srcPiece + src + destPiece + dest); + System.out.println(ChessRules.class + ": CAPTURED -> " + + srcPiece + src + destPiece + dest); } } // CHECK - public boolean validMove( - ChessState state, - ChessCoordinate src, - ChessCoordinate dest) { - this.state = state; - this.src = src; - this.dest = dest; - + public boolean validMove() { return pieceMoves() && - srcHasPiece() && - insideBoard() && - uninhabitedSpace() && - legalSkip() && - validRookMove() && - validKnightMove() && - validBishopMove() && - validQueenMove() && - validKingMove() && - validPawnMove(); + srcHasPiece() && + insideBoard() && + unoccupiedSpace() && + legalSkip() && + validRookMove() && + validKnightMove() && + validBishopMove() && + validQueenMove() && + validKingMove() && + validPawnMove(); } /* - * Checks if the piece moved. It cannot stay in same spot. - */ - public boolean pieceMoves() { + * Checks if the piece moved. It cannot stay in same spot. + */ + private boolean pieceMoves() { if(src.equals(dest)) { - System.err.println(failurePrefix+"pieceMoves test"); + logFailure("pieceMoves"); return false; } return true; } /* - * Checks if source coordinate has a chess piece. - */ + * Checks if source coordinate has a chess piece. + */ private boolean srcHasPiece() { - final ChessPiece srcPiece = ChessPiece.find(state.get(src)); if(srcPiece == ChessPiece.NA) { - System.err.println(failurePrefix+"srcHasPiece test"); + logFailure("srcHasPiece"); return false; - } else - return true; + } + return true; } /* - * Checks if the destination coordinate is inside the chess - * board. - */ + * Checks if the destination coordinate is inside the chess + * board. + */ private boolean insideBoard() { - final char file = dest.getFile(); - final int rank = dest.getRank(); - - if(file > 'h' || file < 'a' || - rank > ChessCoordinate.MAX || rank < 1) { - System.err.println(failurePrefix+"insideBoard test"); + if(dest.invalid()) { + logFailure("insideBoard"); return false; } return true; } /* - * Checks if player moved a chess piece onto one of his own pieces. - */ - private boolean uninhabitedSpace() { - final ChessPiece srcPiece = ChessPiece.find(state.get(src)); - final ChessPiece destPiece = ChessPiece.find(state.get(dest)); - + * Checks if player moved a chess piece onto one of his own pieces. + */ + private boolean unoccupiedSpace() { // are the source and destination pieces same color? if(srcPiece.getColor() == destPiece.getColor()) { - System.err.println(failurePrefix+"uninhabitedSpace test"); + logFailure("unoccupiedSpace"); return false; - } else - return true; + } + return true; } /* - * Checks if source piece skips over other pieces when moving. - */ + * Checks if source piece skips over other pieces when moving. + */ private boolean legalSkip() { - final ChessPiece srcPiece = ChessPiece.find(state.get(src)); - // Knight is an exception. - if(srcPiece.getType() == ChessType.KNIGHT) + if(srcType==ChessType.KNIGHT) return true; final int hor = dest.getFile() - src.getFile(); @@ -134,22 +131,25 @@ public class ChessRules { int rank = dest.getRank(); int file = dest.getFile(); + + if(hor != 0) { + if(hor > 0) file--; + else file++; + } + if(ver != 0) { + if(ver > 0) rank--; + else rank++; + } + while (src.getFile() != file || src.getRank() != rank) { - try { - final byte pieceValue = - state.get(new ChessCoordinate((char)file, rank)); - ChessPiece check = ChessPiece.find(pieceValue); - - if(check != ChessPiece.NA) { - System.err.println(failurePrefix+"legalSkip test"); - return false; - } - } catch (Exception e) { - System.err.println(failurePrefix+ - "Legal Skip method generated illegal chess"+ - " coordinate. This should not happen. Weird"); - e.printStackTrace(); + final byte pieceValue = + state.get(new ChessCoordinate((char)file, rank)); + ChessPiece check = ChessPiece.find(pieceValue); + + if(check != ChessPiece.NA) { + logFailure("legalSkip"); + return false; } if(hor != 0) { @@ -165,123 +165,192 @@ public class ChessRules { } private boolean validRookMove(){ - //Rank must be the same exclusive or file must be the same for a rook to move - final ChessPiece srcPiece = ChessPiece.find(state.get(src)); - final ChessType type = srcPiece.getType(); - if(type==ChessType.ROOK){ + //Rank must be the same exclusive or file must be the + // same for a rook to move + if(srcType==ChessType.ROOK){ + if(rookMove()) + return true; - if(this.src.getRank()==this.dest.getRank()^this.src.getFileNumber()==this.dest.getFileNumber()){ - return true; - } - System.out.println("Rook Move Failed"); - return false; + logFailure("validRookMove"); + return false; } return true; } private boolean validKnightMove(){ - final ChessPiece srcPiece = ChessPiece.find(state.get(src)); - final ChessType type = srcPiece.getType(); + if(srcType==ChessType.KNIGHT){ + final int rankDiff = Math.abs(src.getRank()-dest.getRank()); + final int fileDiff = Math.abs(src.getFile()-dest.getFile()); - if(type==ChessType.KNIGHT){ - if(Math.abs(this.src.getRank()-this.dest.getRank())==2&&Math.abs(this.src.getFileNumber()-this.dest.getFileNumber())==1){ - return true; - } - else if(Math.abs(this.src.getRank()-this.dest.getRank())==1&&Math.abs(this.src.getFileNumber()-this.dest.getFileNumber())==2){ - return true; - } - System.out.println("Knight Move Failed"); - return false; + if((rankDiff == 2 && fileDiff == 1) || + (rankDiff == 1 && fileDiff == 2)) { + return true; + } + + logFailure("validKnightMove"); + return false; } return true; } private boolean validPawnMove(){ - final ChessPiece srcPiece = ChessPiece.find(state.get(src)); - final ChessType type = srcPiece.getType(); - - if(type==ChessType.PAWN){ - final ChessPiece destPiece = ChessPiece.find(state.get(dest)); - //Pawn move up one - if (srcPiece.getColor()==ChessColor.WHITE){ + if(srcType==ChessType.PAWN){ + //Pawn move up one + if (srcPiece.getColor() == ChessColor.WHITE){ - if(this.src.getRank()+1==(this.dest.getRank())&&this.src.getFileNumber()==this.dest.getFileNumber()){ - return true; - } - //Pawn capture + if(src.getRank()+1 == dest.getRank() && + src.getFile() == dest.getFile()){ + return true; + } - if(this.src.getRank()+1==(this.dest.getRank())&&Math.abs(this.src.getFileNumber()-this.dest.getFileNumber())==1&&srcPiece.getColor()!=destPiece.getColor()&&destPiece != ChessPiece.NA){ - return true; - } - } - else{ + //Pawn capture + if(src.getRank()+1 == dest.getRank() && + Math.abs(src.getFile()-dest.getFile()) == 1 && + srcPiece.getColor() != destPiece.getColor() && + destPiece != ChessPiece.NA) { + return true; + } + } else { - if(this.src.getRank()==(this.dest.getRank()+1)&&this.src.getFileNumber()==this.dest.getFileNumber()){ - return true; - } - //Pawn capture + if(src.getRank() == dest.getRank()+1 && + src.getFile() == dest.getFile()) { + return true; + } - if(this.src.getRank()+1==(this.dest.getRank()+1)&&Math.abs(this.src.getFileNumber()-this.dest.getFileNumber())==1&&srcPiece.getColor()!=destPiece.getColor()&&destPiece != ChessPiece.NA){ - return true; + //Pawn capture + if(src.getRank()+1 == dest.getRank()+1 && + Math.abs(src.getFile()-dest.getFile()) == 1 && + srcPiece.getColor() != destPiece.getColor() && + destPiece != ChessPiece.NA){ + return true; + } } - } - System.out.println("Pawn Cannot Capture"); - /*Pawns can also move 2 spaces on first turn - *Pawns can also capture en passant - Still functional without these features though*/ - System.out.println("Pawn Move Failed"); - return false; + //System.out.println("Pawn Cannot Capture"); + /*Pawns can also move 2 spaces on first turn + *Pawns can also capture en passant + Still functional without these features though*/ + logFailure("validPawnMove"); + return false; } return true; } private boolean validBishopMove(){ - final ChessPiece srcPiece = ChessPiece.find(state.get(src)); - final ChessType type = srcPiece.getType(); + if(srcType==ChessType.BISHOP){ + if(bishopMove()) + return true; - if(type==ChessType.BISHOP){ - if(Math.abs(this.src.getRank()-this.dest.getRank())==Math.abs(this.src.getFileNumber()-this.dest.getFileNumber())){ - return true; - } - System.out.println("Bishop Move Failed"); - return false; + logFailure("validBishopMove"); + return false; } return true; } private boolean validKingMove(){ - final ChessPiece srcPiece = ChessPiece.find(state.get(src)); - final ChessType type = srcPiece.getType(); + if(srcType==ChessType.KING){ + if(src.getRank()-dest.getRank() < 2 && + src.getFile()-dest.getFileNumber() < 2) { + return true; + } - if(type==ChessType.KING){ - if(Math.abs(this.src.getRank())-Math.abs(this.dest.getRank())<2&&Math.abs(this.src.getFileNumber())-Math.abs(this.dest.getFileNumber())<2){ - return true; - } - System.out.println("King Move Failed"); - //Moves that get the king captured are invalid - return false; + logFailure("validKingMove"); + //Moves that get the king captured are invalid + return false; } return true; } private boolean validQueenMove() { - return rook()^bishop(); + if(srcType == ChessType.QUEEN){ + if(!(rookMove() ^ bishopMove())) { + logFailure("validQueenMove"); + return false; + } + } + return true; } - private boolean rook() { - if(this.src.getRank()==this.dest.getRank()^this.src.getFileNumber()==this.dest.getFileNumber()){ - return true; - } - System.out.println("Queen Move Failed"); - return false; + public ChessDirection[] possibleDirections() { + if(srcType==ChessType.PAWN) return pawnDirections(); + if(srcType==ChessType.ROOK) return rookDirections(); + if(srcType==ChessType.BISHOP) return bishopDirections(); + if(srcType==ChessType.KNIGHT) return knightDirections(); + if(srcType==ChessType.QUEEN) return queenDirections(); + if(srcType==ChessType.KING) return kingDirections(); + else + return new ChessDirection[]{}; } - private boolean bishop() { - if(Math.abs(this.src.getRank()-this.dest.getRank())==Math.abs(this.src.getFileNumber()-this.dest.getFileNumber())){ - return true; - } - System.out.println("Queen Move Failed"); - return false; + private ChessDirection[] pawnDirections() { + return new ChessDirection[] { + ChessDirection.FORWARD, + ChessDirection.FORWARD_LEFT, + ChessDirection.FORWARD_RIGHT + }; + } + + private ChessDirection[] rookDirections() { + return new ChessDirection[] { + ChessDirection.FORWARD, + ChessDirection.BACK, + ChessDirection.LEFT, + ChessDirection.RIGHT + }; + } + + private ChessDirection[] bishopDirections() { + return new ChessDirection[] { + ChessDirection.FORWARD_LEFT, + ChessDirection.FORWARD_RIGHT, + ChessDirection.BACK_LEFT, + ChessDirection.BACK_RIGHT + }; + } + + private ChessDirection[] knightDirections() { + return new ChessDirection[] { + ChessDirection.KNIGHT_LEFT_FORWARD, + ChessDirection.KNIGHT_LEFT_BACK, + ChessDirection.KNIGHT_RIGHT_FORWARD, + ChessDirection.KNIGHT_RIGHT_BACK, + ChessDirection.KNIGHT_FORWARD_LEFT, + ChessDirection.KNIGHT_FORWARD_RIGHT, + ChessDirection.KNIGHT_BACK_LEFT, + ChessDirection.KNIGHT_BACK_RIGHT + }; + } + + private ChessDirection[] queenDirections() { + return concat(bishopDirections(), rookDirections()); + } + + private ChessDirection[] kingDirections() { + return queenDirections(); } + private boolean rookMove() { + return src.getRank() == dest.getRank() ^ + src.getFile() == dest.getFile(); + } + + private boolean bishopMove() { + final int rankDiff = Math.abs(src.getRank()-dest.getRank()); + final int fileDiff = Math.abs(src.getFile()-dest.getFile()); + + return rankDiff == fileDiff; + } + + private void logFailure(String method) { + if(log) + System.err.println(ChessRules.class + ": FAILURE -> "+ + method+" test --- Move: "+ + srcPiece+src+dest); + } + + // TODO where should this be placed? + private static <T> T[] concat(T[] first, T[] second) { + T[] result = Arrays.copyOf(first, first.length + second.length); + System.arraycopy(second, 0, result, first.length, second.length); + return result; + } } diff --git a/src/chess/ChessState.java b/src/chess/ChessState.java @@ -1,6 +1,6 @@ package chess; -import chess.piece.ChessPiece; +import chess.ChessPiece; /** * Check @@ -17,22 +17,28 @@ public class ChessState { } public void set(ChessCoordinate coor, ChessPiece piece) { - int rank = fixRankOrder(coor.getRank()); - state[rank-1][coor.getFileNumber()-1] = (byte) piece.getNum(); + final int rank = fixRankOrder(coor.getRank()) - 1; + final int file = coor.getFileNumber() - 1; + + state[rank][file] = (byte) piece.getNum(); } public byte get(ChessCoordinate coor) { - int rank = fixRankOrder(coor.getRank()); - return state[rank-1][coor.getFileNumber()-1]; + final int rank = fixRankOrder(coor.getRank()) - 1; + final int file = coor.getFileNumber() - 1; + + return state[rank][file]; } public void move(ChessCoordinate coor, ChessCoordinate coor1) { - int rank = fixRankOrder(coor.getRank()); - int rank1 = fixRankOrder(coor1.getRank()); + final int rank = fixRankOrder(coor.getRank()) - 1; + final int rank1 = fixRankOrder(coor1.getRank()) - 1; + + final int file = coor.getFileNumber() - 1; + final int file1 = coor1.getFileNumber() - 1; - state[rank1-1][coor1.getFileNumber()-1] = - state[rank-1][coor.getFileNumber()-1]; - state[rank-1][coor.getFileNumber()-1] = 0; + state[rank1][file1] = state[rank][file]; + state[rank][file] = 0; } private int fixRankOrder(int rank) { diff --git a/src/chess/ChessType.java b/src/chess/ChessType.java @@ -0,0 +1,30 @@ +package chess; + +/** + * Check + */ +public enum ChessType { + KING ("K", 1000), + QUEEN ("Q", 9), + BISHOP ("B", 3), + KNIGHT ("N", 3), + ROOK ("R", 5), + PAWN ("P", 1), + NA (" ", 0); + + private int value; + private String symbol; + + ChessType(String symbol, int value) { + this.symbol = symbol; + this.value = value; + } + + public int getValue() { + return value; + } + + public String toString() { + return symbol; + } +} diff --git a/src/chess/Player.java b/src/chess/Player.java @@ -1,27 +0,0 @@ -package chess; - -import chess.piece.ChessColor; - -/** - * Check - */ -public class Player { - - private static final String ERROR_MSG = - Player.class+": Invalid color."; - - private int points; - private ChessColor color; - - public Player(ChessColor color) { - if(color == ChessColor.NA) - throw new IllegalArgumentException(ERROR_MSG); - - this.color = color; - points = 0; - } - - public ChessColor getColor() { - return color; - } -} diff --git a/src/chess/piece/ChessColor.java b/src/chess/piece/ChessColor.java @@ -1,20 +0,0 @@ -package chess.piece; - -/** - * Check - */ -public enum ChessColor { - BLACK ("B"), - WHITE ("W"), - NA (" "); - - private String symbol; - - ChessColor(String symbol) { - this.symbol = symbol; - } - - public String toString() { - return symbol; - } -} diff --git a/src/chess/piece/ChessMove.java b/src/chess/piece/ChessMove.java @@ -1,15 +0,0 @@ -package chess.piece; - -/** - * Check - */ -public enum ChessMove { - FORWARD, - BACK, - LEFT, - RIGHT, - FORWARD_LEFT, - FORWARD_RIGHT, - BACK_LEFT, - BACK_RIGHT; -} diff --git a/src/chess/piece/ChessPiece.java b/src/chess/piece/ChessPiece.java @@ -1,53 +0,0 @@ -package chess.piece; - -/** - * Check - */ -public enum ChessPiece { - BLACK_KING (12, ChessColor.BLACK, ChessType.KING), - BLACK_QUEEN (11, ChessColor.BLACK, ChessType.QUEEN), - BLACK_BISHOP (10, ChessColor.BLACK, ChessType.BISHOP), - BLACK_KNIGHT (9, ChessColor.BLACK, ChessType.KNIGHT), - BLACK_ROOK (8, ChessColor.BLACK, ChessType.ROOK), - BLACK_PAWN (7, ChessColor.BLACK, ChessType.PAWN), - WHITE_KING (6, ChessColor.WHITE, ChessType.KING), - WHITE_QUEEN (5, ChessColor.WHITE, ChessType.QUEEN), - WHITE_BISHOP (4, ChessColor.WHITE, ChessType.BISHOP), - WHITE_KNIGHT (3, ChessColor.WHITE, ChessType.KNIGHT), - WHITE_ROOK (2, ChessColor.WHITE, ChessType.ROOK), - WHITE_PAWN (1, ChessColor.WHITE, ChessType.PAWN), - NA (-1, ChessColor.NA, ChessType.NA); - - private int num; - private ChessColor color; - private ChessType type; - - ChessPiece(int num, ChessColor color, ChessType type) { - this.num = num; - this.color = color; - this.type = type; - } - - public ChessType getType() { - return type; - } - - public ChessColor getColor() { - return color; - } - - public int getNum() { - return num; - } - - public String toString() { - return color.toString() + type.toString(); - } - - public static ChessPiece find(int num) { - for (ChessPiece piece : ChessPiece.values()) - if(piece.getNum() == num) return piece; - - return ChessPiece.NA; - } -} diff --git a/src/chess/piece/ChessType.java b/src/chess/piece/ChessType.java @@ -1,30 +0,0 @@ -package chess.piece; - -/** - * Check - */ -public enum ChessType { - KING ("K", 1000), - QUEEN ("Q", 9), - BISHOP ("B", 3), - KNIGHT ("N", 3), - ROOK ("R", 5), - PAWN ("P", 1), - NA (" ", 0); - - private int value; - private String symbol; - - ChessType(String symbol, int value) { - this.symbol = symbol; - this.value = value; - } - - public int getValue() { - return value; - } - - public String toString() { - return symbol; - } -}