diff --git a/src/suicideChess/ComputerPlayer.java b/src/suicideChess/ComputerPlayer.java new file mode 100644 index 0000000..8d4c09c --- /dev/null +++ b/src/suicideChess/ComputerPlayer.java @@ -0,0 +1,47 @@ +package suicideChess; + +import java.util.ArrayList; + +import suicideChess.Square.NotAValidSquare; + +/** + * This class will contain all the AI. + * @author Jean-Baptiste Hétier + * @version $LastChangedRevision: 33 $, $LastChangedDate: 2006-01-13 17:03:06 +0000 (Fri, 13 Jan 2006) $ + */ + +public class ComputerPlayer { + + private int color; + + /** + * This constructor creates a computer that plays with the given color + * @param color An integer representing the color. (See {@link Piece}) + * @see Piece + */ + public ComputerPlayer(int color) { + this.color = color; + } + + /** + * This asks the computer to compute a move + * @param bitboard The current status of the {@link Board} + * @return move A {@link Move} + * @throws NotAValidSquare + * @see Board + * @see Move + */ + public Move doMove(Board bitboard) throws NotAValidSquare { + Rules.legalMovesForPlayer(bitboard,color); + ArrayList allLegalMoves = Rules.getLegalMovesCapture(); + if (allLegalMoves.size()==0) { + allLegalMoves = Rules.getLegalMovesNonCapture(); + } + if (allLegalMoves.size()!=0) { + return allLegalMoves.get(0); + } + + throw new RuntimeException(); + + } +} diff --git a/src/suicideChess/Move.java b/src/suicideChess/Move.java index b862a73..bd32efe 100644 --- a/src/suicideChess/Move.java +++ b/src/suicideChess/Move.java @@ -302,7 +302,10 @@ public class Move { * @return String */ public String toString() { - return fromSquare.toString()+toSquare+promotionPiece; + if (isPromotion) { + return fromSquare.toString()+toSquare+promotionPiece.toString(); + } + return fromSquare.toString()+toSquare; } diff --git a/src/suicideChess/Piece.java b/src/suicideChess/Piece.java index c7c05de..d01d2e3 100644 --- a/src/suicideChess/Piece.java +++ b/src/suicideChess/Piece.java @@ -158,6 +158,6 @@ public class Piece { case KNIGHT: return Character.toString(KNIGHT_CHAR); } - return "**Error**"; + return "**Warning** in Piece.java"; } } diff --git a/src/suicideChess/Rules.java b/src/suicideChess/Rules.java index 319d202..eb4504e 100644 --- a/src/suicideChess/Rules.java +++ b/src/suicideChess/Rules.java @@ -300,7 +300,7 @@ public class Rules { * You need to call legalMovesFromSquare before calling this function. * @return ArrayList */ - public ArrayList getLegalMovesNonCapture() { + public static ArrayList getLegalMovesNonCapture() { return legalMovesNonCapture; } @@ -310,7 +310,7 @@ public class Rules { * You need to call legalMovesFromSquare before calling this function. * @return ArrayList */ - public ArrayList getLegalMovesCapture() { + public static ArrayList getLegalMovesCapture() { return legalMovesCapture; } diff --git a/src/suicideChess/SuicideChess.java b/src/suicideChess/SuicideChess.java index 792f51b..6c45a1c 100644 --- a/src/suicideChess/SuicideChess.java +++ b/src/suicideChess/SuicideChess.java @@ -4,6 +4,7 @@ import java.io.BufferedReader; import java.io.InputStreamReader; import java.util.ArrayList; + import suicideChess.Move.NotAValidMoveException; import suicideChess.Square.NotAValidSquare; @@ -14,142 +15,190 @@ import suicideChess.Square.NotAValidSquare; */ public class SuicideChess { - - /* - * Those flags are used to perform extra checks during the debugging of the - * program. They may be safely all set to false once the program is stable. - * It should improve performance a lot. - */ - /** - * does BitBoard.class removePiece function checks if removing piece is legal ? - */ - public static final boolean BITBOARD_REMOVEPIECE_CHECK_REMOVE = true; - /** - * does Square.class checks if the strings are valid (is "z9" a valid square ? - */ - public static final boolean SQUARE_CHECK_INVALID = true; - - private static final int MAIN_VERSION_NUMBER = 0; - private static final int REVISION_NUMBER = 19; - - /** - * The main function - * @param args No parameters should be transmitted to this function. - */ - public static void main(String[] args) { - System.out.println(" Welcome to SuicideChess v"+MAIN_VERSION_NUMBER+"."+REVISION_NUMBER+"!"); - System.out.println(); - BufferedReader moveInput = new BufferedReader(new InputStreamReader(System.in)); - - try { - Board bitboard = new Board(); - bitboard.display(); - - int playerColor = Piece.WHITE; - System.out.println("White: "); - - - while (true) { - try { - String whatMove= moveInput.readLine(); + /* + * Those flags are used to perform extra checks during the debugging of the + * program. They may be safely all set to false once the program is stable. + * It should improve performance a lot. + */ + /** + * does BitBoard.class removePiece function checks if removing piece is legal ? + */ + public static final boolean BITBOARD_REMOVEPIECE_CHECK_REMOVE = true; + /** + * does Square.class checks if the strings are valid (is "z9" a valid square ?) + */ + public static final boolean SQUARE_CHECK_INVALID = true; + + /** + * The name to be displayed + */ + public static final String NAME = "djib's SuicideChess v0.1.9"; + + /** + * Displays informations in the console. + */ + public static final boolean ASCII_GAME = false; + + /** + * The main function + * @param args No parameters should be transmitted to this function. + */ + public static void main(String[] args) { + + try { + + BufferedReader moveInput = new BufferedReader(new InputStreamReader(System.in)); + Board bitboard = new Board(); + + if (ASCII_GAME) + bitboard.display(); + int currentPlayerColor = Piece.WHITE; + if (ASCII_GAME) + System.out.println("White: "); + + ComputerPlayer computer = new ComputerPlayer(Piece.BLACK); + + boolean playing = true; + + while (playing) { + try { + String whatMove= moveInput.readLine(); boolean playedALegalMove = false; - - if (whatMove.startsWith("quit")) { - System.out.println("Goodbye!"); - break; - } - - if (whatMove.startsWith("hint")) { - Rules rules = new Rules(); - rules.legalMovesForPlayer(bitboard,playerColor); - ArrayList allLegalMoves = rules.getLegalMovesCapture(); - if (allLegalMoves.size()==0) { - allLegalMoves = rules.getLegalMovesNonCapture(); - } - for(int i = 0; i allLegalMoves = rules.getLegalMovesCapture(); - if (allLegalMoves.size()==0) { - allLegalMoves = rules.getLegalMovesNonCapture(); - } else { - needToCapture = true; - } - for (int moveIndex = 0; moveIndex < allLegalMoves.size(); moveIndex++) { - if (allLegalMoves.get(moveIndex).isSimpleEqual(theMove)) { - if(theMove.isPromotionMove()&& - theMove.getPromotionPiece().getPieceNumber()!=allLegalMoves.get(moveIndex).getPromotionPiece().getPieceNumber()) { - continue; - } - foundMoveIndex=moveIndex; - break; - } - } - if (foundMoveIndex == -1) { - if (needToCapture) { - System.out.println("Capturing is mandatory."); - } - System.out.println("This move is not valid. Please type 'hint' to see list of legal moves."); - } else { - allLegalMoves.get(foundMoveIndex).display(); - bitboard.doMove(allLegalMoves.get(foundMoveIndex)); - bitboard.display(); - playedALegalMove=true; - } - } else { - System.out.println("Please play a piece of the right color."); - } - - if (playedALegalMove) { - if (playerColor == Piece.WHITE) { - playerColor = Piece.BLACK; - System.out.println("Black: "); - } else { - playerColor = Piece.WHITE; - System.out.println("White: "); - } - } - - } catch (NotAValidMoveException err) { - System.out.println(err); - continue; - } catch (NotAValidSquare err) { - System.out.println(err); - continue; - } catch (Exception err) { - System.out.println(err); - break; - } - } - } catch (NotAValidSquare e) { - e.printStackTrace(); - } - } + int xBoardCommand = XBoardProtocol.getCommand(whatMove); + + switch (xBoardCommand) { + case XBoardProtocol.XBOARD: + break; + case XBoardProtocol.PROTOVER: + XBoardProtocol.initialise(); + break; + case XBoardProtocol.NOT_ACCEPTED_SUICIDE: + System.out.println("tellusererror \"This game only plays suicide chess.\""); + playing=false; + break; + case XBoardProtocol.NOT_ACCEPTED_USERMOVE: + System.out.println("tellusererror \"XBoard must send moves starting with 'usermove'\""); + playing=false; + break; + case XBoardProtocol.NOPROTOVER: + System.out.println("tellusererror \"You must use an engine with XBoard protocol 2 or higher.\""); + playing=false; + break; + case XBoardProtocol.QUIT: + System.out.println("Goodbye!"); + playing=false; + break; + case XBoardProtocol.NEW: + System.out.println("variant suicide"); + break; + case XBoardProtocol.UNKNOWN: + System.out.println("Error (unknown command): "+whatMove); + break; + case XBoardProtocol.MOVE: + Move theMove = new Move(whatMove.substring(9), bitboard); -} + boolean needToCapture = false; + int foundMoveIndex = -1; + if(theMove.getMovingPiece().getColor() == currentPlayerColor) { + Rules.legalMovesForPlayer(bitboard,currentPlayerColor); + ArrayList allLegalMoves = Rules.getLegalMovesCapture(); + if (allLegalMoves.size()==0) { + allLegalMoves = Rules.getLegalMovesNonCapture(); + } else { + needToCapture = true; + } + for (int moveIndex = 0; moveIndex < allLegalMoves.size(); moveIndex++) { + if (allLegalMoves.get(moveIndex).isSimpleEqual(theMove)) { + if(theMove.isPromotionMove()&& + theMove.getPromotionPiece().getPieceNumber()!=allLegalMoves.get(moveIndex).getPromotionPiece().getPieceNumber()) { + continue; + } + foundMoveIndex=moveIndex; + break; + } + } + if (foundMoveIndex == -1) { + if (needToCapture) { + if (ASCII_GAME) + System.out.println("Capturing is mandatory."); + } + System.out.println("Illegal move: "+theMove.toString()); + } else { + bitboard.doMove(allLegalMoves.get(foundMoveIndex)); + if (ASCII_GAME) { + allLegalMoves.get(foundMoveIndex).display(); + bitboard.display(); + } + playedALegalMove=true; + } + } else { + if (ASCII_GAME) + System.out.println("Please play a piece of the right color."); + System.out.println("Illegal move: "+theMove.toString()); + } + + if (playedALegalMove) { + currentPlayerColor = Piece.BLACK; + Move computerMove = computer.doMove(bitboard); + bitboard.doMove(computerMove); + XBoardProtocol.doMove(computerMove); + if (ASCII_GAME) { + computerMove.display(); + bitboard.display(); + } + currentPlayerColor = Piece.WHITE; + if (ASCII_GAME) + System.out.println("White: "); + } + break; + } + +// if (whatMove.startsWith("hint")) { +// Rules rules = new Rules(); +// rules.legalMovesForPlayer(bitboard,currentPlayerColor); +// ArrayList allLegalMoves = rules.getLegalMovesCapture(); +// if (allLegalMoves.size()==0) { +// allLegalMoves = rules.getLegalMovesNonCapture(); +// } +// for(int i = 0; i= 2 + */ + public static final int PROTOVER = 1; + /** + * Received a 'protover' < 2 + */ + public static final int NOPROTOVER = 2; + /** + * Reveived command 'new' + */ + public static final int NEW = 3; + /** + * Reveiced command 'quit' + */ + public static final int QUIT = 4; + /** + * Received a move + */ + public static final int MOVE = 5; + /** + * Received an invalid move + */ + public static final int INVALID = 6; + /** + * XBoard did not accept sending moves with usermove + */ + public static final int NOT_ACCEPTED_USERMOVE = 9; + /** + * XBoard did not accept variant suicide chess + */ + public static final int NOT_ACCEPTED_SUICIDE = 10; + /** + * Unknown command + */ + public static final int UNKNOWN = -1; + + /** + * This function initialises the communications with XBoard. + * @throws IOException If SuicideChess.XBOARDPROTOCOL_CREATES_LOGFILE is true then the initialisation + * will create a logfile. + */ + public static void initialise() throws IOException { + //done=1 is here to tell that the program has finish requesting features + if (SuicideChess.ASCII_GAME) { + System.out.println("Welcome to SuicideChess "+SuicideChess.NAME+"!"); + System.out.println("This game was not designed to be played in console. Please use it with XBoard, WinBoard or any compatible program."); + System.out.println(); + } + System.out.println("feature myname=\"djib's Suicide Chess\""); + System.out.println("feature sigint=0 sigterm=0"); + System.out.println("feature usermove=1"); //sends moves like 'usermove e2e4' + System.out.println("feature variants=\"suicide\""); + System.out.println("feature time=0 draw=0 reuse=0 analyse=0"); + System.out.println("feature done=1"); + if (SuicideChess.ASCII_GAME) + System.out.println(); + } + + + /** + * Sends a move message to XBoard + * @param move The {@link Move} to be made + * @see Move + */ + public static void doMove(Move move) { + System.out.println("move "+move.toString()); + } + + /** + * Interprets XBoard Commands + * @param command The command to be interpreted + * @return a integer reprenting the command (se constants defined in XBoardProtocol.java + */ + + public static int getCommand(String command) { + if (command.equals("xboard")) { + return XBOARD; + } else if (command.startsWith("protover")) { + if (Integer.parseInt(command.substring(9))>=2) + return PROTOVER; + return NOPROTOVER; + } else if (command.equals("new")) { + return NEW; + } else if (command.equals("quit")) { + return QUIT; + } else if (command.startsWith("usermove")) { + return MOVE; + } else if (command.equals("rejected variants")) { + return NOT_ACCEPTED_SUICIDE; + } else if (command.equals("rejected usermove")) { + return NOT_ACCEPTED_USERMOVE; + } + + return UNKNOWN; + } + +}