{"id":28356081,"url":"https://github.com/aw205/poko","last_synced_at":"2026-04-28T17:34:26.446Z","repository":{"id":244633922,"uuid":"813794078","full_name":"Aw205/Poko","owner":"Aw205","description":"A chess engine 🐈‍⬛","archived":false,"fork":false,"pushed_at":"2024-07-18T02:44:55.000Z","size":905,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-06-20T02:36:09.721Z","etag":null,"topics":["chess-engine","springboot"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","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/Aw205.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,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-06-11T18:53:46.000Z","updated_at":"2024-07-18T02:54:40.000Z","dependencies_parsed_at":null,"dependency_job_id":"882eed55-8963-4b5c-89b2-a8e57643d00b","html_url":"https://github.com/Aw205/Poko","commit_stats":null,"previous_names":["aw205/woodpusher","aw205/poko"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/Aw205/Poko","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Aw205%2FPoko","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Aw205%2FPoko/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Aw205%2FPoko/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Aw205%2FPoko/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Aw205","download_url":"https://codeload.github.com/Aw205/Poko/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Aw205%2FPoko/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32392299,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-28T14:34:11.604Z","status":"ssl_error","status_checked_at":"2026-04-28T14:32:37.009Z","response_time":56,"last_error":"SSL_read: 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-engine","springboot"],"created_at":"2025-05-28T06:11:27.548Z","updated_at":"2026-04-28T17:34:26.437Z","avatar_url":"https://github.com/Aw205.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Poko\n\nA chess engine.\n\n## Performance\n\n### Perft Tests\n\nStarting Position: `rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1`\n\n\u003cdetails open\u003e\n\u003csummary\u003e Results \u003c/summary\u003e\n\n| Depth  | Nodes        | Time (ms) | Time w/ bulk-counting (ms) |\n| ------ | ------------ | --------- | -------------------------- |\n| 1      | 20 \t\t\t| 0         | 0        \n| 2      | 400      \t| 1    \t    | 0        \n| 3      | 8902      \t| 6    \t    | 3\n| 4      | 197,281      | 23    \t| 14   \n| 5      | 4,865,609\t| 267    \t| 161   \n| 6      | 119,060,324  | 5485    \t| 2591 \n| 7      | 3,195,901,860| 136,134   | 61,802\n\n\u003c/details\u003e\n\n\\\nKiwipete (Position 2 on CPW): `r3k2r/p1ppqpb1/bn2pnp1/3PN3/1p2P3/2N2Q1p/PPPBBPPP/R3K2R w KQkq - 0 1`\n\n\u003cdetails\u003e\n\u003csummary\u003e Results \u003c/summary\u003e\n\n| Depth  | Nodes        | Time (ms) | Time w/ bulk-counting (ms) |\n| ------ | ------------ | --------- | -------------------------- |\n| 1      | 48 \t\t\t| 0         | 0     \n| 2      | 2039      \t| 3         | 1     \n| 3      | 97,862      \t| 16        | 7\n| 4      | 4,085,603    | 196       | 87\n| 5      | 193,690,690\t| 7170      | 2412\n| 6      | 8,031,647,685| 300,512   | 106,694  \n\u003c/details\u003e\n\n\\\nPosition 3 on CPW: `8/2p5/3p4/KP5r/1R3p1k/8/4P1P1/8 w - - 0 1`\n\n\u003cdetails\u003e\n\u003csummary\u003e Results \u003c/summary\u003e\n\n| Depth  | Nodes        | Time (ms) | Time w/ bulk-counting (ms) |\n| ------ | ------------ | --------- | -------------------------- |\n| 1      | 14 \t\t\t|  0        | 0    \n| 2      | 191      \t|  0   \t\t| 0        \n| 3      | 2812      \t|  3    \t| 1\n| 4      | 43,238    \t|  10    \t| 6   \n| 5      | 674,624\t\t|  46    \t| 30   \n| 6      | 11,030,083 \t|  503    \t| 223\n| 7      | 178,633,661 \t|  7730    \t| 3122\n| 8      | 3,009,794,393|  124,691  | 48,912   \n\n\u003c/details\u003e\n\n\n## Implementation\n\nA brief overview of the **move generation**, **search**, and **evaluation**.\n\n### Move generation\n\n#### Calculating Attacked Squares \n\n\u003cdetails\u003e\n\u003csummary\u003e King \u003c/summary\u003e\n\n - Precalculate the king moves given the position `square`.\n\n```java\n        long east = (square \u003c\u003c 1) \u0026 ~fileMasks[0]; // ~fileMasks[0] ensures that overflow is adjusted for\n\t\tlong west = (square \u003e\u003e 1) \u0026 ~fileMasks[7];\n\t\tlong attack = (east | west);\n\t\tattack |= (attack \u003c\u003c 8 | attack \u003e\u003e 8); // finding the top and bottom adjacent squares\n\t\t\n\t\treturn (attack | (square \u003e\u003e 8)| (square \u003c\u003c 8)); // finding the diagonals\n```\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e Knight \u003c/summary\u003e\n\n-  Precalcuate the knight moves given a position `pos`.\n\n```java\n\n        long east = 0;\n        long west = 0;\n        long attacks = 0;\n\n\t\teast = (pos \u003c\u003c 1) \u0026 ~fileMasks[0];\n\t\twest = (pos \u003e\u003e 1) \u0026 ~fileMasks[7];\n\t\tattacks = (east | west) \u003c\u003c 16 \u0026 (~rankMasks[0] \u0026 ~rankMasks[1]); //down 2 left/right 1\n\t\tattacks |= (east | west) \u003e\u003e 16 \u0026 (~rankMasks[7] \u0026 ~rankMasks[6]); //up 2 left/right 1\n\t\teast = (east \u003c\u003c 1) \u0026 ~fileMasks[0];\n\t\twest = (west \u003e\u003e 1) \u0026 ~fileMasks[7];\n\t\tattacks |= (east | west) \u003c\u003c 8 \u0026 (~rankMasks[0]); // left/right 2 up 1\n\t\tattacks |= (east | west) \u003e\u003e 8 \u0026 (~rankMasks[7]); // left/right 2 down 1\n\n        // rank and file masks account for moves out of bounds\n\n\t\treturn attacks;\n\n```\n\u003c/details\u003e\n\n\n\u003cdetails\u003e\n\u003csummary\u003e Bishop \u003c/summary\u003e\n\n- Operates with sliding moves, so we just need to know which diagonals the bishops sits on.\n\n```java \n\n        int row = square / 8;\n\t\tint col = square % 8;\n\t\tint diagIndex = (row-col) \u0026 15; // index of the diagonal the bishop is on -\u003e '/'\n\t\tint antiDiagIndex = (row+col) ^ 7; // index of the anti-diagonal -\u003e '\\'\n\t\t\n\t\treturn sliding_moves(square,occupied,diagMasks[diagIndex]) | sliding_moves(square,occupied,antiDiagMasks[antiDiagIndex]);\n\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e Rook \u003c/summary\u003e\n\n- Like the bishop, the rook operates with sliding moves but instead with a rank/files mask instead of diag/anti-diag masks.\n\n```java\n        return sliding_moves(square,occupied,rankMasks[square/8]) | sliding_moves(square,occupied,fileMasks[square%8]); \n```\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e Pawn \u003c/summary\u003e\n\n- Since pawns can't exist on the 1st or 8th rank, rank masks are uneccessary.\n\n```java\n       \tlong pawn_move = 1L \u003c\u003c square;\n\t\tlong push = (color == 0) ? pawn_move \u003c\u003c 8 : pawn_move \u003e\u003e 8;\n\t\treturn push \u0026 ~GameState.occupied; \n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e Queen \u003c/summary\u003e\n\n- This is the union of the bishop and rook moves.\n\n```java\n\n        long attackedSquares = MoveLogic.rook_moves(squareIndex,GameState.occupied);\n\t    attackedSquares |= MoveLogic.bishop_moves(squareIndex,GameState.occupied);\n\n```\n\u003c/details\u003e\n\n\\\nThe sliding pieces employ a technique called [hyperbola quintessence](https://www.chessprogramming.org/Hyperbola_Quintessence) to generate the sliding moves. \n\n\n#### Checks \u0026 Pins\n\nTo determine if a move is legal, we have to know whether our king is in check and the position of the pinned pieces.\n\n\n\u003cdetails\u003e\n\u003csummary\u003e Finding checks \u003c/summary\u003e\n\n- We generate different attacks from the position of the king and intersect it with the position of the corresponding enemy pieces. The result is a bitboard of all pieces that are giving checks.\n\n```java\n \t\t// getting positions of all the pieces\n\n\t\tlong pawnPos = GameState.piecePosition[color][Type.PAWN];\n\t\tlong knightPos = GameState.piecePosition[color][Type.KNIGHT];\n\t\tlong rookPos = bishopPos = GameState.piecePosition[color][Type.QUEEN];\n\t\tlong bishopPos |= GameState.piecePosition[color][Type.BISHOP];\n\t\trookPos |= GameState.piecePosition[color][Type.ROOK];\n\n\t\treturn (pawnAttacks[color ^ 1][kingIndex] \u0026 pawnPos) | (knightAttacks[kingIndex] \u0026 knightPos)\n\t\t\t\t| (bishop_moves(kingIndex, GameState.occupied) \u0026 bishopPos)\n\t\t\t\t| (rook_moves(kingIndex, GameState.occupied) \u0026 rookPos);\n\n```\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e Finding absolute pins\n\n\n\n\u003c/details\u003e\n\n#### Make/Unmake \n\nWhen a move is made, the game state needs to be updated to reflect the new position. \n\n- `occupied` - a bitboard of the squares occupied by pieces.\n- `colorPositions` - an array of bitboards representing the occupied squares of each color (black/white).\n- `attackedSquares` - an array of bitboards representing the combined attacked squares of the same colored pieces.\n- `piecePosition` - a 2D array of bitboards representing the position of each piece indexed by color and piece type.\n- `board` - a square centric array of the board.\n- `stack` - a stack from which Position objects are pushed and popped during make/unmake.\n\n\n### Search\n\nUses the Alpha-Beta algorithm.\n\nFeatures currently implemented:\n\n- Transposition tables\n- Quiescence search\n- Move ordering\n\t- Captures first\n\t- MMV_LVA\n- Iterative deepening\n\n### Evaluation\n\n\nIt's pretty simple right now.\n\n- Material \n- Mobility\n\t- Attacked squares","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Faw205%2Fpoko","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Faw205%2Fpoko","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Faw205%2Fpoko/lists"}