{"id":37021406,"url":"https://github.com/lunalobos/chessapi4j","last_synced_at":"2026-01-14T02:31:29.728Z","repository":{"id":168027385,"uuid":"643648500","full_name":"lunalobos/chessapi4j","owner":"lunalobos","description":"A simple chess API for java.","archived":false,"fork":false,"pushed_at":"2025-11-13T14:38:33.000Z","size":5115,"stargazers_count":3,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-11-13T15:13:15.812Z","etag":null,"topics":["chess","java","maven-central"],"latest_commit_sha":null,"homepage":"https://lunalobos.github.io/chessapi4j/","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/lunalobos.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":"2023-05-21T20:24:22.000Z","updated_at":"2025-11-13T14:38:38.000Z","dependencies_parsed_at":null,"dependency_job_id":"99dc870e-fc35-4ae9-ab11-431cf981a69c","html_url":"https://github.com/lunalobos/chessapi4j","commit_stats":null,"previous_names":["lunalobos/chessapi4j"],"tags_count":4,"template":false,"template_full_name":null,"purl":"pkg:github/lunalobos/chessapi4j","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lunalobos%2Fchessapi4j","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lunalobos%2Fchessapi4j/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lunalobos%2Fchessapi4j/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lunalobos%2Fchessapi4j/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/lunalobos","download_url":"https://codeload.github.com/lunalobos/chessapi4j/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lunalobos%2Fchessapi4j/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28408711,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-14T01:52:23.358Z","status":"online","status_checked_at":"2026-01-14T02:00:06.678Z","response_time":107,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"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","java","maven-central"],"created_at":"2026-01-14T02:31:29.098Z","updated_at":"2026-01-14T02:31:29.720Z","avatar_url":"https://github.com/lunalobos.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"![Java](https://img.shields.io/badge/Java-11%2B-green)\n[![Static Badge](https://img.shields.io/badge/javadoc-1.2.11-brightgreen)](https://lunalobos.github.io/chessapi4j/apidocs/chessapi4j/package-summary.html)\n[![Maven Central](https://img.shields.io/maven-central/v/io.github.lunalobos/chessapi4j)](https://central.sonatype.com/artifact/io.github.lunalobos/chessapi4j)\n![License](https://img.shields.io/github/license/lunalobos/chessapi4j)\n\n![chessapi4j](https://chessapi4j.my.canva.site/media/7547b1586c5d91c735c3b3a67838eb13.png)\n\n# Overview\n\nThis library aims to provide a solid foundation for handling abstractions of chess concepts such as board positions, determination of the state of a position (checkmate, stalemate, insufficient material, etc.), games between players (either in progress or already played), legal move generation and validation, FEN validation, ECO code determination, and conversion to and from PGN format.\n\n\n\u003e **⚠️ Java 11 Compatibility Note:**  \n\u003e Full compatibility with Java 11 is ensured starting from version **1.2.10**. However, it is **strongly recommended** to use the `functional` package when working with Java 11, as the original package is significantly slower in this environment (the cause is currently unknown).\n\n\n\u003e **⚠️ Java 17 Compatibility Note:** \n\u003e There do not appear to be performance issues with the original package when running on Java 17. Nevertheless, it is still recommended to use the `functional` package, as it is generally more robust and safer for concurrent or complex applications.\n\n## Table of contents\n\n1. [Getting Started with ChessAPI4j](#getting-started-with-chessapi4j)\n2. [Reference Documentation](#reference-documentation)\n3. [Position Representation](#position-representation)\n4. [Move representation and move generation](#move-representation-and-move-generation)\n5. [PGN handling](#pgn-handling)\n6. [Other Features](#other-features)\n   - [Utility Classes](#utility-classes)\n   - [Heuristic Evaluation and Search](#heuristic-evaluation-and-search)\n7. [Functional Package (since 1.2.9)](#sparkles-functional-package)\n    - [Position](#position)\n    - [Generator](#generator)\n    - [Game](#game)\n    - [PGNHandler](#pgnhandler)\n    - [Move and PGNMove](#move-and-pgnmove)\n7. [Unit Testing](#unit-testing)\n8. [Javadoc](#javadoc)\n9. [Contributing](#contributing)\n10. [License](#license)\n11. [Author](#author)\n\n## :rocket: Getting Started with ChessAPI4j\n\nTo use the library you need Java 11 or higher and Maven 3.8 or higher. Start by cloning this repository and then using Maven to install it.\n\n### Step 1: Verify your Maven and Java versions\n\nI recommend use [Semeru jDK](https://developer.ibm.com/languages/java/semeru-runtimes/downloads/) and downloading Maven from [here](https://maven.apache.org/download.cgi).\n\n```console\n\n$ mvn -version\nApache Maven 3.9.6 (bc0240f3c744dd6b6ec2920b3cd08dcc295161ae)\nMaven home: C:\\apache-maven-3.9.6\nJava version: 21.0.4, vendor: IBM Corporation, runtime: C:\\semeru-jdk-21.0.4+7\nDefault locale: es_ES, platform encoding: UTF-8\nOS name: \"windows 10\", version: \"10.0\", arch: \"amd64\", family: \"windows\"\n\n$ java -version\nopenjdk version \"21.0.4\" 2024-07-16 LTS\nIBM Semeru Runtime Open Edition 21.0.4.0 (build 21.0.4+7-LTS)\nEclipse OpenJ9 VM 21.0.4.0 (build openj9-0.46.0, JRE 21 Windows 10 amd64-64-Bit Compressed References 20240716_229 (JIT enabled, AOT enabled)\nOpenJ9   - 1a6f6128aa\nOMR      - 840a9adba\nJCL      - 7d844187b25 based on jdk-21.0.4+7)\n\n```\n\n### Step 2: Add the dependency to your project\n\nAdd the following to your dependencies:\n\n```xml\n\n\u003cdependency\u003e\n    \u003cgroupId\u003eio.github.lunalobos\u003c/groupId\u003e\n    \u003cartifactId\u003echessapi4j\u003c/artifactId\u003e\n    \u003cversion\u003e1.2.11\u003c/version\u003e\n\u003c/dependency\u003e\n\n```\n\n## :books: Reference Documentation\n\nThe following links correspond to the historical documentation of several relevant concepts. I recommend at least skimming their content if you are not familiar with the FEN, UCI, and PGN standards.\n\n- [FEN_1999_05_27](https://www.stmintz.com/ccc/index.php?id=53266)\n- [PGN_standard_1994-03-12](https://ia902908.us.archive.org/26/items/pgn-standard-1994-03-12/PGN_standard_1994-03-12.txt)\n- [UCI_April_2006](https://www.shredderchess.com/download/div/uci.zip)\n\nYou can see a copy of these files [here](https://github.com/lunalobos/chessapi4j/tree/master/ref).\n\n## :chess_pawn: Position Representation\n\nThe Position class allows representing a position in a very comprehensive way. Its empty constructor generates the initial position, and it also has a constructor that takes the FEN representation as an argument.\n\n```java\n\n    // start position\n    var startpos = new Position();\n\n    // custom position\n    var customPos = new Position(\"r4rk1/1pp1qppp/p1np1n2/2b1p1B1/2B1P1b1/P1NP1N2/1PP1QPPP/R4RK1 w - - 0 10\");\n\n```\n\nMethods to obtain a FEN representation as well as a graphical representation are providesd by this class.\n\n```java\n    var position = new Position();\n    var fen  = position.toFen(); // fen string: rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1\n    var positionRep = position.toString(); // graphical representation\n```\n\nA factory class is also provided that allows creating a Position object from a string that provides the FEN representation of an initial position followed by the moves token followed by the subsequent moves, analogous to the input requested by the UCI protocol.\n\n```java\n    // a position after the initial moves of petrov's defense\n    var petrov = PositionFactory.fromMoves(\"rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1 moves e2e4 e7e5 g1f3 g8f6\");\n```\n\nThe secureInstance method belongs to the PositionFactory class and acts as a safe factory method for creating Position instances from a FEN string. If the FEN string is valid, it returns an Optional containing the Position object. Otherwise, it returns an empty Optional.\n\n```java\n// startpos fen\nvar fen = \"rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1\";\nvar positionOpt = PositionFactory.secureInstance(fen);\n\npositionOpt.ifPresentOrElse(\n    position -\u003e System.out.println(\"Valid position created!\"),\n    () -\u003e System.out.println(\"Invalid FEN string, no position created.\")\n);\n\n```\n\nThe isValidFen method is part of the Rules class and is responsible for checking whether a given FEN (Forsyth-Edwards Notation) string represents a legal chess position. This method doesn't verify if the position could be reached through valid moves in a real game; it only ensures that the basic rules are followed.\n\n```java\n\nvar fen = \"rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1\";\nvar isLegalPosition = Rules.isValidFen(fen);\n\nif (isLegalPosition) {\n    System.out.println(\"The FEN represents a legal position.\");\n} else {\n    System.out.println(\"The FEN does not represent a legal position.\");\n}\n\n```\n\n## :chess_pawn: Move representation and move generation\n\n### Move class\n\nThe Move class provides a basic representation of a chess move. Among its properties are the origin and destination squares as well as the piece to promote if any. It does not provide information about the piece being moved or the position from which it starts.\n\n```java\n    // move object\n    var move = new Move(Square.G1, Square.G2);\n```\n\nA factory class is also provided for cases where a move needs to be created from the algebraic notation of the UCI protocol.\n\n```java\n    try {\n      var isWhiteMove = true; // necesary for promotions\n      var moveUciNotation = \"e2e4\";\n      var move = MoveFactory.instance(moveUciNotation, isWhiteMove);\n    } catch (MovementException e){\n      e.printStackTarce();\n    }\n\n```\n\nThe PGNMove class extends Move and is provided for cases where classical algebraic notation functionalities and PGN format are required. The toString method change between Move and PGNMove.\n\n```java\n    var move = new Move(Square.G1, Square.F3);\n    var startpos = new Position();\n    // a pgn move needs to know the position previous to the move\n    var pgnMove = new PGNMove(move, startpos);\n    var moveUCINotation = move.toString(); // g1f3\n    var moveStandardNotation = pgnMove.toString(); // Nf3\n```\n\n### Move Generation\n\nThe library includes a move generator. It provides two utility methods for move generation. On one hand, \"generateChildren\" generates all positions derived from the position given as an argument. On the other hand, if we have already generated the child positions, the \"generateMoves\" method returns the list of Move objects in the same order as the list of child positions given as an argument. The methods of Generator are instance methods. To use an instance of this class, it is necessary to use the GeneratorFactory factory class.\n\nLet's see this feature in action:\n\n```java\n\n    // creates a position\n    var position = PositionFactory.secureInstance(\"r4rk1/1pp1qppp/p1np1n2/2b1p1B1/2B1P1b1/P1NP1N2/1PP1QPPP/R4RK1 w - - 0 10\").orElseThrow();\n    // calculate the positions derived from the position just created.\n    var children = GeneratorFactory.instance().generateChildren(position);\n\n    var childrenCount = children.size(); // 46\n\n    // creates the list of object moves\n    var moves = GeneratorFactory.instance().generateMoves(position, children);\n    // moves: b2b3, b2b4, g2g3, h2h3, h2h4, a3a4, d3d4, c3b1,..., g1h1\n\n\n```\n\n## :chess_pawn: PGN handling\n\nA basic representation of a game in PGN format is provided with the Game class, as well as several subclasses to represent the characteristics of a game saved with this notation. The PGNHandler class allows manipulation of PGN databases.\n\nIf you need to implement PGN file handling functionality, these classes are suitable.\n\n**PGNMove**: Inherits from Move, adding properties for annotations, comments, and variations. toString() method returns the SAN notation format.\n\n**Game**: Represents a game and contains the data that every game saved in PGN format possesses. Among its properties are the main tags (event, site, date, round, white, black, result) and supplementary tags (all represented with the Tag class), as well as a list of moves represented with the PGNMove class. This class can be used to model a real-time game and then export it to PGN format using the toString method.\n\n```java\n\n    // create the tags and other parameters\n    var event = new Tag(\"event\", \"FooTournament\");\n    var site = new Tag(\"site\", \"BarCity\");\n    var date = new Tag(\"date\", \"2001.12.20\");\n    var round = new Tag(\"round\", \"1\");\n    var white = new Tag(\"white\", \"foo\");\n    var black = new Tag(\"black\", \"bar\");\n    var result = new Tag(\"result\", \"\"); // it is unknown yet\n    Set\u003cTag\u003e supplementalTags = new HashSet\u003c\u003e();\n    List\u003cPGNMove\u003e moves = new ArrayList\u003c\u003e();\n\n    // game object\n    final var game = new Game(event, site, date, round, white, black, result, supplementalTags, moves);\n\n    // We can see that the initial position of this object is the initial position of the game\n    var initial = game.positionAt(1, Side.WHITE);\n    System.out.printf(\"%s\\n\", initial);\n\n    // add moves\n    Stream.of(\n      new Move(Square.E2, Square.E4), // 1. e4\n      new Move(Square.E7, Square.E5), // 1... e5\n      new Move(Square.F1, Square.C4), // 2. Bc4\n      new Move(Square.D7, Square.D6), // 2... d6\n      new Move(Square.D1, Square.H5), // 3. Qh5\n      new Move(Square.G8, Square.F6), // 3... Nf6??\n      new Move(Square.H5, Square.F7)  // 4. Qxf7#\n      ).forEach(game::addMove);\n\n    var isCheckmate = game.currentPosition().isCheckmate(); // true\n    var result = game.getTagValue(\"RESULT\").orElseThrow(); // \"1-0\"\n    // The toString() method of the Game class is the game in PGN format\n    var pgnGame = game.toString();\n    /*\n    * [event \"FooTournament\"]\n    * [site \"BarCity\"]\n    * [date \"2024.04.17\"]\n    * [round \"1\"]\n    * [white \"foo\"]\n    * [balck \"bar\"]\n    * [result \"1-0\"]\n    * 1. e4 e5 2. Bc4 d6 3. Qh5 Nf6 4. Qxf7# 1-0\n    */\n\n```\n\nFrom an instance of the game class you can obtain the ECO code.\n\n```java\n    var eco = game.getEcoDescriptor().getEco(); // ECO code\n    var opening = game.getEcoDescriptor().getName(); // opening name\n```\n\n**PGNHandler**: The main function of this class is to provide static methods for handling PGN notations and files. Regarding the latter, this class allows obtaining a list of Game objects from a PGN file.\n\n```java\n\n    // supose you've got a pgn file with several games\n    var path = \"pgnGames.pgn\";\n    // you can just import then like this\n    var games = PGNHandler.parseGames(Paths.get(path));// a list of game objects\n\n```\n\n## :chess_pawn: Other Features\n\n### Utility Classes\n\nThe Util and AdvanceUtil classes provide useful methods for working with custom heuristic functions. Initially, I thought about making these classes not visible since they are not entirely safe, but I thought someone might find them useful.\n\n### Heuristic Evaluation and Search\n\nThis library offers interfaces and implementations for various search and evaluation algorithms. While an implementation is provided, these feature is still experimental.\n\n## :sparkles: Functional Package\n\nIntroduced in version 1.2.9, the functional package presents a new generation of classes for working with chess. It is focused on immutability, safety, and robustness. All main classes in this package provide unmodifiable (immutable) instances by default, making them thread-safe and especially suitable for concurrent or multithreaded environments.\n\n### Position\n\nThe Position class in the functional package allows for representing chess positions immutably. Once an instance is created, its state cannot be modified, ensuring that the position data remains consistent and safe in any context—even when shared across multiple threads. This class provides a zobristHash() method that returns the corresponding Zobrist hash value as a long (i.e., 64 bits), which is the minimum acceptable length for a hash of this kind. However, Java has a limitation in that it does not allow arrays with lengths over 32 bits, so implementing hash tables for positions becomes a bit more complex.\n\n```java\nimport chessapi4j.functional.Factory;\n...\n// You can always use the same startpos instance because it is immutable,\n// and therefore thread-safe.\nvar startpos = Factory.startpos();\n\n// If you need a new instance of this class, you can call the children method\n// to get its derived positions from legal moves.\nvar children = startpos.children();\n\n// You can create new positions just by using the move method\n// in one of its available versions.\nvar position = startpos.move(\"g1f3\"); // King's Knight Opening\n\n// You can also use standard algebraic notation.\nvar nextPosition = startpos.sanMove(\"d5\"); // King's Knight Opening again\n\n// It is also suitable for constructing a position from several moves.\nvar finalPosition = startpos\n        .sanMove(\"e4\")\n        .sanMove(\"e5\")\n        .sanMove(\"Nf3\")\n        .sanMove(\"Nc6\")\n        .sanMove(\"Bb5\"); // Ruy Lopez Opening\n\n// You may want to store this position after a heuristic evaluation in\n// your hash table implementation. You can use the zobristHash() method\n// to fulfill the hashing contract of your implementation.\nvar hash = finalPosition.zobristHash(); // this is a long value\n\n```\n\n### Generator\n\nThe Generator class for move generation offers the same functionality as in the main package. Although it is currently about 30% slower than the original version due to the creation of move objects (the computational cost of instantiating more objects), the advantage of this package does not lie in performance yet, but rather in a more solid programmatic flow, which leads to simpler system design.\n\nSince the Position class provides the children method, it's not necessary to use this class directly, although it is available through the generator method in Factory.\n\n### Game\n\nThe Game class in the functional package enables the creation of chess game representations that can be either immutable (when the result is defined) or mutable (when the game is ongoing). Its setter methods are synchronized, allowing game modifications in multithreaded environments to be handled much more reliably than with the original Game class. This makes it an ideal choice for servers, concurrent analysis, or any application where data safety is a top priority. This class can detect when the game is over and set the result tag to the corresponding value.\n\n```java\n\nimport chessapi4j.functional.Game;\n...\n// lets create a open to modification instance\nvar game = Game.builder()\n        .event(\"DSB Kongress-16 Hauptturnier A\")\n        .site(\"Duesseldorf\")\n        .date(\"1908.08.14\")\n        .round(\"11\")\n        .white(\"Lasker, Edward\")\n        .black(\"Alekhine, Alexander\")\n        .repetitionsMode(Game.RepetitionsMode.AWARE)\n        .build();\n// you can add the game moves in a simple way\ngame.sanMove(\"e4\")\n    .sanMove(\"e5\")\n    .sanMove(\"Nf3\")\n    .sanMove(\"d6\")\n    ... // until the game is over\n// you can see de eco code like in the original class\nvar ecoCode = game.getEcoDescriptor().getEco();\n\n```\n\n### PGNHandler\n\nThe PGNHandler class has the same functionality as in the original version, but it's implemented for the new classes in the package.\n```java\nimport chessapi4j.functional.PGNHandler;\n...\n// you need to provide a input stream with the pgn database\nvar is = ... // some input stream instatiation\n// this will convert the original database to a game list, a classic representation\nvar games = PGNHandler.parseGames(is);\n\n```\n\n### Move and PGNMove\nThe Move and PGNMove classes are almost identical to their original versions, but they are immutable. This is important to keep in mind for PGNMove, which must be instantiated all at once rather than in parts. In general, developers don't construct it manually, but it's also possible to instantiate a PGNMove using the basic parameters: target square, origin square, promotion piece, and origin position.\n\n## :white_check_mark: Unit Testing\n\nI have created a series of unit tests that ensure the characteristics specified by the library. In particular, the Generator class has been thoroughly tested, and I have tried to optimize it as much as possible to improve its speed. PGNHandler also has been tested.\n\n## :books: Javadoc\n\nChessAPI4j provides basic [javadoc](https://lunalobos.github.io/chessapi4j/apidocs/chessapi4j/package-summary.html), which will clear up many of the doubts you may have.\n\n## :raising_hand: Contributing\n\nI have not yet created rules for contributing. For now, each case will be analyzed individually without any fixed criteria. If you find bugs, please open an issue or write to my email.\n\n## :page_with_curl: License\n\nChessAPI4j is licensed under the Apache License, Version 2.0 (\"License\"). You may use, modify, and distribute this software according to the terms and conditions outlined in the License.\n\n## :mailbox_closed: Author\n\nThis library is developed and maintained by me (https://github.com/lunalobos). Feel free to contact me at my email lunalobosmiguel@gmail.com.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flunalobos%2Fchessapi4j","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Flunalobos%2Fchessapi4j","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flunalobos%2Fchessapi4j/lists"}