{"id":18015582,"url":"https://github.com/nomemory/neat-chess","last_synced_at":"2025-03-26T18:31:19.385Z","repository":{"id":39801656,"uuid":"354072918","full_name":"nomemory/neat-chess","owner":"nomemory","description":"Java UCI Protocol implementation (Universal Chess Engine)","archived":false,"fork":false,"pushed_at":"2023-01-03T05:57:34.000Z","size":2662,"stargazers_count":35,"open_issues_count":6,"forks_count":3,"subscribers_count":3,"default_branch":"main","last_synced_at":"2025-03-22T06:41:37.532Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/nomemory.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2021-04-02T16:25:50.000Z","updated_at":"2025-03-10T13:47:14.000Z","dependencies_parsed_at":"2023-02-01T05:15:29.831Z","dependency_job_id":null,"html_url":"https://github.com/nomemory/neat-chess","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nomemory%2Fneat-chess","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nomemory%2Fneat-chess/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nomemory%2Fneat-chess/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nomemory%2Fneat-chess/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/nomemory","download_url":"https://codeload.github.com/nomemory/neat-chess/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":245712654,"owners_count":20660277,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","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":[],"created_at":"2024-10-30T04:14:28.017Z","updated_at":"2025-03-26T18:31:18.928Z","avatar_url":"https://github.com/nomemory.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"A simple [UCI](https://en.wikipedia.org/wiki/Universal_Chess_Interface) (*Universal Chess Interface*) Client written in Java.\n\nTested with [Stockfish 13](https://stockfishchess.org/blog/2021/stockfish-13/).\n\nMaven:\n\n```xml\n\u003cdependency\u003e\n  \u003cgroupId\u003enet.andreinc\u003c/groupId\u003e\n  \u003cartifactId\u003eneatchess\u003c/artifactId\u003e\n  \u003cversion\u003e1.0\u003c/version\u003e\n\u003c/dependency\u003e\n```\n\n# Documentation \n\n## Starting / Closing the client\n\nBy using the `startStockfish()` method, the client assumes that Stockfish is already installed on the system, and it's accesible in `$PATH` as `\"stockfish\"`.\n\n```java\nvar uci = new UCI();\nuci.startStockfish();\n```        \n\nUsing `start(String cmd)` **neat-chess** can be tested with other chess engines:\n\n```java\n// leela chess \nvar uci = new UCI();\nuci.start(\"lc0\");\n```\n\nBy default each command you are sending to the engine, has a timeout of `60s` (during which the thread is blocked).\n\nYou can configure the global default timeout to a different value:\n\n```java\nvar uci = new UCI(5000l); // default timeout 5 seconds\nuci.startStockfish();\n```\n\nIf the client commands exceed the timeout interval an unchecked `UCITimeoutException` is thrown. But more on that in the next sections.\n\nTo retrieve the `defaultTimeout` simply call: `var timeout = uci.getDefaultTimeout()`.\n\nTo close the client simply call: `uci.close();`.\n\n## Commands\n\nMost commands respond with an `UCIResponse\u003cT\u003e` object. This class wraps a possible exception, and the actual result value.\n\nThe most common idiom(s) is/are:\n\n```java\nvar response = uci.\u003csome_command\u003e(...);\nvar result = response.getResultOrThrow();\n// do something with the result\n```\n\nor\n\n```java\nvar response = uci.\u003csome_command\u003e(...);\nif (response.succes()) {\n  var result = response.getResult();\n  // do something with the result\n}\n```\n\nAn `UCIResponse\u003cT\u003e` can only throw a `UCIRuntimeException`. This class has the following sub-types:\n- `UCIExecutionException` - when the `Thread` executing the command fails;\n- `UCIInterruptedException`- when the `Thread` executing the command fails;\n- `UCITimeoutException` - when `Thread` exeucuting the command timeouts;\n- `UCIUncheckedIOException` - when the communication with the engine process fails;\n- `UCIUnknownCommandException` - when the server doesn't understand the command the client has sent;\n- `UCIParsingException` - when the engine sends output that the client doesn't understand;\n\nAll commands support custom timeout. Usually this is the last parametere of the command function:\n\n```java\nvar response = uci.\u003csome_command\u003e(args, long timeout);\n```\n\n## Retrieving the engine information\n\nThe method for obtaining the engine information (the current engine name and supported engine options) is `UCIResponse\u003cEngineInfo\u003e = uci.getEngineInfo()`.\n\nExample:\n\n```java\nvar uci = new UCI(5000l); // default timeout 5 seconds\nuci.startStockfish();\nUCIResponse\u003cEngineInfo\u003e response = uci.getEngineInfo();\nif (response.success()) {\n\n    // Engine name\n    EngineInfo engineInfo = response.getResult();\n    System.out.println(\"Engine name:\" + engineInfo.getName());\n    \n    // Supported engine options\n    System.out.println(\"Supported engine options:\");\n    Map\u003cString, EngineOption\u003e engineOptions = engineInfo.getOptions();\n    engineOptions.forEach((key, value) -\u003e {\n        System.out.println(\"\\t\" + key);\n        System.out.println(\"\\t\\t\" + value);\n    });\n}\nuci.close();\n```\n\nOutput:\n\n```\nEngine name:Stockfish 13\nSupported engine options:\n\tHash\n\t\tSpinEngineOption{name='Hash', defaultValue=16, min=1, max=33554432}\n\tMove Overhead\n\t\tSpinEngineOption{name='Move Overhead', defaultValue=10, min=0, max=5000}\n\tUCI_AnalyseMode\n\t\tCheckEngineOption{name='UCI_AnalyseMode', defaultValue=false}\n\tUCI_LimitStrength\n\t\tCheckEngineOption{name='UCI_LimitStrength', defaultValue=false}\n\tThreads\n\t\tSpinEngineOption{name='Threads', defaultValue=1, min=1, max=512}\n\tMultiPV\n\t\tSpinEngineOption{name='MultiPV', defaultValue=1, min=1, max=500}\n/// and so on\n```\n\n## Setting an option\n\nFor changing an option of the engine you can use the following methods:\n- `UCIResponse\u003cList\u003cString\u003e\u003e setOption(String optionName, String value, long timeout)`\n- `UCIResponse\u003cList\u003cString\u003e\u003e setOption(String optionName, String value)`\n\nFor example, modifying the `MultiPV` option to `10` is as simple as:\n\n```java\nvar uci = new UCI(5000l); // default timeout 5 seconds\nuci.startStockfish();\nuci.setOption(\"MultiPV\", \"10\", 3000l).getResultOrThrow(); // custome timeout 3 seconds\nuci.close();\n```\n\n## Getting the best move for a position\n\nIf you plan using the engine to analyse various positions that are not part of the same game, it's recommended to call the `uciNewGame()` first.\n\nAn UCI engine understands [FEN notations](https://en.wikipedia.org/wiki/Forsyth%E2%80%93Edwards_Notation), so the method to make the engine aware of the position he needs to analyse is: \n- `UCIResponse\u003cList\u003cString\u003e\u003e positionFen(String fen, long timeout)`\n- `UCIResponse\u003cList\u003cString\u003e\u003e positionFen(String fen)`\n\nAfter the position has been set on the board, to retrieve the best move:\n- `UCIResponse\u003cBestMove\u003e bestMove(int depth, long timeout)` - to analyse for a given depth (e.g.: 18 moves deep);\n- `UCIResponse\u003cBestMove\u003e bestMove(int depth)`;\n- `UCIResponse\u003cBestMove\u003e bestMove(long moveTime, long timeout)` - to analyse for a fixed amount of time (e.g.: 10000l - 10 seconds);\n- `UCIResponse\u003cBestMove\u003e bestMove(long moveTime)`;\n\nLet's take the example the following position:\n\n\u003cimg src=\"https://github.com/nomemory/neat-chess/blob/main/assets/position01.png\" width=\"30%\"/\u003e\n\nThe corresponding FEN for the position is:\n\n```\nrnbqk3/pp6/5b2/2pp1p1p/1P3P1P/5N2/P1PPP1P1/RNBQKB2 b Qq - 0 14\n```\n\nThe code that determines what the best move is:\n\n```java\nvar uci = new UCI(5000l); // default timeout 5 seconds\nuci.startStockfish();\nuci.uciNewGame();\n\nuci.positionFen(\"rnbqk3/pp6/5b2/2pp1p1p/1P3P1P/5N2/P1PPP1P1/RNBQKB2 b Qq - 0 14\");\n\nvar result10depth = uci.bestMove(10).getResultOrThrow();\nSystem.out.println(\"Best move after analysing 10 moves deep: \" + result10depth);\n\nvar result10seconds = uci.bestMove(10_000l).getResultOrThrow();\nSystem.out.println(\"Best move after analysing for 10 seconds: \" + result10seconds);\n\nuci.close();\n```\n\n## Analysing a position\n\nAnalysing the best N lines for a given FEN position is very similar to the code for finding what is best move. \n\nThe methods for finding out what are the best lines are:\n- `UCIResponse\u003cAnalysis\u003e analysis(long moveTime, long timeout)` - to analyse for a given depth (e.g.: 18 moves deep);\n- `UCIResponse\u003cAnalysis\u003e analysis(long moveTime)`\n- `UCIResponse\u003cAnalysis\u003e analysis(int depth, long timeout)` - to analyse for a fixed amount of time (e.g.: 10000l - 10 seconds);\n- `UCIResponse\u003cAnalysis\u003e analysis(int depth)` \n\n\u003e By default Stockfish analyses only one line, so if you want to analyse multiple lines in parallel, you need to set `MultiPV`: `uci.setOption(\"MultiPV\", \"10\", 3000l)`\n\nLet's take for example the following position:\n\n\u003cimg src=\"https://github.com/nomemory/neat-chess/blob/main/assets/position02.png\" width=\"30%\"/\u003e\n\nThe corresponding FEN for the position is:\n\n```\nr1bqkb1r/2pp1ppp/p1n2n2/1p2p3/4P3/1B3N2/PPPP1PPP/RNBQK2R w KQkq - 2 6\n```\n\nAnd in order to get the 10 best continuations, the code is:\n\n```java\nvar uci = new UCI();\nuci.startStockfish();\nuci.setOption(\"MultiPV\", \"10\");\n\nuci.uciNewGame();\nuci.positionFen(\"r1bqkb1r/2pp1ppp/p1n2n2/1p2p3/4P3/1B3N2/PPPP1PPP/RNBQK2R w KQkq - 2 6\");\nUCIResponse\u003cAnalysis\u003e response = uci.analysis(18);\nvar analysis = response.getResultOrThrow();\n\n// Best move\nSystem.out.println(\"Best move: \" + analysis.getBestMove());\nSystem.out.println(\"Is Draw: \" + analysis.isDraw());\nSystem.out.println(\"Is Mate: \" + analysis.isMate());\n\n// Possible best moves\nvar moves = analysis.getAllMoves();\nmoves.forEach((idx, move) -\u003e {\n    System.out.println(\"\\t\" + move);\n});\n\nuci.close();\n```\n\nThe output:\n\n```\nBest move: \n\tMove{lan='e1g1', strength=0.6, pv=1, depth=18, continuation=[c8b7, d2d3, f8c5, b1c3, ...]}\nBest moves:\n\tMove{lan='e1g1', strength=0.6, pv=1, depth=18, continuation=[c8b7, d2d3, f8c5, b1c3, ...]}\n\tMove{lan='d2d4', strength=0.55, pv=2, depth=18, continuation=[d7d6, c2c3, f8e7, e1g1, ...]}\n\tMove{lan='a2a4', strength=0.52, pv=3, depth=18, continuation=[c8b7, d2d3, b5b4, b1d2, ...]}\n\tMove{lan='b1c3', strength=0.36, pv=4, depth=18, continuation=[f8e7, d2d3, d7d6, a2a4, ...]}\n\tMove{lan='d2d3', strength=0.26, pv=5, depth=18, continuation=[f8c5, b1c3, d7d6, c1g5, ...]}\n\tMove{lan='d1e2', strength=-0.02, pv=6, depth=18, continuation=[f8c5, a2a4, a8b8, a4b5, ...]}\n\tMove{lan='c2c3', strength=-0.50, pv=7, depth=18, continuation=[f6e4, e1g1, d7d5, f1e1, ...]}\n\tMove{lan='b3d5', strength=-0.57, pv=8, depth=18, continuation=[f6d5, e4d5, c6d4, f3d4, ...]}\n\tMove{lan='h2h3', strength=-0.63, pv=9, depth=18, continuation=[f6e4, e1g1, d7d5, b1c3, ...]}\n\tMove{lan='f3g5', strength=-0.7, pv=10, depth=18, continuation=[d7d5, d2d3, c6d4, e4d5, ...]}\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnomemory%2Fneat-chess","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fnomemory%2Fneat-chess","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnomemory%2Fneat-chess/lists"}