# pokerlib
[![PyPI version](https://badge.fury.io/py/pokerlib.svg)](https://pypi.org/project/pokerlib)
A lightweight Python poker library, focusing on simplifying a Texas hold'em poker game implementation, when its io is supplied. It includes modules that help with hand parsing and poker game continuation.
To install, run
```bash
pip install pokerlib
```
If experiencing issues, specify the latest version as
```bash
pip install pokerlib==2.2.6
```
## Usage
Library consists of a module for parsing cards, which can be used separately, and modules that aid in running a poker game.
### HandParser
This module takes care of hand parsing. A hand usually consists of 2 dealt cards plus 5 on the board, and `HandParser` is heavily optimized to work with up to 7 cards (with more than 7 cards, this is no longer Texas hold'em). A card is defined as a pair of two enums - Rank and Suit. All of the enums used are of `IntEnum` type, so you can also freely interchange them for integers. Below is an example of how to construct two different hands and then compare them.
```python
from pokerlib import HandParser
from pokerlib.enums import Rank, Suit
hand1 = HandParser([
(Rank.KING, Suit.SPADE),
(Rank.ACE, Suit.SPADE)
])
hand2 = HandParser([
(Rank.NINE, Suit.SPADE),
(Rank.TWO, Suit.CLUB)
])
board = [
(Rank.EIGHT, Suit.SPADE),
(Rank.TEN, Suit.SPADE),
(Rank.JACK, Suit.SPADE),
(Rank.QUEEN, Suit.SPADE),
(Rank.TWO, Suit.HEART)
]
# add new cards to each hand
hand1 += board # add the board to hand1
hand2 += board # add the board to hand2
print(hand1.handenum) # Hand.STRAIGHTFLUSH
print(hand2.handenum) # Hand.STRAIGHTFLUSH
print(hand1 > hand2) # True
```
> **note:**
> In the previous version, each hand had to be parsed manually with `hand.parse()`, now calling any of the methods requiring the hand to be parsed, triggers parsing automatically. This only happens once, except if the cards in a given hand change. The only way cards in a hand should change is through the `__iadd__` method. If this method is called with hand already parsed, the hand is considered unparsed.
It is also possible to fetch hand's kickers.
```python
hand = HandParser([
(Rank.TWO, Suit.DIAMOND),
(Rank.ACE, Suit.CLUB),
(Rank.TWO, Suit.SPADE),
(Rank.THREE, Suit.DIAMOND),
(Rank.TEN, Suit.HEART),
(Rank.SIX, Suit.HEART),
(Rank.KING, Suit.CLUB)
])
print(list(hand.kickercards))
# [
# (<Rank.ACE: 12>, <Suit.CLUB: 1>),
# (<Rank.KING: 11>, <Suit.CLUB: 1>),
# (<Rank.TEN: 8>, <Suit.HEART: 3>)
# ]
```
Using HandParser, we can [estimate the probability](https://github.com/kuco23/pokerlib/blob/master/examples/winning_probability.py) of a given hand winning the game with given known cards on the table (as implemented in another python cli-app [here](https://github.com/cookpete/poker-odds)). We do this by repeatedly random-sampling hands, then averaging the wins. Mathematically, this process converges to the probability by the law of large numbers.
### Poker Game
A poker table can be established by providing its configuration.
A poker table object responds to given input with appropriate output,
which can be customized by overriding the two functions producing it.
```python
from pokerlib import Table, Player, PlayerSeats
# table that prints outputs
class MyTable(Table):
def publicOut(self, out_id, **kwargs):
print(out_id, kwargs)
def privateOut(self, player_id, out_id, **kwargs):
print(out_id, kwargs)
# define a new table
table = MyTable(
table_id = 0,
seats = PlayerSeats([None] * 9),
buyin = 100,
small_blind = 5,
big_blind = 10
)
```
We could have seated players on the `seats` inside `MyTable` constructor,
but let's add them to the defined table.
```python
player1 = Player(
table_id = table.id,
_id = 1,
name = 'alice',
money = table.buyin
)
player2 = Player(
table_id = table.id,
_id = 2,
name = 'bob',
money = table.buyin
)
# seat player1 at the first seat
table += player1, 0
# seat player2 at the first free seat
table += player2
```
Communication with the `table` object is established through specified enums,
which can be modified by overriding table's `publicIn` method.
Using enum IO identifiers, we can implement a poker game as shown below.
```python
from pokerlib.enums import RoundPublicInId, TablePublicInId
table.publicIn(player1.id, TablePublicInId.STARTROUND)
table.publicIn(player1.id, RoundPublicInId.CALL)
table.publicIn(player2.id, RoundPublicInId.CHECK)
table.publicIn(player1.id, RoundPublicInId.CHECK)
table.publicIn(player2.id, RoundPublicInId.RAISE, raise_by=50)
table.publicIn(player1.id, RoundPublicInId.CALL)
table.publicIn(player1.id, RoundPublicInId.CHECK)
table.publicIn(player2.id, RoundPublicInId.CHECK)
table.publicIn(player1.id, RoundPublicInId.ALLIN)
table.publicIn(player2.id, RoundPublicInId.CALL)
```
Wrong inputs are mostly ignored, though they can produce a response, when it seems useful. As noted before, when providing input, the `table` object responds with output ids (e.g. `PLAYERACTIONREQUIRED`) along with additional data that depends on the output id. For all possible outputs, check `RoundPublicInId` and `TablePublicInId` enums.
A simple command line game, where you respond with enum names, can be implemented simply as in `examples/round_simulate.py`. Command
```bash
python examples/round_simulate.py 3
```
runs a poker game with 3 players using the terminal as IO. Note that responses are in non-formatted raw form.
## Tests
Basic tests for this library are included. You can test `HandParser` by running
```bash
python tests/handparser_reactive.py
```
and `Round` with
```bash
python tests/round_test.py
```
Note that HandParser can be fuzz tested against another poker library [pokerface](https://github.com/AussieSeaweed/pokerface) with
```bash
python tests/handparser_against_pokerface.py
```
which means it is considered safe. On the other hand, `Table` may still have some bugs.
## License
GNU General Public License v3.0
Raw data
{
"_id": null,
"home_page": "https://github.com/kuco23/pokerlib/",
"name": "pokerlib",
"maintainer": "",
"docs_url": null,
"requires_python": ">=3.10,<4.0",
"maintainer_email": "",
"keywords": "python,poker,library",
"author": "kuco23",
"author_email": "nseverkar@gmail.com",
"download_url": "https://files.pythonhosted.org/packages/2a/33/702ac8f9d3a6e674c82319001a1bfc23f9f5ddb0aff63c6f5e5ae71f1570/pokerlib-2.2.7.tar.gz",
"platform": null,
"description": "# pokerlib\n[![PyPI version](https://badge.fury.io/py/pokerlib.svg)](https://pypi.org/project/pokerlib)\n\nA lightweight Python poker library, focusing on simplifying a Texas hold'em poker game implementation, when its io is supplied. It includes modules that help with hand parsing and poker game continuation.\n\nTo install, run\n```bash\npip install pokerlib\n```\n\nIf experiencing issues, specify the latest version as\n```bash\npip install pokerlib==2.2.6\n```\n\n## Usage\nLibrary consists of a module for parsing cards, which can be used separately, and modules that aid in running a poker game.\n\n### HandParser\nThis module takes care of hand parsing. A hand usually consists of 2 dealt cards plus 5 on the board, and `HandParser` is heavily optimized to work with up to 7 cards (with more than 7 cards, this is no longer Texas hold'em). A card is defined as a pair of two enums - Rank and Suit. All of the enums used are of `IntEnum` type, so you can also freely interchange them for integers. Below is an example of how to construct two different hands and then compare them.\n\n```python\nfrom pokerlib import HandParser\nfrom pokerlib.enums import Rank, Suit\n\nhand1 = HandParser([\n (Rank.KING, Suit.SPADE),\n (Rank.ACE, Suit.SPADE)\n])\n\nhand2 = HandParser([\n (Rank.NINE, Suit.SPADE),\n (Rank.TWO, Suit.CLUB)\n])\n\nboard = [\n (Rank.EIGHT, Suit.SPADE),\n (Rank.TEN, Suit.SPADE),\n (Rank.JACK, Suit.SPADE),\n (Rank.QUEEN, Suit.SPADE),\n (Rank.TWO, Suit.HEART)\n]\n\n# add new cards to each hand\nhand1 += board # add the board to hand1\nhand2 += board # add the board to hand2\n\nprint(hand1.handenum) # Hand.STRAIGHTFLUSH\nprint(hand2.handenum) # Hand.STRAIGHTFLUSH\nprint(hand1 > hand2) # True\n```\n\n> **note:**\n> In the previous version, each hand had to be parsed manually with `hand.parse()`, now calling any of the methods requiring the hand to be parsed, triggers parsing automatically. This only happens once, except if the cards in a given hand change. The only way cards in a hand should change is through the `__iadd__` method. If this method is called with hand already parsed, the hand is considered unparsed.\n\nIt is also possible to fetch hand's kickers.\n\n```python\nhand = HandParser([\n (Rank.TWO, Suit.DIAMOND),\n (Rank.ACE, Suit.CLUB),\n (Rank.TWO, Suit.SPADE),\n (Rank.THREE, Suit.DIAMOND),\n (Rank.TEN, Suit.HEART),\n (Rank.SIX, Suit.HEART),\n (Rank.KING, Suit.CLUB)\n])\n\nprint(list(hand.kickercards))\n# [\n# (<Rank.ACE: 12>, <Suit.CLUB: 1>),\n# (<Rank.KING: 11>, <Suit.CLUB: 1>),\n# (<Rank.TEN: 8>, <Suit.HEART: 3>)\n# ]\n```\nUsing HandParser, we can [estimate the probability](https://github.com/kuco23/pokerlib/blob/master/examples/winning_probability.py) of a given hand winning the game with given known cards on the table (as implemented in another python cli-app [here](https://github.com/cookpete/poker-odds)). We do this by repeatedly random-sampling hands, then averaging the wins. Mathematically, this process converges to the probability by the law of large numbers.\n\n\n### Poker Game\nA poker table can be established by providing its configuration.\nA poker table object responds to given input with appropriate output,\nwhich can be customized by overriding the two functions producing it.\n\n```python\nfrom pokerlib import Table, Player, PlayerSeats\n\n# table that prints outputs\nclass MyTable(Table):\n def publicOut(self, out_id, **kwargs):\n print(out_id, kwargs)\n def privateOut(self, player_id, out_id, **kwargs):\n print(out_id, kwargs)\n\n# define a new table\ntable = MyTable(\n table_id = 0,\n seats = PlayerSeats([None] * 9),\n buyin = 100,\n small_blind = 5,\n big_blind = 10\n)\n```\n\nWe could have seated players on the `seats` inside `MyTable` constructor,\nbut let's add them to the defined table.\n\n```python\nplayer1 = Player(\n table_id = table.id,\n _id = 1,\n name = 'alice',\n money = table.buyin\n)\nplayer2 = Player(\n table_id = table.id,\n _id = 2,\n name = 'bob',\n money = table.buyin\n)\n# seat player1 at the first seat\ntable += player1, 0\n# seat player2 at the first free seat\ntable += player2\n```\n\nCommunication with the `table` object is established through specified enums,\nwhich can be modified by overriding table's `publicIn` method.\nUsing enum IO identifiers, we can implement a poker game as shown below.\n\n```python\nfrom pokerlib.enums import RoundPublicInId, TablePublicInId\n\ntable.publicIn(player1.id, TablePublicInId.STARTROUND)\ntable.publicIn(player1.id, RoundPublicInId.CALL)\ntable.publicIn(player2.id, RoundPublicInId.CHECK)\ntable.publicIn(player1.id, RoundPublicInId.CHECK)\ntable.publicIn(player2.id, RoundPublicInId.RAISE, raise_by=50)\ntable.publicIn(player1.id, RoundPublicInId.CALL)\ntable.publicIn(player1.id, RoundPublicInId.CHECK)\ntable.publicIn(player2.id, RoundPublicInId.CHECK)\ntable.publicIn(player1.id, RoundPublicInId.ALLIN)\ntable.publicIn(player2.id, RoundPublicInId.CALL)\n```\n\nWrong inputs are mostly ignored, though they can produce a response, when it seems useful. As noted before, when providing input, the `table` object responds with output ids (e.g. `PLAYERACTIONREQUIRED`) along with additional data that depends on the output id. For all possible outputs, check `RoundPublicInId` and `TablePublicInId` enums.\n\nA simple command line game, where you respond with enum names, can be implemented simply as in `examples/round_simulate.py`. Command\n```bash\npython examples/round_simulate.py 3\n```\nruns a poker game with 3 players using the terminal as IO. Note that responses are in non-formatted raw form.\n\n\n## Tests\nBasic tests for this library are included. You can test `HandParser` by running\n```bash\npython tests/handparser_reactive.py\n```\nand `Round` with\n```bash\npython tests/round_test.py\n```\nNote that HandParser can be fuzz tested against another poker library [pokerface](https://github.com/AussieSeaweed/pokerface) with\n```bash\npython tests/handparser_against_pokerface.py\n```\nwhich means it is considered safe. On the other hand, `Table` may still have some bugs.\n\n## License\nGNU General Public License v3.0\n",
"bugtrack_url": null,
"license": "",
"summary": "Python poker library",
"version": "2.2.7",
"project_urls": {
"Homepage": "https://github.com/kuco23/pokerlib/",
"Repository": "https://github.com/kuco23/pokerlib/"
},
"split_keywords": [
"python",
"poker",
"library"
],
"urls": [
{
"comment_text": "",
"digests": {
"blake2b_256": "fca7aebee0b0d0243ef5f4a66167b82ffae4a529df3629a32eb6173ab76065dc",
"md5": "09c0373d539043502798ce72e635baef",
"sha256": "605d17bad00ffb611e2eb13a817de51bbbafcb42b9969b68482807917db76570"
},
"downloads": -1,
"filename": "pokerlib-2.2.7-py3-none-any.whl",
"has_sig": false,
"md5_digest": "09c0373d539043502798ce72e635baef",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": ">=3.10,<4.0",
"size": 39880,
"upload_time": "2023-09-09T09:44:57",
"upload_time_iso_8601": "2023-09-09T09:44:57.514527Z",
"url": "https://files.pythonhosted.org/packages/fc/a7/aebee0b0d0243ef5f4a66167b82ffae4a529df3629a32eb6173ab76065dc/pokerlib-2.2.7-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": "",
"digests": {
"blake2b_256": "2a33702ac8f9d3a6e674c82319001a1bfc23f9f5ddb0aff63c6f5e5ae71f1570",
"md5": "43f8b9190c92220b7ac7fdf8a1d8d44a",
"sha256": "12929a6e1e960363481f0faefeb537c69e4c3ce7a7a2e068b3ebffb01eee490b"
},
"downloads": -1,
"filename": "pokerlib-2.2.7.tar.gz",
"has_sig": false,
"md5_digest": "43f8b9190c92220b7ac7fdf8a1d8d44a",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3.10,<4.0",
"size": 26657,
"upload_time": "2023-09-09T09:44:59",
"upload_time_iso_8601": "2023-09-09T09:44:59.962966Z",
"url": "https://files.pythonhosted.org/packages/2a/33/702ac8f9d3a6e674c82319001a1bfc23f9f5ddb0aff63c6f5e5ae71f1570/pokerlib-2.2.7.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2023-09-09 09:44:59",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "kuco23",
"github_project": "pokerlib",
"travis_ci": false,
"coveralls": false,
"github_actions": false,
"lcname": "pokerlib"
}