Skip to main content

En Pyssant is a chess implementation and engine

Project description

En Pyssant

En Pyssant is a chess implementation and engine.

Background

En Pyssant is a hobby project to implement a complete chess implementation and engine in Python with a simple, straightforward API. The public API is thusly documented and implemented that it should be relatively simple to swap out individual components with different implementations.

The focus is on keeping the API clean and flexible. This may come at the cost of performance, but if performance were the primary goal, perhaps it mightn’t have been a good idea to use Python in the first place.

The goal is to keep the project thoroughly tested with unit and integration tests. More of the latter than the former.

Install

Installing En Pyssant should be a simple matter of executing the following command:

pip3 install --user en-pyssant

Usage

Longum iter est per praecepta, breve et efficax per exempla—It’s a long way by the rules, but short and efficient with examples.

First, import everything:

>>> from en_pyssant import *
>>> from en_pyssant.rules import *
>>> # Technically you should never star-import, but it makes
>>> # the examples easier.

En Pyssant has a few core data types:

>>> white_pawn = Piece(Type.PAWN, Side.WHITE)
>>> white_pawn
Piece(type=<Type.PAWN: 'p'>, side=<Side.WHITE: 1>)
>>> a1 = Square('a1')
>>> a1.up().up()
'a3'

You can easily create a starting board, or import any other board layout from partial Forsyth-Edwards Notation (FEN):

>>> board = DictBoard()
>>> board
rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR
>>> DictBoard.from_fen('rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR')
rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR
>>> board[a1]
Piece(type=<Type.ROOK: 'r'>, side=<Side.WHITE: 1>)
>>> print(board['a3'])
None
>>> board.put('a3', white_pawn)
rnbqkbnr/pppppppp/8/8/8/P7/PPPPPPPP/RNBQKBNR

You can also easily create a chess position in the same way, which is a complete state of the chess game (i.e., the board and some extra information). Find below the diverse ways of creating the starting position:

>>> position = Position()
>>> position
rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1
>>> Position(
...     board=DictBoard(),
...     side_to_play=Side.WHITE,
...     castling={Side.WHITE: CastlingAvailability(True, True),
...               Side.BLACK: CastlingAvailability(True, True)},
...     en_passant_target=None,
...     half_move_clock=0,
...     move_count=1)
...
rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1
>>> Position.from_fen('rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1')
rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1
>>> position.move_count
1

If Forsyth-Edwards Notation is too terse, you can easily get some pretty output instead:

>>> print(board.pretty())
  A B C D E F G H
8 r n b q k b n r
7 p p p p p p p p
6 . . . . . . . .
5 . . . . . . . .
4 . . . . . . . .
3 . . . . . . . .
2 P P P P P P P P
1 R N B Q K B N R
>>> print(position.pretty())
  A B C D E F G H
8 r n b q k b n r
7 p p p p p p p p
6 . . . . . . . .
5 . . . . . . . .
4 . . . . . . . .
3 . . . . . . . .
2 P P P P P P P P
1 R N B Q K B N R
<BLANKLINE>
FEN: rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1

Boards and positions are immutable data containers. Whenever you would normally change the state of a position, you simply create a new one and discard the old one. Though typically you let En Pyssant create the new position for you by performing moves upon the board:

>>> move = Move('a2', 'a3')
>>> new_position = do_move(position, move)
>>> new_position
rnbqkbnr/pppppppp/8/8/8/P7/1PPPPPPP/RNBQKBNR b KQkq - 0 1
>>> print(new_position.board.pretty())
  A B C D E F G H
8 r n b q k b n r
7 p p p p p p p p
6 . . . . . . . .
5 . . . . . . . .
4 . . . . . . . .
3 P . . . . . . .
2 . P P P P P P P
1 R N B Q K B N R

You can also use Standard Algebraic Notation to do moves. You are allowed to be a little creative in creating your SAN strings. The parser is fairly tolerant and permissive:

>>> san = 'a3'  # or 'Pa3', or 'a2a3', or 'Pa2-a3'
>>> assert new_position == do_move(position, san)

You can easily obtain a list of all moves or perform other game logic upon the position. There are 20 legal moves at the start of any chess game:

>>> assert len(list(moves(position))) == 20
>>> is_check(position)
False
>>> is_checkmate(position)
False

You are also provided with a simple wrapper that keeps track of the current position and the history of the game for you. Below a simple game of Fool’s Mate:

