From 213b1e3bf02853d6f5816bd50bccf04318ee3061 Mon Sep 17 00:00:00 2001 From: djib Date: Fri, 27 Jan 2006 23:34:09 +0000 Subject: [PATCH] v0.4.1 The computer plays with minmax and detects the end of games No known bugs --- TODO | 11 + src/suicideChess/Board.java | 26 ++- src/suicideChess/ComputerPlayer.java | 13 +- src/suicideChess/Move.java | 8 +- src/suicideChess/Rules.java | 305 +++++++++++++-------------- src/suicideChess/Square.java | 17 +- src/suicideChess/SuicideChess.java | 36 +++- src/suicideChess/XBoardProtocol.java | 2 +- 8 files changed, 225 insertions(+), 193 deletions(-) diff --git a/TODO b/TODO index 6c5cd4e..bc99dc5 100644 --- a/TODO +++ b/TODO @@ -2,3 +2,14 @@ Have a look at all the checks that are done. Add constants for useless ones. Look at what should be static + +Detect end of game. +This will be done with heuristics because number of pieces on the games will be a parameter of the heuristic function. + +Be able to let the computer play against himself. + +I haven't implemented the draw at all !!! + +Allow undo. + +Improve speed by adding a function : is there a legal move ? \ No newline at end of file diff --git a/src/suicideChess/Board.java b/src/suicideChess/Board.java index 0288421..f1df18e 100644 --- a/src/suicideChess/Board.java +++ b/src/suicideChess/Board.java @@ -31,12 +31,8 @@ public class Board { private static final int NB_OF_BITBOARDS = 14; + @SuppressWarnings("serial") public class NoPieceOnSquare extends Exception { - /* - * Added by Eclipse - */ - private static final long serialVersionUID = -2750943856086117656L; - NoPieceOnSquare(String s) { super(s); }; } @@ -88,6 +84,9 @@ public class Board { */ public Board() throws NotAValidSquare { + //the following line makes sure that enPassantSquare is defined at some point. + enPassantSquare = new Square("a1"); + bitBoards = new long[NB_OF_BITBOARDS]; addPiece(new Square("a1"),new Piece(Piece.WHITE_ROOK)); addPiece(new Square("b1"),new Piece(Piece.WHITE_KNIGHT)); @@ -141,7 +140,7 @@ public class Board { this.bitBoards[i] = bitboard.bitBoards[i]; } this.enPassant = bitboard.enPassant; - this.enPassantSquare = bitboard.enPassantSquare; + this.enPassantSquare = new Square(bitboard.enPassantSquare); } /*================* @@ -163,8 +162,6 @@ public class Board { } else { removePiece(move.toSquare(), move.getCapturedPiece()); } - //capture moves change the value of the board - evaluateNewBoardValue(move); } removePiece(move.fromSquare(), move.getMovingPiece()); if (move.isPromotionMove()) { @@ -178,8 +175,8 @@ public class Board { enPassant=true; enPassantSquare=move.getEnPassantSquare(); } - - + + evaluateNewBoardValue(move); } /** @@ -421,6 +418,15 @@ public class Board { boardValue = numberOfBlackPieces - numberOfWhitePieces; } } + if ((Rules.getLegalMovesCapture().size()==0)&&(Rules.getLegalMovesNonCapture().size()==0)) { + // The following line is NOT an error !!! + // After move from WHITE, if there is no moves for BLACK, BLACK won. + if (move.getMovingPiece().getColor()==Piece.WHITE) { + boardValue = BLACK_WINS; + } else { + boardValue = WHITE_WINS; + } + } } } \ No newline at end of file diff --git a/src/suicideChess/ComputerPlayer.java b/src/suicideChess/ComputerPlayer.java index cf98530..6b21a3e 100644 --- a/src/suicideChess/ComputerPlayer.java +++ b/src/suicideChess/ComputerPlayer.java @@ -16,13 +16,6 @@ public class ComputerPlayer { - /** - * This constructor creates a computer. - */ - public ComputerPlayer() { - //this.color = color; - } - /** * This asks the computer to compute a move * @param bitboard The current status of the {@link Board} @@ -32,7 +25,7 @@ public class ComputerPlayer { * @see Board * @see Move */ - public Move doRandomMove(Board bitboard, int color) throws NotAValidSquare { + public static Move doRandomMove(Board bitboard, int color) throws NotAValidSquare { Random generator = new Random(); Rules.legalMovesForPlayer(bitboard,color); ArrayList allLegalMoves = Rules.getLegalMovesCapture(); @@ -57,14 +50,14 @@ public class ComputerPlayer { * @see Board * @see Move */ - public Move doMinMaxMove(Board bitboard, int color) throws NotAValidSquare, NoPieceOnSquare { + public static Move doMinMaxMove(Board bitboard, int color) throws NotAValidSquare, NoPieceOnSquare { bestMove = null; MinMax(bitboard, color, 0); return bestMove; } - private int MinMax(Board bitboard, int color, int currentDepth) throws NotAValidSquare, NoPieceOnSquare { + private static int MinMax(Board bitboard, int color, int currentDepth) throws NotAValidSquare, NoPieceOnSquare { if (currentDepth >= SuicideChess.PLY_DEPTH) { return bitboard.getBoardValue(); } diff --git a/src/suicideChess/Move.java b/src/suicideChess/Move.java index bd32efe..5bbaa94 100644 --- a/src/suicideChess/Move.java +++ b/src/suicideChess/Move.java @@ -32,15 +32,11 @@ public class Move { private boolean isEnPassant=false; private Square enPassantSquare; + @SuppressWarnings("serial") public class NotAValidMoveException extends Exception { - /* - * Generated by Eclipse - */ - private static final long serialVersionUID = 2194133427162274651L; - NotAValidMoveException(String s) { super(s); }; } - + /*=============* * CONSTRUCTOR * *=============*/ diff --git a/src/suicideChess/Rules.java b/src/suicideChess/Rules.java index 3152acb..a242dc8 100644 --- a/src/suicideChess/Rules.java +++ b/src/suicideChess/Rules.java @@ -12,7 +12,7 @@ import suicideChess.Square.NotAValidSquare; */ public class Rules { - + private static ArrayList legalMovesNonCapture; private static ArrayList legalMovesCapture; @@ -66,40 +66,39 @@ public class Rules { * @see Square * @see Board */ - public static void legalMovesFromSquare(Square fromSquare, Board board) throws NotAValidSquare { + public static void legalMovesFromSquare(Square fromSquare, Board board) throws NotAValidSquare { Move validMove; - Square toSquare; - - Piece movingPiece = board.getPiece(fromSquare); - switch (movingPiece.getPieceType()) { - case Piece.NONE: - break; - case Piece.PAWN: - boolean normalMove=true; //is a normal (straight) move allowed - boolean promotion=false; - boolean bigJump=false; //if the pawn is allowed to move two squares - Square toBigJumpSquare=null; //the square for the "big jump" - - boolean captureRight=true; - boolean captureLeft=true; - Square toCaptureLeftSquare=null; - Square toCaptureRightSquare=null; + Square toSquare; + Piece movingPiece = board.getPiece(fromSquare); + switch (movingPiece.getPieceType()) { + case Piece.NONE: + break; + case Piece.PAWN: + boolean normalMove=true; //is a normal (straight) move allowed + boolean promotion=false; + boolean bigJump=false; //if the pawn is allowed to move two squares + Square toBigJumpSquare=null; //the square for the "big jump" + + boolean captureRight=true; + boolean captureLeft=true; + Square toCaptureLeftSquare=null; + Square toCaptureRightSquare=null; boolean captureEnPassantRight=board.isEnPassant(); boolean captureEnPassantLeft=board.isEnPassant(); Square captureEnPassantLeftSquare=null; Square captureEnPassantRightSquare=null; - - switch (movingPiece.getColor()) { - case Piece.WHITE: - toSquare = new Square(fromSquare.getFileNb(), fromSquare.getRank()+1); - if (fromSquare.getRank()==2) { - bigJump=true; - toBigJumpSquare = new Square(fromSquare.getFileNb(), fromSquare.getRank()+2); - } else if (toSquare.getRank()==Board.NB_OF_RANKS) { - promotion=true; - } - if(fromSquare.getFileNb()>1) { //make sure not to go out of the board + + switch (movingPiece.getColor()) { + case Piece.WHITE: + toSquare = new Square(fromSquare.getFileNb(), fromSquare.getRank()+1); + if (fromSquare.getRank()==2) { + bigJump=true; + toBigJumpSquare = new Square(fromSquare.getFileNb(), fromSquare.getRank()+2); + } else if (toSquare.getRank()==Board.NB_OF_RANKS) { + promotion=true; + } + if(fromSquare.getFileNb()>1) { //make sure not to go out of the board toCaptureLeftSquare = new Square(fromSquare.getFileNb()-1, fromSquare.getRank()+1); if(captureEnPassantLeft) { captureEnPassantLeftSquare = new Square(fromSquare.getFileNb()-1, fromSquare.getRank()); @@ -123,15 +122,15 @@ public class Rules { captureRight = false; captureEnPassantRight=false; } - break; - case Piece.BLACK: - toSquare = new Square(fromSquare.getFileNb(), fromSquare.getRank()-1); - if (fromSquare.getRank()==(Board.NB_OF_RANKS-1)) { - bigJump=true; - toBigJumpSquare = new Square(fromSquare.getFileNb(), fromSquare.getRank()-2); - } else if (toSquare.getRank()==1) { - promotion=true; - } + break; + case Piece.BLACK: + toSquare = new Square(fromSquare.getFileNb(), fromSquare.getRank()-1); + if (fromSquare.getRank()==(Board.NB_OF_RANKS-1)) { + bigJump=true; + toBigJumpSquare = new Square(fromSquare.getFileNb(), fromSquare.getRank()-2); + } else if (toSquare.getRank()==1) { + promotion=true; + } if(fromSquare.getFileNb()>1) { //make sure not to go out of the board toCaptureLeftSquare = new Square(fromSquare.getFileNb()-1, fromSquare.getRank()-1); if(captureEnPassantLeft) { @@ -156,89 +155,89 @@ public class Rules { captureRight = false; captureEnPassantRight=false; } - break; + break; default: throw new RuntimeException("ERROR 01."); - } - if (board.getPiece(toSquare).getPieceNumber()!=Piece.NONE) { - normalMove= false; //cannot move forward if there is a piece + } + if (board.getPiece(toSquare).getPieceNumber()!=Piece.NONE) { + normalMove= false; //cannot move forward if there is a piece bigJump=false; - } - if (captureLeft&& + } + if (captureLeft&& ((board.getPiece(toCaptureLeftSquare).getColor()==Piece.NO_COLOR) - || (board.getPiece(toCaptureLeftSquare).getColor()==movingPiece.getColor()))) { - captureLeft = false; - } + || (board.getPiece(toCaptureLeftSquare).getColor()==movingPiece.getColor()))) { + captureLeft = false; + } if (captureRight&& ((board.getPiece(toCaptureRightSquare).getColor()==Piece.NO_COLOR) - || (board.getPiece(toCaptureRightSquare).getColor()==movingPiece.getColor()))) { - captureRight = false; - } - if (bigJump && (board.getPiece(toBigJumpSquare).getPieceNumber()!=Piece.NONE)) { - bigJump=false; - } - if (promotion) { - if (normalMove) { - //to Queen - validMove = new Move(fromSquare, toSquare, movingPiece, new Piece(Piece.NONE), new Piece(Piece.QUEEN_CHAR, movingPiece.getColor())); - legalMovesNonCapture.add(validMove); - //to King - validMove = new Move(fromSquare, toSquare, movingPiece, new Piece(Piece.NONE), new Piece(Piece.KING_CHAR, movingPiece.getColor())); - legalMovesNonCapture.add(validMove); - //to Bishop - validMove = new Move(fromSquare, toSquare, movingPiece, new Piece(Piece.NONE), new Piece(Piece.BISHOP_CHAR, movingPiece.getColor())); - legalMovesNonCapture.add(validMove); + || (board.getPiece(toCaptureRightSquare).getColor()==movingPiece.getColor()))) { + captureRight = false; + } + if (bigJump && (board.getPiece(toBigJumpSquare).getPieceNumber()!=Piece.NONE)) { + bigJump=false; + } + if (promotion) { + if (normalMove) { + //to Queen + validMove = new Move(fromSquare, toSquare, movingPiece, new Piece(Piece.NONE), new Piece(Piece.QUEEN_CHAR, movingPiece.getColor())); + legalMovesNonCapture.add(validMove); + //to King + validMove = new Move(fromSquare, toSquare, movingPiece, new Piece(Piece.NONE), new Piece(Piece.KING_CHAR, movingPiece.getColor())); + legalMovesNonCapture.add(validMove); + //to Bishop + validMove = new Move(fromSquare, toSquare, movingPiece, new Piece(Piece.NONE), new Piece(Piece.BISHOP_CHAR, movingPiece.getColor())); + legalMovesNonCapture.add(validMove); //to Knight validMove = new Move(fromSquare, toSquare, movingPiece, new Piece(Piece.NONE), new Piece(Piece.KNIGHT_CHAR, movingPiece.getColor())); legalMovesNonCapture.add(validMove); - //to Rook - validMove = new Move(fromSquare, toSquare, movingPiece, new Piece(Piece.NONE), new Piece(Piece.ROOK_CHAR, movingPiece.getColor())); - legalMovesNonCapture.add(validMove); - } - if (captureLeft) { - //to Queen - validMove = new Move(fromSquare, toCaptureLeftSquare, movingPiece, board.getPiece(toCaptureLeftSquare), new Piece(Piece.QUEEN_CHAR, movingPiece.getColor())); - legalMovesCapture.add(validMove); - //to King - validMove = new Move(fromSquare, toCaptureLeftSquare, movingPiece, board.getPiece(toCaptureLeftSquare), new Piece(Piece.KING_CHAR, movingPiece.getColor())); - legalMovesCapture.add(validMove); - //to Bishop - validMove = new Move(fromSquare, toCaptureLeftSquare, movingPiece, board.getPiece(toCaptureLeftSquare), new Piece(Piece.BISHOP_CHAR, movingPiece.getColor())); - legalMovesCapture.add(validMove); + //to Rook + validMove = new Move(fromSquare, toSquare, movingPiece, new Piece(Piece.NONE), new Piece(Piece.ROOK_CHAR, movingPiece.getColor())); + legalMovesNonCapture.add(validMove); + } + if (captureLeft) { + //to Queen + validMove = new Move(fromSquare, toCaptureLeftSquare, movingPiece, board.getPiece(toCaptureLeftSquare), new Piece(Piece.QUEEN_CHAR, movingPiece.getColor())); + legalMovesCapture.add(validMove); + //to King + validMove = new Move(fromSquare, toCaptureLeftSquare, movingPiece, board.getPiece(toCaptureLeftSquare), new Piece(Piece.KING_CHAR, movingPiece.getColor())); + legalMovesCapture.add(validMove); + //to Bishop + validMove = new Move(fromSquare, toCaptureLeftSquare, movingPiece, board.getPiece(toCaptureLeftSquare), new Piece(Piece.BISHOP_CHAR, movingPiece.getColor())); + legalMovesCapture.add(validMove); //to Knight validMove = new Move(fromSquare, toCaptureLeftSquare, movingPiece, board.getPiece(toCaptureLeftSquare), new Piece(Piece.KNIGHT_CHAR, movingPiece.getColor())); legalMovesCapture.add(validMove); - //to Rook - validMove = new Move(fromSquare, toCaptureLeftSquare, movingPiece, board.getPiece(toCaptureLeftSquare), new Piece(Piece.ROOK_CHAR, movingPiece.getColor())); - legalMovesCapture.add(validMove); - } - if (captureRight) { - //to Queen - validMove = new Move(fromSquare, toCaptureRightSquare, movingPiece, board.getPiece(toCaptureRightSquare), new Piece(Piece.QUEEN_CHAR, movingPiece.getColor())); - legalMovesCapture.add(validMove); - //to King - validMove = new Move(fromSquare, toCaptureRightSquare, movingPiece, board.getPiece(toCaptureRightSquare), new Piece(Piece.KING_CHAR, movingPiece.getColor())); - legalMovesCapture.add(validMove); - //to Knight - validMove = new Move(fromSquare, toCaptureRightSquare, movingPiece, board.getPiece(toCaptureRightSquare), new Piece(Piece.KNIGHT_CHAR, movingPiece.getColor())); - legalMovesCapture.add(validMove); - //to Bishop - validMove = new Move(fromSquare, toCaptureRightSquare, movingPiece, board.getPiece(toCaptureRightSquare), new Piece(Piece.BISHOP_CHAR, movingPiece.getColor())); - legalMovesCapture.add(validMove); - //to Rook - validMove = new Move(fromSquare, toCaptureRightSquare, movingPiece, board.getPiece(toCaptureRightSquare), new Piece(Piece.ROOK_CHAR, movingPiece.getColor())); - legalMovesCapture.add(validMove); - } - } else { - if (normalMove) { - validMove = new Move(fromSquare, toSquare, movingPiece, new Piece(Piece.NONE), new Piece(Piece.NONE)); - legalMovesNonCapture.add(validMove); - } - if (bigJump) { - //create an 'en-passant' status + //to Rook + validMove = new Move(fromSquare, toCaptureLeftSquare, movingPiece, board.getPiece(toCaptureLeftSquare), new Piece(Piece.ROOK_CHAR, movingPiece.getColor())); + legalMovesCapture.add(validMove); + } + if (captureRight) { + //to Queen + validMove = new Move(fromSquare, toCaptureRightSquare, movingPiece, board.getPiece(toCaptureRightSquare), new Piece(Piece.QUEEN_CHAR, movingPiece.getColor())); + legalMovesCapture.add(validMove); + //to King + validMove = new Move(fromSquare, toCaptureRightSquare, movingPiece, board.getPiece(toCaptureRightSquare), new Piece(Piece.KING_CHAR, movingPiece.getColor())); + legalMovesCapture.add(validMove); + //to Knight + validMove = new Move(fromSquare, toCaptureRightSquare, movingPiece, board.getPiece(toCaptureRightSquare), new Piece(Piece.KNIGHT_CHAR, movingPiece.getColor())); + legalMovesCapture.add(validMove); + //to Bishop + validMove = new Move(fromSquare, toCaptureRightSquare, movingPiece, board.getPiece(toCaptureRightSquare), new Piece(Piece.BISHOP_CHAR, movingPiece.getColor())); + legalMovesCapture.add(validMove); + //to Rook + validMove = new Move(fromSquare, toCaptureRightSquare, movingPiece, board.getPiece(toCaptureRightSquare), new Piece(Piece.ROOK_CHAR, movingPiece.getColor())); + legalMovesCapture.add(validMove); + } + } else { + if (normalMove) { + validMove = new Move(fromSquare, toSquare, movingPiece, new Piece(Piece.NONE), new Piece(Piece.NONE)); + legalMovesNonCapture.add(validMove); + } + if (bigJump) { + //create an 'en-passant' status validMove = new Move(fromSquare, toBigJumpSquare, toSquare, movingPiece, false); - legalMovesNonCapture.add(validMove); - } + legalMovesNonCapture.add(validMove); + } if (captureEnPassantLeft) { //create an 'en-passant' move validMove = new Move(fromSquare, toCaptureLeftSquare, captureEnPassantLeftSquare, movingPiece, true); @@ -249,51 +248,52 @@ public class Rules { validMove = new Move(fromSquare, toCaptureRightSquare, captureEnPassantRightSquare, movingPiece, true); legalMovesCapture.add(validMove); } - + if (captureLeft) { - validMove = new Move(fromSquare, toCaptureLeftSquare, movingPiece, board.getPiece(toCaptureLeftSquare), new Piece(Piece.NONE)); - legalMovesCapture.add(validMove); - } - if (captureRight) { - validMove = new Move(fromSquare, toCaptureRightSquare, movingPiece, board.getPiece(toCaptureRightSquare), new Piece(Piece.NONE)); - legalMovesCapture.add(validMove); - } - } - - break; - default: - //look for all valid moves - for (int ray=0; - ray of all legal {@link Move} @@ -4843,7 +4843,6 @@ public class Rules { movesAllowed[Piece.QUEEN][ 45 ][ 2 ][ 4 ] = 5; movesAllowed[Piece.QUEEN][ 45 ][ 3 ][ 0 ] = 53; movesAllowed[Piece.QUEEN][ 45 ][ 3 ][ 1 ] = 61; - movesAllowed[Piece.QUEEN][ 45 ] = new int[ 8 ][]; movesAllowed[Piece.QUEEN][ 45 ][ 4 ] = new int[ 5 ]; movesAllowed[Piece.QUEEN][ 45 ][ 5 ] = new int[ 2 ]; movesAllowed[Piece.QUEEN][ 45 ][ 6 ] = new int[ 2 ]; diff --git a/src/suicideChess/Square.java b/src/suicideChess/Square.java index 5fd36db..dc849df 100644 --- a/src/suicideChess/Square.java +++ b/src/suicideChess/Square.java @@ -13,12 +13,8 @@ public class Square { private int fileNb; private int rank; - public class NotAValidSquare extends Exception { - /* - * Generated by Eclipse - */ - private static final long serialVersionUID = 7586171991212094565L; - + @SuppressWarnings("serial") + public class NotAValidSquare extends Exception { NotAValidSquare(String s) { super(s); }; } @@ -46,6 +42,15 @@ public class Square { } } } + + /** + * Constructs a Square by copying another square + */ + public Square(Square square) { + this.file = square.file; + this.fileNb = square.fileNb; + this.rank = square.rank; + } /** * Construcs a Square given a bitboard square (number from 0 to 63) diff --git a/src/suicideChess/SuicideChess.java b/src/suicideChess/SuicideChess.java index 709596d..d4bdfc5 100644 --- a/src/suicideChess/SuicideChess.java +++ b/src/suicideChess/SuicideChess.java @@ -65,6 +65,23 @@ public class SuicideChess { } } + /** + * 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 @@ -95,7 +112,6 @@ public class SuicideChess { System.out.println("White: "); } - ComputerPlayer computer = new ComputerPlayer(); boolean computerPlaying = true; //the computer does not play in foce mode. boolean playing = true; @@ -132,7 +148,7 @@ public class SuicideChess { System.out.println("variant suicide"); break; case XBoardProtocol.HINT: - System.out.println("Hint: "+computer.doRandomMove(bitboard,currentPlayerColor)); + System.out.println("Hint: "+ComputerPlayer.doRandomMove(bitboard,currentPlayerColor)); break; case XBoardProtocol.FORCE: computerPlaying = false; @@ -193,6 +209,10 @@ public class SuicideChess { System.out.println("Illegal move: "+theMove.toString()); } + if (testWinningPosition(bitboard)) { + computerPlaying=false; + } + if (!playedALegalMove) { break; } @@ -205,7 +225,7 @@ public class SuicideChess { if (xBoardCommand==XBoardProtocol.GO) computerPlaying = true; if (computerPlaying) { - Move computerMove = computer.doMinMaxMove(bitboard,currentPlayerColor); + Move computerMove = ComputerPlayer.doMinMaxMove(bitboard,currentPlayerColor); bitboard.doMove(computerMove); XBoardProtocol.doMove(computerMove); if (ASCII_GAME) { @@ -215,8 +235,11 @@ public class SuicideChess { } changeCurrentPlayerColor(); } + if (testWinningPosition(bitboard)) { + computerPlaying=false; + } + break; - } // if (whatMove.startsWith("hint")) { @@ -255,9 +278,8 @@ public class SuicideChess { } catch (NotAValidSquare err) { System.out.println(err); continue; - } catch (Exception err) { - System.out.println(err); - break; + } catch (Exception e) { + e.printStackTrace(); } } } diff --git a/src/suicideChess/XBoardProtocol.java b/src/suicideChess/XBoardProtocol.java index 4a87d18..24a5c0c 100644 --- a/src/suicideChess/XBoardProtocol.java +++ b/src/suicideChess/XBoardProtocol.java @@ -78,7 +78,7 @@ public class XBoardProtocol { 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 colors=0"); + System.out.println("feature time=0 draw=0 reuse=0 analyze=0 colors=0"); System.out.println("feature done=1"); if (SuicideChess.ASCII_GAME) System.out.println();