package suicideChess; import java.io.BufferedReader; import java.io.InputStreamReader; import java.util.ArrayList; import suicideChess.Move.NotAValidMoveException; import suicideChess.Square.NotAValidSquare; /** * Main file (the game in itself) * @author Jean-Baptiste Hétier * @version $LastChangedRevision$, $LastChangedDate$ */ 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; /** * The name to be displayed */ public static final String NAME = "djib's SuShi v0.5.2"; /** * Displays informations in the console. */ public static final boolean ASCII_GAME = true; /** * Number of Plies the computes searches to */ public static final int PLY_DEPTH = 4; /** * Test and display if the board is in a winning state. * @param bitboard A Board * @return True or False */ private static boolean testWinningPosition (Board bitboard) { if (bitboard.getBoardValue()==Board.BLACK_WINS) { System.out.println("0-1 {Black mates}"); return true; } else if (bitboard.getBoardValue()==Board.WHITE_WINS) { System.out.println("1-0 {White mates}"); return true; } return false; } /** * If feature usermove has not been accepted by XBoard then consider all unknown commands * as moves */ private static boolean acceptedUsermove = false; /** * This array is used for undo purposes. Positions are sorted from last to first. */ private static ArrayList allPlayedPositions = new ArrayList(); /** * This function is used to add a new position to the list of all positions * @param position A {@link Board} * @see Board */ private static void addPlayedPosition (Board position) { allPlayedPositions.add(0,new Board(position)); } /** * This function is used to undo the last position played */ private static Board removePlayedPosition () { allPlayedPositions.remove(0); return allPlayedPositions.get(0); } /** * This variable says whether the computer should display a "thinking output" */ private static boolean post = true; /** * Should computer display thinking output or not ? * @return boolean */ public static boolean postThinkingOutput() { return post; } /** * The main function * @param args No parameters should be transmitted to this function. * @throws NotAValidSquare */ public static void main(String[] args) throws NotAValidSquare { System.out.println("Welcome to SuicideChess "+SuicideChess.NAME+"!"); if (!SuicideChess.ASCII_GAME) { 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(); BufferedReader moveInput = new BufferedReader(new InputStreamReader(System.in)); Board bitboard = new Board(); addPlayedPosition(bitboard); if (ASCII_GAME) { bitboard.display(); System.out.println("White: "); } boolean computerPlaying = true; //the computer does not play in foce mode. boolean playing = true; while (playing) { try { String whatMove= moveInput.readLine(); boolean playedALegalMove = false; 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.ACCEPTED_USERMOVE: acceptedUsermove=true; 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.HINT: System.out.println("Hint: "+ComputerPlayer.doRandomMove(bitboard)); break; case XBoardProtocol.FORCE: computerPlaying = false; break; case XBoardProtocol.PING: System.out.println("pong "+whatMove.substring(5)); break; case XBoardProtocol.REMOVE: removePlayedPosition(); //no break here case XBoardProtocol.UNDO: bitboard=new Board(removePlayedPosition()); if (ASCII_GAME) { bitboard.display(); } break; case XBoardProtocol.POST: post=true; break; case XBoardProtocol.NOPOST: post=false; break; case XBoardProtocol.SETBOARD: bitboard=new Board(whatMove.substring(9)); if(ASCII_GAME) bitboard.display(); break; case XBoardProtocol.UNKNOWN: if (acceptedUsermove) { System.out.println("Error (unknown command): "+whatMove); break; } //if XBoard did not accept usermove command we try and interpret every unknown command //as a move. case XBoardProtocol.MOVE: Move theMove; if (acceptedUsermove) { theMove = new Move(whatMove.substring(9), bitboard); } else { theMove = new Move(whatMove, bitboard); } if (testWinningPosition(bitboard)) { //if board was set in an illegal position System.out.println("Illegal move: "+theMove.toString()); break; } boolean needToCapture = false; int foundMoveIndex = -1; if(theMove.getMovingPiece().getColor() == bitboard.getCurrentPlayer()) { Rules.legalMovesForPlayer(bitboard); 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)); addPlayedPosition(bitboard); if (ASCII_GAME) { allLegalMoves.get(foundMoveIndex).display(); System.out.println("Board value: "+bitboard.getBoardValue()); 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 (testWinningPosition(bitboard)) { computerPlaying=false; } if (!playedALegalMove) { break; } //No break statement here on purpose. case XBoardProtocol.GO: //this is not really nice but it avoids having to write twice the code //I check if I did really receive a XBoardProtocol.GO or it I just got there //because there is no break statement. if (xBoardCommand==XBoardProtocol.GO) computerPlaying = true; if (testWinningPosition(bitboard)) { //in case an illegal position have been sent computerPlaying=false; break; } if (computerPlaying) { Move computerMove = ComputerPlayer.doAlphaBetaMove(bitboard); bitboard.doMove(computerMove); addPlayedPosition(bitboard); XBoardProtocol.doMove(computerMove); if (ASCII_GAME) { computerMove.display(); System.out.println("Board value: "+bitboard.getBoardValue()); bitboard.display(); } } if (testWinningPosition(bitboard)) { computerPlaying=false; } 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