{"id":42969371,"url":"https://github.com/bhlangonijr/chesslib","last_synced_at":"2026-01-31T00:22:48.769Z","repository":{"id":44938422,"uuid":"61509385","full_name":"bhlangonijr/chesslib","owner":"bhlangonijr","description":"chess library for legal move generation, FEN/PGN parsing and more","archived":false,"fork":false,"pushed_at":"2026-01-10T17:55:30.000Z","size":2927,"stargazers_count":273,"open_issues_count":18,"forks_count":83,"subscribers_count":16,"default_branch":"master","last_synced_at":"2026-01-11T05:23:18.106Z","etag":null,"topics":["chess-legal-moves","chess-library","chessboard","fen","java","pgn"],"latest_commit_sha":null,"homepage":"","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/bhlangonijr.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2016-06-20T01:44:34.000Z","updated_at":"2026-01-10T17:55:34.000Z","dependencies_parsed_at":"2024-09-18T03:36:23.169Z","dependency_job_id":null,"html_url":"https://github.com/bhlangonijr/chesslib","commit_stats":null,"previous_names":[],"tags_count":38,"template":false,"template_full_name":null,"purl":"pkg:github/bhlangonijr/chesslib","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bhlangonijr%2Fchesslib","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bhlangonijr%2Fchesslib/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bhlangonijr%2Fchesslib/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bhlangonijr%2Fchesslib/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/bhlangonijr","download_url":"https://codeload.github.com/bhlangonijr/chesslib/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bhlangonijr%2Fchesslib/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28924542,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-30T22:32:35.345Z","status":"ssl_error","status_checked_at":"2026-01-30T22:32:31.927Z","response_time":66,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["chess-legal-moves","chess-library","chessboard","fen","java","pgn"],"created_at":"2026-01-31T00:22:48.690Z","updated_at":"2026-01-31T00:22:48.749Z","avatar_url":"https://github.com/bhlangonijr.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"Simple Java Chess Library\n=========================\n\n[![](https://jitpack.io/v/bhlangonijr/chesslib.svg)](https://jitpack.io/#bhlangonijr/chesslib) ![mvn build](https://github.com/bhlangonijr/chesslib/actions/workflows/maven.yml/badge.svg)\n\n\nChesslib is a simple java chess library for generating\nlegal chess moves given a chessboard [position](https://en.wikipedia.org/wiki/Chess#Setup),\nparse a chess game stored in [PGN](https://en.wikipedia.org/wiki/Portable_Game_Notation) or [FEN](https://en.wikipedia.org/wiki/Forsyth–Edwards_Notation) format and many other things.\n\n# Table of Contents\n\n1. [Building/Installing](#Building)\n2. [Usage](#Usage)\n3. [Create a chessboard and make a move](#Create_a_chessboard_and_make_a_move)\n4. [Undo a move](#Undo_a_move)\n5. [Get FEN string from chessboard](#Get_FEN_string_from_chessboard)\n6. [Load a chessboard position from FEN notation](#Load_a_chessboard_position_from_notation)\n7. [MoveList](#MoveList)\n8. [Generate all chess legal-moves for the current position](#Generate_all_chess_legal_moves_for_the_current_position)\n9. [Checking chessboard situation](#Checking_chessboard_situation)\n10. [Comparing boards](#Comparing_boards)\n11. [Load a chess game collection from a file](#Load_a_chess_game_collection_from_a_PGN_file)\n12. [Advanced usage](#Advanced_usage)\n13. [Sanity checking of chesslib move generation with Perft](#Sanity_checking_of_chesslib_move_generation_with_Perft)\n14. [Creating a full-fledged chess engine](#Creating_a_full_fledged_chess_engine)\n15. [Capturing and reacting to events](#Capturing_and_reacting_to_events)\n\n# \u003ca name=\"Building\"\u003e\u003c/a\u003e Building/Installing\n## From source\n\n```\n$ git clone git@github.com:bhlangonijr/chesslib.git\n$ cd chesslib/\n$ mvn clean compile package install\n```\n\n## From repo\n\nChesslib dependency can be added via the jitpack repository.\n\n## Maven\n\n```xml\n\u003crepositories\u003e\n  ...\n  \u003crepository\u003e\n    \u003cid\u003ejitpack.io\u003c/id\u003e\n    \u003curl\u003ehttps://jitpack.io\u003c/url\u003e\n  \u003c/repository\u003e\n\u003c/repositories\u003e\n```\n\n```xml\n\u003cdependency\u003e\n  \u003cgroupId\u003ecom.github.bhlangonijr\u003c/groupId\u003e\n  \u003cartifactId\u003echesslib\u003c/artifactId\u003e\n  \u003cversion\u003e1.3.4\u003c/version\u003e\n\u003c/dependency\u003e\n```\n\n## Gradle\n\n```groovy\nrepositories {\n    ...\n    maven { url 'https://jitpack.io' }\n}\n```\n\n```groovy\ndependencies {\n    ...\n    compile 'com.github.bhlangonijr:chesslib:1.3.4'\n    ...\n}\n```\n\n# \u003ca name=\"Usage\"\u003e\u003c/a\u003e Usage\n\n## \u003ca name=\"Create_a_chessboard_and_make_a_move\"\u003e\u003c/a\u003e Create a chessboard and make a move\n\n```java\n    // Creates a new chessboard in the standard initial position\n    Board board = new Board();\n\n    //Make a move from E2 to E4 squares\n    board.doMove(new Move(Square.E2, Square.E4));\n\n    //print the chessboard in a human-readable form\n    System.out.println(board.toString());\n```\n\nAlternatively one could just specify the move using SAN, e.g.:\n```java\n    Board board = new Board();\n    board.doMove(\"e4\");\n```\n\nResult:\n```text\nrnbqkbnr\npppppppp\n\n\n    P\n\nPPPP PPP\nRNBQKBNR\nSide: BLACK\n```\n## \u003ca name=\"Undo_a_move\"\u003e\u003c/a\u003e Undo a move\n\n```java\n    // Undo the last move from the stack and return it\n    Move move = board.undoMove();\n```\n\n## \u003ca name=\"Get_FEN_string_from_chessboard\"\u003e\u003c/a\u003e Get FEN string from chessboard\n\n```java\n    System.out.println(board.getFen());\n```\n\n## \u003ca name=\"Load_a_chessboard_position_from_notation\"\u003e\u003c/a\u003e Load a chessboard position from [FEN](https://en.wikipedia.org/wiki/Forsyth–Edwards_Notation) notation\n\n```java\n    // Load a FEN position into the chessboard\n    String fen = \"rnbqkbnr/pppppppp/8/8/4P3/8/PPPP1PPP/RNBQKBNR b KQkq e3 0 1\";\n    Board board = new Board();\n    board.loadFromFen(fen);\n\n    //Find the square locations of black bishops\n    List\u003cSquare\u003e blackBishopSquares = board.getPieceLocation(Piece.BLACK_BISHOP);\n\n    //Get the piece at A1 square...\n    Piece piece = board.getPiece(Square.A1);\n```\n## \u003ca name=\"MoveList\"\u003e\u003c/a\u003e MoveList\n\n`MoveList` stores a list of moves played in the chessboard. When created it assumes the initial \nposition of a regular chess game. Arbitrary moves from a chess game can be loaded using SAN or LAN string: \n\n```java\n    String san = \"e4 Nc6 d4 Nf6 d5 Ne5 Nf3 d6 Nxe5 dxe5 Bb5+ Bd7 Bxd7+ Qxd7 Nc3 e6 O-O exd5 \";\n    MoveList list = new MoveList();\n    list.loadFromSan(san);\n    \n    System.out.println(\"FEN of final position: \" + list.getFen());\n```\n\n## \u003ca name=\"Generate_all_chess_legal_moves_for_the_current_position\"\u003e\u003c/a\u003e Generate all chess legal-moves for the current position\n\n```java\n    // Generate legal chess moves for the current position\n    Board board = new Board();\n    List\u003cMove\u003e moves = board.legalMoves();\n    System.out.println(\"Legal moves: \" + moves);\n```\nResult:\n```text\n  a2a3 a2a4 b2b3 b2b4 c2c3 c2c4 d2d3 d2d4 e2e3 e2e4 f2f3 f2f4 g2g3 g2g4 h2h3 h2h4 b1a3 b1c3 g1f3 g1h3\n```\n\nRelaying the legal moves to the chessboard:\n\n```java\n    ...\n    for (Move move : moves) {\n        board.doMove(move);\n        //do something\n        board.undoMove();\n    }\n    System.out.println(\"Legal moves: \" + moves);\n```\n\n## \u003ca name=\"Checking_chessboard_situation\"\u003e\u003c/a\u003e Checking chessboard situation\n\nChessboard situation can be checked using the methods:\n \n  - `board.isDraw()`\n  - `board.isInsufficientMaterial()`\n  - `board.isStaleMate()`\n  - `board.isKingAttacked()`\n  - `board.isMated()`\n  - `board.getSideToMove()`\n  - ...\n  \n  \n## \u003ca name=\"Comparing_boards\"\u003e\u003c/a\u003e Comparing boards\n\nThere are two methods for comparing boards:\n \n  - `board.equals(board2)`: Compares ignoring the board history\n  - `board.strictEquals(board2)`: Compares the board and its history\n\n## \u003ca name=\"Load_a_chess_game_collection_from_a_PGN_file\"\u003e\u003c/a\u003e Load a chess game collection from a [PGN](https://en.wikipedia.org/wiki/Portable_Game_Notation) file\n\n```java\n    PgnHolder pgn = new PgnHolder(\"/opt/games/linares_2002.pgn\");\n    pgn.loadPgn();\n    for (Game game: pgn.getGames()) {\n        game.loadMoveText();\n        MoveList moves = game.getHalfMoves();\n        Board board = new Board();\n        //Replay all the moves from the game and print the final position in FEN format\n        for (Move move: moves) {\n            board.doMove(move);\n        }\n        System.out.println(\"FEN: \" + board.getFen());\n    }\n```\nYou could achieve the same by loading the move list final FEN position:\n```java\n    ...\n    board.loadFromFen(moves.getFen());\n\n```\nIterating over a PGN file games using the `PgnIterator`:\n```java\n    PgnIterator games = new PgnIterator(\"/opt/games/linares_2002.pgn\");\n    for (Game game: games) {\n        System.out.println(\"Game: \" + game);\n    }\n```\nNote: The iterator is highly recommended for processing large PGN files as it is not retaining in the memory\nintermediate objects loaded during the process of each iteration.\n\nCapturing the comments from each move:\n\n```java\n    PgnIterator games = new PgnIterator(\"src/test/resources/rav_alternative.pgn\");\n    for (Game game: games) {\n        String[] moves = game.getHalfMoves().toSanArray();\n        Map\u003cInteger, String\u003e comments = game.getComments();\n        for (int i = 0; i \u003c moves.length; i++) {\n            String ply = ((i + 2) / 2) + (i % 2 != 0 ? \"..\" : \" \");\n            String move = moves[i];\n            String comment = comments.get(i + 1) + \"\";\n            System.out.println(ply + move + \" \" + comment.trim());\n        }\n    }\n```\nThe output should be something like: \n```text\n1 e4 Ponomariov plays 1. e4 in much the same way as any of the other top-level GMs.\n1..e6 Now, along with Pe4 there is an indication Black will place pawns on light-color squares to prevent Bf1 from ever being dangerous. White will probably have to meet 2...d5 with e4-e5 to open the d3-h7 diagonal. So, White needs a Pd4 to support Pe5.\n```\nYou can also load PGN from string directly in memory, when PGN file is not needed\n\n```java\n\nString pgnText = \"\"\" \n\n[Event \"CCT 13\"]\n[Site \"FICS, San Jose, California US\"]\n[Date \"2011.01.29\"]\n[Round \"2\"]\n[White \"Rookie\"]\n[Black \"JabbaChess\"]\n[Result \"1-0\"]\n[ECO \"C00\"]\n[WhiteElo \"2285\"]\n[BlackElo \"1680\"]\n[Annotator \"Albert Silver\"]\n[PlyCount \"67\"]\n[EventDate \"2011.??.??\"]\n[TimeControl \"3000+3\"]\n\n1. e4 e6 2. d4 a6 3. Nf3 d5 4. exd5 exd5 5. Bd3 Nc6 6. O-O Nf6 7. Re1+ Be7 8.\nc3 O-O 9. Nbd2 Re8 10. Ne5 Nxe5 11. dxe5 Nd7 12. Nb3 g6 13. Nd4 c5 14. Nf3 b5\n...\n\"\"\"\n// file name does not need to be provided\nPgnHolder pgn = new PgnHolder();\n\npgn.loadPgn(pgnText);\n\n// can access PGN data just like file\n\n```\n\n# \u003ca name=\"Advanced_usage\"\u003e\u003c/a\u003e Advanced usage\n\n## \u003ca name=\"Sanity_checking_of_chesslib_move_generation_with_Perft\"\u003e\u003c/a\u003e Sanity checking of chesslib move generation with Perft\n\nPerft, (performance test, move path enumeration) is a debugging function to walk the \nmove generation tree of strictly legal moves to count all the leaf nodes of a certain depth.\nExample of a perft function using chesslib: \n\n```java\n    private long perft(Board board, int depth, int ply) throws MoveGeneratorException {\n\n        if (depth == 0) {\n            return 1;\n        }\n        long nodes = 0;      \n        List\u003cMove\u003e moves = board.legalMoves();\n        for (Move move : moves) {\n            board.doMove(move);\n            nodes += perft(board, depth - 1, ply + 1);\n            board.undoMove();\n        }\n        return nodes;\n    }\n```\n\nThere are plenty of known results for Perft tests on a given set of chess positions.\nIt can be tested against the library to check if it's reliably generating moves and while \nkeeping the `Board` in a consistent state, e.g.:\n\n```java\n    @Test\n    public void testPerftInitialPosition() throws MoveGeneratorException {\n\n        Board board = new Board();\n        board.setEnableEvents(false);\n        board.loadFromFen(\"rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1\");\n\n        long nodes = perft(board, 5, 1);\n        assertEquals(4865609, nodes);\n    }\n```\n\nIt's known that from the initial standard chess position, there should have exactly 4865609 positions\nfor depth 5. Deviation from this number would imply a bug in move generation or keeping the board state. \n\n## \u003ca name=\"Creating_a_full_fledged_chess_engine\"\u003e\u003c/a\u003e Creating a full-fledged chess engine\n\n[kengine](https://github.com/bhlangonijr/kengine) is a minimalistic chess engine built on top of kotlin and chesslib to \nshowcase a more advanced use case.\n\n## \u003ca name=\"Capturing_and_reacting_to_events\"\u003e\u003c/a\u003e Capturing and reacting to events\n\nActions occurring in the chessboard or when loading a PGN file are emitted as events by the library so that it can\nbe captured by a GUI, for example:\n\n### \u003ca name=\"Listening_to_PGN_loading_progress\"\u003e\u003c/a\u003e Listening to PGN loading progress\n\nCreate your listener:\n\n```java\nclass MyListener implements PgnLoadListener {\n    \n    private int games = 0;\n\n     @Override\n    public void notifyProgress(int games) {\n        System.out.println(\"Loaded \" + games + \" games...\");\n    }\n}\n```\n\nAdd the listener to `PgnHolder` object and load the games:\n\n```java\n    PgnHolder pgn = new PgnHolder(\".../games.pgn\");\n    // add your listener\n    pgn.getListener().add(myListener);\n    pgn.loadPgn();\n```\n\nExample implementing a `SwingWorker` to update a Swing `ProgressBarDialog` with PGN loading status: \n\n```java\n\nprivate final ProgressBarDialog progress = new ProgressBarDialog(\"PGN Loader\", frame);\n...\nprivate void init() {\n    ...\n    LoadPGNWorker loadPGNWorker = new LoadPGNWorker();\n    loadPGNWorker.addPropertyChangeListener(new PropertyChangeListener() {\n        @Override\n        public void propertyChange(PropertyChangeEvent e) {                \n            progress.getProgressBar().setIndeterminate(true);\n            progress.getProgressBar().setValue((Integer) e.getNewValue());\n        }\n    });\n    loadPGNWorker.execute();\n\n}\n...\nprivate class LoadPGNWorker extends SwingWorker\u003cInteger, Integer\u003e implements PgnLoadListener {\n\n    @Override\n    protected Integer doInBackground() throws Exception {\n        try {\n            getPgnHolder().getListener().add(this);\n            loadPGN();\n        } catch (Exception e) {\n            JOptionPane.showMessageDialog(owner, errorMessageFromBundle + e.getMessage(), JOptionPane.ERROR_MESSAGE);\n            log.error(\"Error loading pgn\", e);\n        } finally {\n            progress.dispose();\n        }\n        return getPgnHolder().getSize();\n    }\n    \n    @Override\n    protected void done() {\n        setProgress(100);\n    }\n    \n    @Override\n    public void notifyProgress(int games) {\n        setProgress(Math.min(90, games));\n        progress.getLabel().setText(\"Loading games...\");\n    }\n}\n```\n\n### \u003ca name=\"Listening_to_chessboard_events\"\u003e\u003c/a\u003e Listening to chessboard events\n\nMoves played and game statuses are emitted by the `Board` whenever these actions happen.\n\nImplement your `Board` listener:\n```java\nclass MyBoardListener implements BoardEventListener {\n\n    @Override\n    public void onEvent(BoardEvent event) {\n\n        if (event.getType() == BoardEventType.ON_MOVE) {\n            Move move = (Move) event;\n            System.out.println(\"Move \" + move + \" was played\");\n        }\n    }\n}\n```\n\nAdd your listener to `Board` and listen to played moves events:\n```java\n    Board board = new Board();\n    board.addEventListener(BoardEventType.ON_MOVE, new MyBoardListener());    \n\n    handToGui(board);\n    ...\n```\n\n* Beware that listeners are executed using the calling thread that updated the `Board` and \ndepending on your listener processing requirements you'd want to hand the execution off \nto a separate thread like in a threadpool:  \n\n```java\n    public void onEvent(BoardEvent event) {\n\n        executors.submit(myListenerRunnable);\n    }\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbhlangonijr%2Fchesslib","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbhlangonijr%2Fchesslib","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbhlangonijr%2Fchesslib/lists"}