Simple Java Chess game API.
The goal is to provide a simple, easy-to-use API to manipulate chess games in Java. It is also easy to extend in order to create extended chess rules, new pieces and so on.
This project does NOT provide any chess engine for position analysis. However, it could be very easily used by another API to do such task.
This API is compiled with the JDK 11.
The main features of this API are:
- Ease of use
- Standard chess rules
- Algebraic notation
- Custom positions
- PGN import
- PGN export
- Game metadata
- ASCII rendering
Use the following dependency in your pom.xml
:
<dependency>
<groupId>ch.astorm</groupId>
<artifactId>jchess</artifactId>
<version>1.2.0</version>
</dependency>
A standard chess game can be very easily created:
//new chess game with standard board and rules
JChessGame game = JChessGame.newGame();
//apply the move to the game
game.play("e4");
//cancel the last move
game.back();
//moves can be played altogether
game.play("e4","e5","Nf3","Nc6","Bb5","a6","Ba4","Nf6","O-O","Be7",
"Re1","b5","Bb3","d6","c3","O-O","h3","Nb8","d4","Nbd7",
"c4","c6","cxb5","axb5","Nc3","Bb7","Bg5","b4","Nb1","h6",
"Bh4","c5","dxe5","Nxe4","Bxe7","Qxe7","exd6","Qf6","Nbd2","Nxd6",
"Nc4","Nxc4","Bxc4","Nb6","Ne5","Rae8","Bxf7+","Rxf7","Nxf7","Rxe1+",
"Qxe1","Kxf7","Qe3","Qg5","Qxg5","hxg5","b3","Ke6","a3","Kd6",
"axb4","cxb4","Ra5","Nd5","f3","Bc8","Kf2","Bf5","Ra7","g6",
"Ra6+","Kc5","Ke1","Nf4","g3","Nxh3","Kd2","Kb5","Rd6","Kc5",
"Ra6","Nf2","g4","Bd3","Re6");
//agree to a draw
game.draw();
//prints the final position (white is on the bottom)
ASCIIPositionRenderer.render(System.out, game.getPosition(), Color.WHITE);
Here are some usages about specific parts of the API.
The main entry point is the JChessGame class that will handle the global game.
The creation of a new game is straightforward:
JChessGame game = JChessGame.newGame();
Once the game is created, it has already the standard chess rules and the initial position built in. Hence, the game is ready and White is on move.
The current Position of a game can be explored with various methods.
Position position = game.getPosition();
//get the positions of all the moveable entities in the position
Map<Coordinate, Moveable> moveables = position.getMoveables();
//get all the white entities in the position
List<Moveable> whiteMoveables = position.getMoveables(Color.WHITE);
//find the location of the white's king
Coordinate kingLocation = position.findLocation(King.class, Color.WHITE);
//get the moveable entity in b1
Moveable moveableAtLocation = position.get("b1");
//set the moveable entity in e5
position.put("e5", new Rook(Color.BLACK));
In some cases, one may want to set a custom position to start.
JChessGame game = JChessGame.newEmptyGame(Color.WHITE);
game.put("a1", new King(Color.WHITE));
game.put("h8", new King(Color.BLACK));
The example below creates a new game with only the two kings and White is on move.
It is possible to put some position without any king on the board. If there is no
king, then the status of the game will remain Status.NOT_FINISHED
.
Note that it is not possible to put multiple kings of the same color on the board.
It is very easy to retrieve all the legal moves in a position for the color on move:
List<Move> legalMoves = game.getAvailableMoves();
If the position is known, the API allows to get the legal moves from a given location:
List<Move> legalMoves = game.getAvailableMoves("c3");
It is also possible to retrieve the legal moves for a given entity:
Position position = game.getPosition();
Coordinate kingCoordinate = position.findLocation(King.class, Color.WHITE);
Moveable king = position.get(kingCoordinate);
List<Move> kingMoves = game.getAvailableMoves(king);
The method getColorOnMove()
can be used to know which color is on move. It is also possible
to switch it to the other one:
JChessGame game = JChessGame.newGame();
game.switchColorOnMove();
//black has the move
game.play("e5");
To play the moves in the game, it is recommanded to use directly the JChessGame
because
they read the algebraic notation
to update the position.
JChessGame game = JChessGame.newGame();
game.play("e4"); //white plays e4
game.play("e5"); //black plays e5
//moves can be grouped together and they will be played in alternance
game.play("Nc3","e6");
Each move will update the current position and automatically switch the Color
being on the move.
It is possible to go back in the moves by using the game.back()
methods.
Move lastMove = game.back(); //drop the last move
List<Move> lastMoves = game.back(3); //drop the last 3 moves (if possible)
You may want to access a possible move in the position without actually playing it:
Move move1 = game.getMove("Nxd4");
Move move2 = game.getMove("d8=Q");
After each move, one can retrieve the game status that can be one of the following values:
Status | Description | Continue |
---|---|---|
NOT_FINISHED |
The game is not finished. | Yes |
WIN_WHITE |
The whites have won. | No |
WIN_BLACK |
The blacks have won. | No |
DRAW |
The game is draw either by agreement (see JChessGame.draw() ) or by insufficiant material. |
Yes |
DRAW_STALEMATE |
The game is a draw by stalemate. One of the player has no legal move that does not put his king in check. | No |
DRAW_REPETITION |
The game is a draw by repeating the same position 5 times. | No |
DRAW_NOCAPTURE |
The game is a draw by playing 75 moves without any capture nor pawn move. | No |
It is possible to continue to play even if the status is DRAW
because it is generally not enforced to stop
(see dead positions).
The status can simply be retrieved after any move with the code below:
Status status = game.getStatus();
The easy way to get the captured pieces of a game is simple to use the JChessGame.getCaptured
method:
JChessGame game = JChessGame.newGame();
game.play("e4", "d5", "exd5");
game.getCaptured(Color.WHITE); //empty
game.getCaptured(Color.BLACK); //contains 1 Pawn entity
It is possible to import basic PGN files
as JChessGame
. Note that the API does not support extended PGN with remarks and deviations.
try(PGNReader pgnReader = new PGNReader(/* reader */) {
JChessGame game = pgnReader.readGame();
while(game!=null) {
/* handle game */
//read next game, if any
game = pgnReader.readGame();
}
}
Note: the PGN format uses ISO-8859-1
encoding.
Once a JChessGame
has been created, the PGN export is straightforward and can
export multiple games.
try(PGNWriter pgnWriter = new PGNWriter(/* writer */)) {
pgnWriter.write(game1);
pgnWriter.write(game2);
pgnWriter.write(game3);
}
The PGN parser supports metadata. This is simply a list of key/value pairs that are stored during the parsing of the file.
JChessGame game = pgnReader.readGame();
Map<String,String> metadata = game.getMetadata();
String result = metadata.get("Result");
Mainly for debug purposes, jchess provides a simple API to print a position in CLI:
The unicode renderer's output is compact but does not support showing which cells are dark or light when they are not empty.
JChessGame game = JChessGame.newGame();
UnicodePositionRenderer.render(System.out, game.getPosition());
JChessGame game = JChessGame.newGame();
game.play("e4", "g6", "Nf3", "Bg7", "d4", "a5", "b3");
ASCIIPositionRenderer.render(System.out, game.getPosition(), Color.WHITE);
The result will look like this:
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
: ::::::::: _ :::www::: _+_ ::::::::: ::::::::::
_ : |=|=| :: _,, :: (/) :::)#(::: )#( ::::::::: _,, ::|=|=|:::
(_) : |#| ::"- \~:: |#| :::|#|::: |#| ::::::::: "- \~ :::|#|::::
(_) : |#| :::|#|::: |#| :::|#|::: |#| ::::::::: |#| :::|#|::::
: /###\ ::/###\:: /###\ ::/###\:: /###\ ::::::::: /###\ ::/###\:::
:::::::::: ::::::::: ::::::::: ::::_:::: :
__ :::::::::: () ::::()::: () ::::()::: () :::(/)::: () :
/ :::::::::: )( ::::)(::: )( ::::)(::: )( :::|#|::: )( :
/ :::::::::: /##\ :::/##\:: /##\ :::/##\:: /##\ :::|#|::: /##\ :
:::::::::: ::::::::: ::::::::: ::/###\:: :
: ::::::::: ::::::::: ::::::::: ::::::::::
: ::::::::: ::::::::: ::::::::: () ::::::::::
/ : ::::::::: ::::::::: ::::::::: )( ::::::::::
(_) : ::::::::: ::::::::: ::::::::: /##\ ::::::::::
: ::::::::: ::::::::: ::::::::: ::::::::::
:::::::::: ::::::::: ::::::::: ::::::::: :
_ :::::()::: ::::::::: ::::::::: ::::::::: :
|_ :::::)(::: ::::::::: ::::::::: ::::::::: :
_) ::::/##\:: ::::::::: ::::::::: ::::::::: :
:::::::::: ::::::::: ::::::::: ::::::::: :
: ::::::::: ::::::::: ::::::::: ::::::::::
. : ::::::::: ::::()::: () ::::::::: ::::::::::
/| : ::::::::: ::::)(::: )( ::::::::: ::::::::::
'-| : ::::::::: :::/__\:: /__\ ::::::::: ::::::::::
: ::::::::: ::::::::: ::::::::: ::::::::::
:::::::::: ::::::::: ::::::::: ::::::::: :
_ :::::::::: () ::::::::: ::::::::: _,, ::::::::: :
_) :::::::::: )( ::::::::: ::::::::: "- \~ ::::::::: :
_) :::::::::: /__\ ::::::::: ::::::::: | | ::::::::: :
:::::::::: ::::::::: ::::::::: /___\ ::::::::: :
: ::::::::: ::::::::: ::::::::: ::::::::::
_ : () ::::::::: () ::::::::: ::::()::: () ::::()::::
) : )( ::::::::: )( ::::::::: ::::)(::: )( ::::)(::::
/_ : /__\ ::::::::: /__\ ::::::::: :::/__\:: /__\ :::/__\:::
: ::::::::: ::::::::: ::::::::: ::::::::::
:::::::::: ::::_:::: www :::_+_::: _ ::::::::: :
:::|_|_|:: _,, :::(/)::: ) ( :::) (::: (/) ::::::::: |_|_| :
/| ::::| |::: "- \~ :::| |::: | | :::| |::: | | ::::::::: | | :
| ::::| |::: | | :::| |::: | | :::| |::: | | ::::::::: | | :
:::/___\:: /___\ ::/___\:: /___\ ::/___\:: /___\ ::::::::: /___\ :
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
_ _ _ __ __ _
/\ |_) / | \ |_ |_ / |_|
/--\ |_) \_ |_/ |__ | \_? | |
The ASCIIPositionRenderer class can be used to render different styles in ASCII.
The standard maven command applies. However, since the tests are time-consuming, you might want to skip them.
mvn clean package -DskipTests
This project is completely developed during my spare time.
Since I'm a big fan of cryptocurrencies and especially Cardano (ADA), you can send me some coins at the address below (check it here):
addr1q9sgms4vc038nq7hu4499yeszy0rsq3hjeu2k9wraksle8arg0n953hlsrtdzpfnxxw996l4t6qu5xsx8cmmakjcqhksaqpj66