# Toulouse: A High-Performance Card Game Library for Scientific Computing
**Toulouse** is a Python library engineered for the high-performance simulation and vectorisation of card games, with a primary focus on applications in reinforcement learning (RL) and Monte Carlo Tree Search (MCTS).
It provides a robust, type-annotated, and efficient foundation for researchers and developers who require rapid state manipulation and observation generation for card-based environments.
---
## Key Features
- **Performance-Oriented Design**: Implements object pooling, LRU caching, and pre-computed state vectors to minimise computational overhead in large-scale simulations.
- **Vectorised State Representation**: Natively generates NumPy array representations for `Card` and `Deck` objects, suitable for direct integration with machine learning frameworks.
- **Extensible Card Systems**: Supports multiple card game configurations (e.g., Italian 40-card, Spanish 40-card) and allows users to register custom systems dynamically.
- **Internationalisation**: Built-in support for multiple languages (en, fr, it, es) via a centralised translation module.
- **Type-Safe and Tested**: A fully type-annotated codebase with a comprehensive `pytest` test suite to ensure reliability.
---
## Core Design & Architecture
Toulouse achieves its performance through several key architectural decisions:
1. **`Card` Object Pooling**: The `get_card()` factory function ensures that each unique `Card` instance is created only once. Subsequent requests for the same card return a cached reference from a global pool, significantly reducing object creation overhead and memory footprint.
2. **LRU-Cached System Lookups**: The `get_card_system()` function is decorated with `@lru_cache`, ensuring that card system configuration data is retrieved from memory after the initial lookup.
3. **Lazy State Vectorisation**: Each `Deck` instance maintains a private `_state_cache` (a NumPy array). This cache is only recomputed when the deck's composition changes (tracked by a `_state_dirty` flag), making repeated access to the `.state` property exceptionally fast.
---
## Installation
Install the library using `pip` or `uv`:
```bash
# Using pip
pip install toulouse
# Using uv
uv add toulouse
```
---
## Quick Start
```python
from toulouse import Deck, get_card
# 1. Initialise a new 40-card Italian deck.
# The default language is Italian ('it').
deck = Deck.new_deck(card_system_key="italian_40", language="fr")
print(deck) # Output: Deck of 40 cards (italian_40)
# 2. Draw the top card from the deck.
deck.shuffle()
hand = deck.draw(1)
drawn_card = hand[0]
print(f"Carte piochée: {drawn_card.to_string('fr')}") # Output: Carte piochée: [Card Name]
# 3. Use the factory function to get a specific card instance.
ace_of_spades = get_card(value=1, suit=2, card_system_key="italian_40")
# 4. Check for card presence (O(1) complexity).
print(f"Le deck contient-il l'As d'Épées? {deck.contains(ace_of_spades)}")
# 5. Get the deck's state as a NumPy vector for ML applications.
state_vector = deck.state
print(f"Shape of state vector: {state_vector.shape}") # Output: Shape of state vector: (40,)
# 6. Display the contents of the deck, grouped by suit.
deck.sort()
print(deck.pretty_print())
```
---
## API Reference
### `get_card()` Factory Function
This is the recommended method for obtaining `Card` instances.
`get_card(value: int, suit: int, card_system_key: str = "italian_40") -> Card`
### `Card` Class
An immutable, hashable data class representing a single card.
- `card.value: int`
- `card.suit: int`
- `card.to_index() -> int`: Returns the card's unique integer index within its system.
- `card.state -> np.ndarray`: Returns a one-hot encoded NumPy vector of the card's state.
- `card.to_string(language: str) -> str`: Returns a localised string representation.
### `Deck` Class
A mutable container for a collection of `Card` objects.
- `Deck.new_deck(card_system_key, language, sorted_deck)`: Class method to create a new, full deck.
- `Deck.from_cards(cards, card_system_key, language)`: Class method to create a deck from an existing list of cards.
- `deck.draw(n: int)`: Removes and returns `n` cards from the top of the deck.
- `deck.append(card: Card)`: Adds a card to the bottom of the deck.
- `deck.contains(card: Card) -> bool`: Checks for the presence of a card (O(1) complexity).
- `deck.state -> np.ndarray`: Returns a binary NumPy vector representing the current state of the deck.
- `deck.shuffle()`: Shuffles the deck in-place.
- `deck.sort()`: Sorts the deck in-place based on card index.
- `deck.reset()`: Restores the deck to its full, sorted state.
- `deck.pretty_print() -> str`: Returns a formatted string of the deck's contents, grouped by suit.
### Card System Management
- `register_card_system(key: str, config: dict)`: Registers a new card system configuration.
- `get_card_system(key: str) -> dict`: Retrieves a card system's configuration dictionary.
---
## Performance Benchmarks
The following benchmarks were recorded on an Apple M-series CPU with Python 3.11.
- **Deck Instantiation (1,000 iterations)**: ~6.2 ms
- **Shuffle, Draw & Reset (1,000 iterations)**: ~9.9 ms
- **Card Lookup (10,000 iterations)**: ~0.6 ms
- **State Vectorisation (10,000 iterations)**: ~4.2 ms
These results demonstrate the library's suitability for performance-critical applications.
---
## Testing
To run the test suite, execute `pytest` from the project root:
```bash
pytest
```
---
## Licence
This project is licensed under the MIT Licence.
Raw data
{
"_id": null,
"home_page": null,
"name": "toulouse",
"maintainer": null,
"docs_url": null,
"requires_python": ">=3.9",
"maintainer_email": null,
"keywords": "cards, game, reinforcement-learning, mcts, numpy",
"author": "mlabarrere",
"author_email": "Your Name <your.email@example.com>",
"download_url": "https://files.pythonhosted.org/packages/f2/ce/93c872d9122d724ec10294e77c7a2a16714ca1793f40f039d78e0bd80bb3/toulouse-1.1.1.tar.gz",
"platform": null,
"description": "# Toulouse: A High-Performance Card Game Library for Scientific Computing\n\n**Toulouse** is a Python library engineered for the high-performance simulation and vectorisation of card games, with a primary focus on applications in reinforcement learning (RL) and Monte Carlo Tree Search (MCTS).\n\nIt provides a robust, type-annotated, and efficient foundation for researchers and developers who require rapid state manipulation and observation generation for card-based environments.\n\n---\n\n## Key Features\n\n- **Performance-Oriented Design**: Implements object pooling, LRU caching, and pre-computed state vectors to minimise computational overhead in large-scale simulations.\n- **Vectorised State Representation**: Natively generates NumPy array representations for `Card` and `Deck` objects, suitable for direct integration with machine learning frameworks.\n- **Extensible Card Systems**: Supports multiple card game configurations (e.g., Italian 40-card, Spanish 40-card) and allows users to register custom systems dynamically.\n- **Internationalisation**: Built-in support for multiple languages (en, fr, it, es) via a centralised translation module.\n- **Type-Safe and Tested**: A fully type-annotated codebase with a comprehensive `pytest` test suite to ensure reliability.\n\n---\n\n## Core Design & Architecture\n\nToulouse achieves its performance through several key architectural decisions:\n\n1. **`Card` Object Pooling**: The `get_card()` factory function ensures that each unique `Card` instance is created only once. Subsequent requests for the same card return a cached reference from a global pool, significantly reducing object creation overhead and memory footprint.\n\n2. **LRU-Cached System Lookups**: The `get_card_system()` function is decorated with `@lru_cache`, ensuring that card system configuration data is retrieved from memory after the initial lookup.\n\n3. **Lazy State Vectorisation**: Each `Deck` instance maintains a private `_state_cache` (a NumPy array). This cache is only recomputed when the deck's composition changes (tracked by a `_state_dirty` flag), making repeated access to the `.state` property exceptionally fast.\n\n---\n\n## Installation\n\nInstall the library using `pip` or `uv`:\n\n```bash\n# Using pip\npip install toulouse\n\n# Using uv\nuv add toulouse\n```\n\n---\n\n## Quick Start\n\n```python\nfrom toulouse import Deck, get_card\n\n# 1. Initialise a new 40-card Italian deck.\n# The default language is Italian ('it').\ndeck = Deck.new_deck(card_system_key=\"italian_40\", language=\"fr\")\nprint(deck) # Output: Deck of 40 cards (italian_40)\n\n# 2. Draw the top card from the deck.\ndeck.shuffle()\nhand = deck.draw(1)\ndrawn_card = hand[0]\nprint(f\"Carte pioch\u00e9e: {drawn_card.to_string('fr')}\") # Output: Carte pioch\u00e9e: [Card Name]\n\n# 3. Use the factory function to get a specific card instance.\nace_of_spades = get_card(value=1, suit=2, card_system_key=\"italian_40\")\n\n# 4. Check for card presence (O(1) complexity).\nprint(f\"Le deck contient-il l'As d'\u00c9p\u00e9es? {deck.contains(ace_of_spades)}\")\n\n# 5. Get the deck's state as a NumPy vector for ML applications.\nstate_vector = deck.state\nprint(f\"Shape of state vector: {state_vector.shape}\") # Output: Shape of state vector: (40,)\n\n# 6. Display the contents of the deck, grouped by suit.\ndeck.sort()\nprint(deck.pretty_print())\n```\n\n---\n\n## API Reference\n\n### `get_card()` Factory Function\n\nThis is the recommended method for obtaining `Card` instances.\n\n`get_card(value: int, suit: int, card_system_key: str = \"italian_40\") -> Card`\n\n### `Card` Class\n\nAn immutable, hashable data class representing a single card.\n\n- `card.value: int`\n- `card.suit: int`\n- `card.to_index() -> int`: Returns the card's unique integer index within its system.\n- `card.state -> np.ndarray`: Returns a one-hot encoded NumPy vector of the card's state.\n- `card.to_string(language: str) -> str`: Returns a localised string representation.\n\n### `Deck` Class\n\nA mutable container for a collection of `Card` objects.\n\n- `Deck.new_deck(card_system_key, language, sorted_deck)`: Class method to create a new, full deck.\n- `Deck.from_cards(cards, card_system_key, language)`: Class method to create a deck from an existing list of cards.\n- `deck.draw(n: int)`: Removes and returns `n` cards from the top of the deck.\n- `deck.append(card: Card)`: Adds a card to the bottom of the deck.\n- `deck.contains(card: Card) -> bool`: Checks for the presence of a card (O(1) complexity).\n- `deck.state -> np.ndarray`: Returns a binary NumPy vector representing the current state of the deck.\n- `deck.shuffle()`: Shuffles the deck in-place.\n- `deck.sort()`: Sorts the deck in-place based on card index.\n- `deck.reset()`: Restores the deck to its full, sorted state.\n- `deck.pretty_print() -> str`: Returns a formatted string of the deck's contents, grouped by suit.\n\n### Card System Management\n\n- `register_card_system(key: str, config: dict)`: Registers a new card system configuration.\n- `get_card_system(key: str) -> dict`: Retrieves a card system's configuration dictionary.\n\n---\n\n## Performance Benchmarks\n\nThe following benchmarks were recorded on an Apple M-series CPU with Python 3.11.\n\n- **Deck Instantiation (1,000 iterations)**: ~6.2 ms\n- **Shuffle, Draw & Reset (1,000 iterations)**: ~9.9 ms\n- **Card Lookup (10,000 iterations)**: ~0.6 ms\n- **State Vectorisation (10,000 iterations)**: ~4.2 ms\n\nThese results demonstrate the library's suitability for performance-critical applications.\n\n---\n\n## Testing\n\nTo run the test suite, execute `pytest` from the project root:\n\n```bash\npytest\n```\n\n---\n\n## Licence\n\nThis project is licensed under the MIT Licence.\n",
"bugtrack_url": null,
"license": null,
"summary": "High-performance card library for ML and RL applications.",
"version": "1.1.1",
"project_urls": {
"Bug Tracker": "https://github.com/yourusername/toulouse/issues",
"Documentation": "https://github.com/yourusername/toulouse#readme",
"Homepage": "https://github.com/yourusername/toulouse",
"Repository": "https://github.com/yourusername/toulouse"
},
"split_keywords": [
"cards",
" game",
" reinforcement-learning",
" mcts",
" numpy"
],
"urls": [
{
"comment_text": null,
"digests": {
"blake2b_256": "ed61985f7ce64dbd7d37305c8e5a40ac4277fcb742f33ec61d7251d5e664a15e",
"md5": "698d8ded288c80e361307fbb38ddc1cf",
"sha256": "7c67a2434181a28fa09edc68e3f41dbe40f61532afc4a243fa9d2f91eec28c66"
},
"downloads": -1,
"filename": "toulouse-1.1.1-py3-none-any.whl",
"has_sig": false,
"md5_digest": "698d8ded288c80e361307fbb38ddc1cf",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": ">=3.9",
"size": 12215,
"upload_time": "2025-07-21T16:04:09",
"upload_time_iso_8601": "2025-07-21T16:04:09.634431Z",
"url": "https://files.pythonhosted.org/packages/ed/61/985f7ce64dbd7d37305c8e5a40ac4277fcb742f33ec61d7251d5e664a15e/toulouse-1.1.1-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": null,
"digests": {
"blake2b_256": "f2ce93c872d9122d724ec10294e77c7a2a16714ca1793f40f039d78e0bd80bb3",
"md5": "8089d2311ff09ed31d8eb49a7a3fe899",
"sha256": "7aaa55d72098386a9a860dca9c00085704f6628a0458d7a14629086fb12fb8cc"
},
"downloads": -1,
"filename": "toulouse-1.1.1.tar.gz",
"has_sig": false,
"md5_digest": "8089d2311ff09ed31d8eb49a7a3fe899",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3.9",
"size": 14807,
"upload_time": "2025-07-21T16:04:10",
"upload_time_iso_8601": "2025-07-21T16:04:10.751634Z",
"url": "https://files.pythonhosted.org/packages/f2/ce/93c872d9122d724ec10294e77c7a2a16714ca1793f40f039d78e0bd80bb3/toulouse-1.1.1.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2025-07-21 16:04:10",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "yourusername",
"github_project": "toulouse",
"github_not_found": true,
"lcname": "toulouse"
}