>>> game = Game()
>>> game.position
rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1
>>> game.do_move('f3')
rnbqkbnr/pppppppp/8/8/8/5P2/PPPPP1PP/RNBQKBNR b KQkq - 0 1
>>> game.do_move('e5')
rnbqkbnr/pppp1ppp/8/4p3/8/5P2/PPPPP1PP/RNBQKBNR w KQkq e6 0 2
>>> game.do_move('g4')
rnbqkbnr/pppp1ppp/8/4p3/6P1/5P2/PPPPP2P/RNBQKBNR b KQkq g3 0 2
>>> game.do_move('Qh4#')
rnb1kbnr/pppp1ppp/8/4p3/6Pq/5P2/PPPPP2P/RNBQKBNR w KQkq - 1 3
>>> print(game.position.board.pretty())
  A B C D E F G H
8 r n b . k b n r
7 p p p p . p p p
6 . . . . . . . .
5 . . . . p . . .
4 . . . . . . P q
3 . . . . . P . .
2 P P P P P . . P
1 R N B Q K B N R
>>> game.is_gameover()
<Gameover.CHECKMATE: 1>
>>> game.winner()
<Side.BLACK: 0>
>>> assert len(game.history) == 4

You can also export (and import) the game as Portable Game Notation:

>>> pgn = game.pgn()
>>> print(pgn)
[Result "0-1"]
<BLANKLINE>
1. f3 e5 2. g4 Qh4# 0-1
>>> new_game = Game.from_pgn(pgn)
>>> new_game.winner()
<Side.BLACK: 0>

The simplest way to play a complete game of chess:

>>> game = Game()
>>> while not game.is_gameover():
...     new_position = game.do_move(next(game.moves()))
...
>>> assert game.is_gameover()

TODO: The engine portion of En Pyssant is a work in progress, and doesn’t really work yet. When it does work, this section will be updated to reflect its usage.

Maintainer

Carmen Bianca Bakker <carmen@carmenbianca.eu>.

Contribute

Any merge requests or suggestions are welcome at https://gitlab.com/carmenbianca/en-pyssant or via e-mail to one of the maintainers.

Starting local development is very simple. Just execute the following commands:

git clone git@gitlab.com:carmenbianca/en-pyssant.git
cd en-pyssant/
python3 -mvenv venv
source venv/bin/activate
make develop

You need to run make develop at least once to set up the virtualenv.

Next, run make help to see the available interactions.

When submitting a merge request, please make sure that all the tests pass. If possible, also provide additional tests to accompany the changed functionality. Always add a change log entry, and make sure to add yourself to AUTHORS.rst.

You are required to add a copyright notice to the files you have changed. It is assumed that you license the changes in your merge request under the licence specified in the header of those files. If not, please be specific. See https://reuse.software/ for more information on licensing.

Licence

GNU General Public License version 3 or later.

Change log

0.1.7 (2018-04-02)

Changed

  • Re-release to fix the documentation. No changes in the codebase.

0.1.5 (2018-03-13)

  • First release.

  • Contains almost all functionality except the chess engine itself. You can play chess, basically. Just not against a hyper-intelligent computer.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

en-pyssant-0.1.7.tar.gz (57.0 kB view details)

Uploaded Source

Built Distribution

en_pyssant-0.1.7-py3-none-any.whl (35.6 kB view details)

Uploaded Python 3

File details

Details for the file en-pyssant-0.1.7.tar.gz.

File metadata

  • Download URL: en-pyssant-0.1.7.tar.gz
  • Upload date:
  • Size: 57.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No

File hashes

Hashes for en-pyssant-0.1.7.tar.gz
Algorithm Hash digest
SHA256 abeccbab5f80d34a2f41cd2496e7a0c9a8699a4434a08b9846b69b4ef0a86b8d
MD5 df85a2efa61bc7775ff36064ab52ded6
BLAKE2b-256 f8b4eca44b37970ab17f2ddd9d69a6b11a65a54eff22065aba0ea0bbca5c2768

See more details on using hashes here.

File details

Details for the file en_pyssant-0.1.7-py3-none-any.whl.

File metadata

File hashes

Hashes for en_pyssant-0.1.7-py3-none-any.whl
Algorithm Hash digest
SHA256 ebec921ec1d52a47358c2bf13fe6d51ce8b9e84b20938a451dd00ba573d7d31d
MD5 9cfc29bede60513b8c7fad5312f1c37c
BLAKE2b-256 7c57d71ae3b9268fee7086d1d37ed335e6c3d6dc9a709a3cb6d58874d59ad2a7

See more details on using hashes here.

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page