{ "info": { "author": "Carmen Bianca Bakker", "author_email": "carmen@carmenbianca.eu", "bugtrack_url": null, "classifiers": [ "Development Status :: 2 - Pre-Alpha", "License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.4", "Programming Language :: Python :: 3.5", "Programming Language :: Python :: 3.6" ], "description": "..\n Copyright (C) 2017-2018 Carmen Bianca Bakker \n\n This file is part of En Pyssant, available from its original location:\n .\n\n This work is licensed under the Creative Commons Attribution-ShareAlike\n 4.0 International License. To view a copy of this license, visit\n .\n\n SPDX-License-Identifier: CC-BY-SA-4.0\n\n\n==========\nEn Pyssant\n==========\n\nEn Pyssant is a chess implementation and engine.\n\n- Free software: GNU General Public License version 3 or later\n\n- Documentation: ``_\n\n- Source code: ``_\n\n- PyPI: ``_\n\n- Python: 3.4+\n\n\n.. IMPORTANT::\n This project is still a heavy work in progress and will break backwards\n compatibility with every release before 1.0.\n\n\nBackground\n==========\n\nEn Pyssant is a hobby project to implement a complete chess implementation and\nengine in Python with a simple, straightforward API. The public API is thusly\ndocumented and implemented that it should be relatively simple to swap out\nindividual components with different implementations.\n\nThe focus is on keeping the API clean and flexible. This may come at the cost\nof performance, but if performance were the primary goal, perhaps it mightn't\nhave been a good idea to use Python in the first place.\n\nThe goal is to keep the project thoroughly tested with unit and integration\ntests. More of the latter than the former.\n\n\nInstall\n=======\n\nInstalling En Pyssant should be a simple matter of executing the following\ncommand::\n\n pip3 install --user en-pyssant\n\n\nUsage\n=====\n\nLongum iter est per praecepta, breve et efficax per exempla---It\u2019s a long way by\nthe rules, but short and efficient with examples.\n\nFirst, import everything::\n\n >>> import threading\n >>> import time\n >>> from en_pyssant import *\n >>> from en_pyssant.engine import *\n >>> from en_pyssant.rules import *\n >>> # Technically you should never star-import, but it makes\n >>> # the examples easier.\n\nEn Pyssant has a few core data types::\n\n >>> white_pawn = Piece(Type.PAWN, Side.WHITE)\n >>> white_pawn\n Piece(type=, side=)\n >>> a1 = Square('a1')\n >>> a1.up().up()\n 'a3'\n\nYou can easily create a starting board, or import any other board layout from\npartial `Forsyth-Edwards Notation (FEN)\n`_::\n\n >>> board = DictBoard()\n >>> board\n rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR\n >>> DictBoard.from_fen('rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR')\n rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR\n >>> board[a1]\n Piece(type=, side=)\n >>> print(board['a3'])\n None\n >>> board.put('a3', white_pawn)\n rnbqkbnr/pppppppp/8/8/8/P7/PPPPPPPP/RNBQKBNR\n\nYou can also easily create a chess position in the same way, which is a complete\nstate of the chess game (i.e., the board and some extra information). Find\nbelow the diverse ways of creating the starting position::\n\n >>> position = Position()\n >>> position\n rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1\n >>> Position(\n ... board=DictBoard(),\n ... side_to_play=Side.WHITE,\n ... castling=Castling(\n ... CastlingSide(True, True),\n ... CastlingSide(True, True)),\n ... en_passant_target=None,\n ... half_move_clock=0,\n ... move_count=1)\n ...\n rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1\n >>> Position.from_fen('rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1')\n rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1\n >>> position.move_count\n 1\n\nIf Forsyth-Edwards Notation is too terse, you can easily get some pretty output\ninstead::\n\n >>> print(board.pretty())\n A B C D E F G H\n 8 r n b q k b n r\n 7 p p p p p p p p\n 6 . . . . . . . .\n 5 . . . . . . . .\n 4 . . . . . . . .\n 3 . . . . . . . .\n 2 P P P P P P P P\n 1 R N B Q K B N R\n >>> print(position.pretty())\n A B C D E F G H\n 8 r n b q k b n r\n 7 p p p p p p p p\n 6 . . . . . . . .\n 5 . . . . . . . .\n 4 . . . . . . . .\n 3 . . . . . . . .\n 2 P P P P P P P P\n 1 R N B Q K B N R\n \n FEN: rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1\n\nBoards and positions are immutable data containers. Whenever you would normally\nchange the state of a position, you simply create a new one and discard the old\none. Though typically you let En Pyssant create the new position for you by\nperforming moves upon the board::\n\n >>> move = Move('a2', 'a3')\n >>> new_position = do_move(position, move)\n >>> new_position\n rnbqkbnr/pppppppp/8/8/8/P7/1PPPPPPP/RNBQKBNR b KQkq - 0 1\n >>> print(new_position.board.pretty())\n A B C D E F G H\n 8 r n b q k b n r\n 7 p p p p p p p p\n 6 . . . . . . . .\n 5 . . . . . . . .\n 4 . . . . . . . .\n 3 P . . . . . . .\n 2 . P P P P P P P\n 1 R N B Q K B N R\n\nYou can also use `Standard Algebraic Notation\n`_ to do moves. You\nare allowed to be a little creative in creating your SAN strings. The parser is\nfairly tolerant and permissive::\n\n >>> san = 'a3' # or 'Pa3', or 'a2a3', or 'Pa2-a3'\n >>> assert new_position == do_move(position, san)\n\nYou can easily obtain a list of all moves or perform other game logic upon the\nposition. There are 20 legal moves at the start of any chess game::\n\n >>> assert len(list(moves(position))) == 20\n >>> is_check(position)\n False\n >>> is_checkmate(position)\n False\n\nYou are also provided with a simple wrapper that keeps track of the current\nposition and the history of the game for you. Below a simple game of `Fool's\nMate `_::\n\n >>> game = Game()\n >>> game.position\n rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1\n >>> game.do_move('f3')\n rnbqkbnr/pppppppp/8/8/8/5P2/PPPPP1PP/RNBQKBNR b KQkq - 0 1\n >>> game.do_move('e5')\n rnbqkbnr/pppp1ppp/8/4p3/8/5P2/PPPPP1PP/RNBQKBNR w KQkq e6 0 2\n >>> game.do_move('g4')\n rnbqkbnr/pppp1ppp/8/4p3/6P1/5P2/PPPPP2P/RNBQKBNR b KQkq g3 0 2\n >>> game.do_move('Qh4#')\n rnb1kbnr/pppp1ppp/8/4p3/6Pq/5P2/PPPPP2P/RNBQKBNR w KQkq - 1 3\n >>> print(game.position.board.pretty())\n A B C D E F G H\n 8 r n b . k b n r\n 7 p p p p . p p p\n 6 . . . . . . . .\n 5 . . . . p . . .\n 4 . . . . . . P q\n 3 . . . . . P . .\n 2 P P P P P . . P\n 1 R N B Q K B N R\n >>> game.is_gameover()\n \n >>> game.winner()\n \n >>> assert len(game.history) == 4\n\nYou can also export (and import) the game as `Portable Game Notation\n`_::\n\n >>> pgn = game.pgn()\n >>> print(pgn)\n [Result \"0-1\"]\n \n 1. f3 e5 2. g4 Qh4# 0-1\n >>> new_game = Game.from_pgn(pgn)\n >>> new_game.winner()\n \n\nThe simplest way to play a complete game of chess::\n\n >>> game = Game()\n >>> while not game.is_gameover():\n ... new_position = game.do_move(next(game.moves()))\n ...\n >>> assert game.is_gameover()\n\nThe most interesting thing, however, is to let the computer play for you. Below\na simple example of utilising the engine::\n\n >>> engine = MCTSEngine()\n >>> # Let the engine do its thinking magic for a few seconds.\n >>> engine.think_for(3)\n True\n >>> engine.is_thinking() # Thinking has just finished.\n False\n >>> best_move = engine.best_move()\n >>> position = engine.do_move(best_move)\n >>> assert position == engine.position\n >>>\n >>> # You can also let the engine think in a subthread.\n >>> thread = threading.Thread(target=engine.think_for, args=(0,))\n >>> thread.start()\n >>> time.sleep(0.2)\n >>> # The engine is now thinking infinitely in another thread.\n >>> engine.is_thinking()\n True\n >>> # You can query the object while the engine is calculating.\n >>> new_best_move = engine.best_move()\n >>> assert best_move != new_best_move\n >>> _ = engine.do_move(new_best_move)\n >>> engine.is_thinking()\n True\n >>> # Cannot think again while thinking.\n >>> engine.think_for(0)\n False\n >>> engine.stop_thinking()\n >>> thread.join()\n\n\nMaintainer\n==========\n\nCarmen Bianca Bakker .\n\n\nContribute\n==========\n\nAny merge requests or suggestions are welcome at\n``_ or via e-mail to one of the\nmaintainers.\n\nStarting local development is very simple. Just execute the following\ncommands::\n\n git clone git@gitlab.com:carmenbianca/en-pyssant.git\n cd en-pyssant/\n python3 -mvenv venv\n source venv/bin/activate\n make develop\n\nYou need to run ``make develop`` at least once to set up the virtualenv.\n\nNext, run ``make help`` to see the available interactions.\n\nWhen submitting a merge request, please make sure that all the tests pass. If\npossible, also provide additional tests to accompany the changed functionality.\nAlways add a change log entry, and make sure to add yourself to AUTHORS.rst.\n\nYou are required to add a copyright notice to the files you have changed. It is\nassumed that you license the changes in your merge request under the licence\nspecified in the header of those files. If not, please be specific. See\n``_ for more information on licensing.\n\n\nLicence\n=======\n\nGNU General Public License version 3 or later.\n\n\n..\n Copyright (C) 2017-2018 Carmen Bianca Bakker \n\n This file is part of En Pyssant, available from its original location:\n .\n\n This work is licensed under the Creative Commons Attribution-ShareAlike\n 4.0 International License. To view a copy of this license, visit\n .\n\n SPDX-License-Identifier: CC-BY-SA-4.0\n\n==========\nChange log\n==========\n\nThis change log follows the `Keep a Changelog `_\nspec. Every release contains the following sections:\n\n- *Added* for new features.\n\n- *Changed* for changes in existing functionality.\n\n- *Deprecated* for soon-to-be removed features.\n\n- *Removed* for now removed features.\n\n- *Fixed* for any bug fixes.\n\n- *Security* in case of vulnerabilities.\n\nThe versions follow `semantic versioning `_.\n\n\n0.2.0 (2018-07-04)\n==================\n\nAdded\n-----\n\n- ``moves_single`` now complements ``moves`` as a function that generates all\n legal moves for a single origin square.\n\n- ``BitBoard`` and ``TupleBoard`` added.\n\n- Added ``Piece.from_str``.\n\n- Added ``do_move_with_history``, which returns a ``(Position, HistoryRecord)``\n tuple.\n\n- ``ParallelEngine`` (base class) and ``MCTSEngine`` added. There is now a\n fully functional engine that isn't ``RandomEngine``.\n\n- Added more methods to ``Engine``.\n\nChanged\n-------\n\n- ``CastlingAvailability`` has been replaced with ``CastlingSide``. Positions\n now no longer contain a dictionary of ``CastlingAvailability`` objects, but a\n ``Castling`` object. For example:\n\n ``castling = {Side.WHITE: CastlingAvailability(True, True), Side.BLACK:\n CastlingAvailability(True, True)``\n\n is now\n\n ``castling = Castling(CastlingSide(True, True), CastlingSide(True, True))``\n\n In effect, this makes ``Position`` objects hashable and entirely immutable.\n\n The new ``Castling`` class still permits key lookup. So\n ``castling[Side.WHITE].kingside`` remains valid.\n\n- ``Square.in_bounds`` and ``Square.goto`` now also accept ``(int, int)`` tuples\n in lieue of ``Direction`` objects. This is more performant because tuples\n hash quicker.\n\n- ``Board.all_pieces`` now starts at a1 and goes to h8.\n\n- Changed some code around to be more\n ``threading``/``multiprocessing``-friendly.\n\n- Changed the public interface of ``Engine``. Specifically:\n\n + ``Engine.__init__`` now takes a position, history and ruleset instead of a\n game.\n\n + ``Engine.think_for`` returns True. If another thread is already thinking,\n it returns False and does not begin thinking.\n\n + ``Engine.stop_thinking`` takes an additional ``blocking`` keyword argument.\n\n\n0.1.7 (2018-04-02)\n==================\n\nChanged\n-------\n\n- Re-release to fix the documentation. No changes in the codebase.\n\n\n0.1.5 (2018-03-13)\n==================\n\n- First release.\n\n- Contains almost all functionality except the chess engine itself. You can\n play chess, basically. Just not against a hyper-intelligent computer.\n\n\n", "description_content_type": "", "docs_url": null, "download_url": "", "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "home_page": "https://gitlab.com/carmenbianca/en-pyssant", "keywords": "", "license": "GPL-3.0+", "maintainer": "", "maintainer_email": "", "name": "en-pyssant", "package_url": "https://pypi.org/project/en-pyssant/", "platform": "", "project_url": "https://pypi.org/project/en-pyssant/", "project_urls": { "Homepage": "https://gitlab.com/carmenbianca/en-pyssant" }, "release_url": "https://pypi.org/project/en-pyssant/0.2.0/", "requires_dist": null, "requires_python": "", "summary": "En Pyssant is a chess implementation and engine", "version": "0.2.0" }, "last_serial": 4030449, "releases": { "0.1.5": [ { "comment_text": "", "digests": { "md5": "1200c1f8dcd3030c5c6163a8df030ae6", "sha256": "03e13184361e324ff75daf6d0d2720848849e385df141f90d97d41f49484a99f" }, "downloads": -1, "filename": "en_pyssant-0.1.5-py3-none-any.whl", "has_sig": true, "md5_digest": "1200c1f8dcd3030c5c6163a8df030ae6", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 35539, "upload_time": "2018-03-13T16:39:03", "url": "https://files.pythonhosted.org/packages/23/93/6454e5956da5cbae4971ad1d19c1710adefacbca7863b09700091e38457c/en_pyssant-0.1.5-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "a2ae05070095bd1dd66e6277e7086d21", "sha256": "a4024673eeebb3d7e4005b48a18c879181cd903c89ac111ab389c0f91b7a228f" }, "downloads": -1, "filename": "en-pyssant-0.1.5.tar.gz", "has_sig": true, "md5_digest": "a2ae05070095bd1dd66e6277e7086d21", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 56174, "upload_time": "2018-03-13T16:39:05", "url": "https://files.pythonhosted.org/packages/f9/bc/115ad6b054bbe549b655844524d35aba3e7415a33dfc52eefb0199935577/en-pyssant-0.1.5.tar.gz" } ], "0.1.7": [ { "comment_text": "", "digests": { "md5": "9cfc29bede60513b8c7fad5312f1c37c", "sha256": "ebec921ec1d52a47358c2bf13fe6d51ce8b9e84b20938a451dd00ba573d7d31d" }, "downloads": -1, "filename": "en_pyssant-0.1.7-py3-none-any.whl", "has_sig": true, "md5_digest": "9cfc29bede60513b8c7fad5312f1c37c", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 35600, "upload_time": "2018-04-02T10:09:57", "url": "https://files.pythonhosted.org/packages/7c/57/d71ae3b9268fee7086d1d37ed335e6c3d6dc9a709a3cb6d58874d59ad2a7/en_pyssant-0.1.7-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "df85a2efa61bc7775ff36064ab52ded6", "sha256": "abeccbab5f80d34a2f41cd2496e7a0c9a8699a4434a08b9846b69b4ef0a86b8d" }, "downloads": -1, "filename": "en-pyssant-0.1.7.tar.gz", "has_sig": true, "md5_digest": "df85a2efa61bc7775ff36064ab52ded6", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 57027, "upload_time": "2018-04-02T10:09:58", "url": "https://files.pythonhosted.org/packages/f8/b4/eca44b37970ab17f2ddd9d69a6b11a65a54eff22065aba0ea0bbca5c2768/en-pyssant-0.1.7.tar.gz" } ], "0.2.0": [ { "comment_text": "", "digests": { "md5": "2e2b3a6f3fc3a809b2381a8f58cbf625", "sha256": "c056cc75bd462aa7f91c6d25b055f1561f7d6fdd66cdd06fd3ae090349e89a1f" }, "downloads": -1, "filename": "en_pyssant-0.2.0-py3-none-any.whl", "has_sig": true, "md5_digest": "2e2b3a6f3fc3a809b2381a8f58cbf625", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 18066053, "upload_time": "2018-07-04T15:26:53", "url": "https://files.pythonhosted.org/packages/70/36/a873a73e4422784891b5cdbf974144b7de0294503878a32797c455b4fb1c/en_pyssant-0.2.0-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "9a909829fe130f055eab93ce21454215", "sha256": "2311fe381fe79e0c48be9a3ef9b2335ea23c11463ddd6b4e7c3a6168bb4efb02" }, "downloads": -1, "filename": "en-pyssant-0.2.0.tar.gz", "has_sig": true, "md5_digest": "9a909829fe130f055eab93ce21454215", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 66958, "upload_time": "2018-07-04T15:26:57", "url": "https://files.pythonhosted.org/packages/c6/83/7cd9fa380be6cf005475073bb75fd94d4fb020281c776c9695646b921669/en-pyssant-0.2.0.tar.gz" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "2e2b3a6f3fc3a809b2381a8f58cbf625", "sha256": "c056cc75bd462aa7f91c6d25b055f1561f7d6fdd66cdd06fd3ae090349e89a1f" }, "downloads": -1, "filename": "en_pyssant-0.2.0-py3-none-any.whl", "has_sig": true, "md5_digest": "2e2b3a6f3fc3a809b2381a8f58cbf625", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 18066053, "upload_time": "2018-07-04T15:26:53", "url": "https://files.pythonhosted.org/packages/70/36/a873a73e4422784891b5cdbf974144b7de0294503878a32797c455b4fb1c/en_pyssant-0.2.0-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "9a909829fe130f055eab93ce21454215", "sha256": "2311fe381fe79e0c48be9a3ef9b2335ea23c11463ddd6b4e7c3a6168bb4efb02" }, "downloads": -1, "filename": "en-pyssant-0.2.0.tar.gz", "has_sig": true, "md5_digest": "9a909829fe130f055eab93ce21454215", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 66958, "upload_time": "2018-07-04T15:26:57", "url": "https://files.pythonhosted.org/packages/c6/83/7cd9fa380be6cf005475073bb75fd94d4fb020281c776c9695646b921669/en-pyssant-0.2.0.tar.gz" } ] }