Combinations
Pactole exposes dedicated classes to represent and manipulate lottery combinations:
EuroMillionsCombinationEuroDreamsCombination
Use them when you want to:
- Create a played ticket from user input.
- Normalize and validate values before storage.
- Compare multiple tickets.
- Evaluate a played ticket against a draw result.
Create combinations from player input
Create combinations from explicit components when your UI already separates fields.
from pactole import EuroDreamsCombination, EuroMillionsCombination
euromillions = EuroMillionsCombination(numbers=[3, 15, 22, 28, 44], stars=[2, 9])
eurodreams = EuroDreamsCombination(numbers=[2, 3, 5, 7, 9, 38], dream=[3])
print(euromillions)
print(eurodreams)
If your source is a flat list (CSV row, form payload, pasted string), pass a single sequence. Pactole automatically splits values by component size.
from pactole import EuroDreamsCombination, EuroMillionsCombination
euromillions = EuroMillionsCombination([3, 15, 22, 28, 44, 2, 9])
eurodreams = EuroDreamsCombination([2, 3, 5, 7, 9, 38, 3])
print(euromillions.numbers.values, euromillions.stars.values)
print(eurodreams.numbers.values, eurodreams.dream.values)
You can also rebuild combinations from per-component lexicographic ranks. This is useful for reproducible indexing, partitioning, or deterministic test fixtures.
from pactole import EuroDreamsCombination, EuroMillionsCombination
first_euromillions = EuroMillionsCombination(numbers=1352788, stars=43)
first_eurodreams = EuroDreamsCombination(numbers=1765425, dream=3)
print(first_euromillions)
print(first_eurodreams)
Read normalized values and metadata
Each combination exposes normalized values and metadata you can persist or display.
from pactole import EuroMillionsCombination
ticket = EuroMillionsCombination(numbers=[44, 3, 28, 22, 15], stars=[9, 2])
print(ticket.numbers.values) # [3, 15, 22, 28, 44]
print(ticket.stars.values) # [2, 9]
print(ticket.values) # [3, 15, 22, 28, 44, 2, 9]
print(ticket.rank) # Global rank across all components
print(ticket.combinations) # 139_838_160 for EuroMillions
print(ticket.count) # 7 (total number of slots: 5 numbers + 2 stars)
print(ticket.min_winning_rank) # 1
print(ticket.max_winning_rank) # 13
Access combination components
Access individual components using dictionary-like methods.
from pactole import EuroMillionsCombination
ticket = EuroMillionsCombination(numbers=[3, 15, 22, 28, 44], stars=[2, 9])
# Get a specific component by name
print(ticket.get('numbers')) # Combination([3, 15, 22, 28, 44])
print(ticket.get('stars')) # Combination([2, 9])
print(ticket.get('invalid')) # None
# Get values for a specific component
print(ticket.get_values('numbers')) # [3, 15, 22, 28, 44]
print(ticket.get_values('stars')) # [2, 9]
print(ticket.get_values('invalid')) # []
Serialize combinations
Convert combinations to various formats for storage, transmission, or display.
String representation
Use string conversion for human-readable display or configuration files.
from pactole import EuroMillionsCombination
ticket = EuroMillionsCombination(numbers=[3, 15, 22, 28, 44], stars=[2, 9])
# Convert to string
ticket_str = ticket.to_string()
print(ticket_str) # 'numbers: [3, 15, 22, 28, 44] stars: [2, 9]'
# Recreate from string
restored = EuroMillionsCombination.from_string(ticket_str)
print(restored.values) # [3, 15, 22, 28, 44, 2, 9]
CSV format
Use CSV conversion for exporting to spreadsheets or data files.
from pactole import EuroMillionsCombination
ticket = EuroMillionsCombination(numbers=[3, 15, 22, 28, 44], stars=[2, 9])
# Convert to CSV-friendly format
csv_data = ticket.to_csv()
print(csv_data)
# {'numbers_1': 3, 'numbers_2': 15, 'numbers_3': 22, 'numbers_4': 28, 'numbers_5': 44,
# 'stars_1': 2, 'stars_2': 9}
# Recreate from CSV
restored = EuroMillionsCombination.from_csv(csv_data)
print(restored.values) # [3, 15, 22, 28, 44, 2, 9]
JSON format
Use JSON conversion for APIs and web applications.
from pactole import EuroMillionsCombination
ticket = EuroMillionsCombination(numbers=[3, 15, 22, 28, 44], stars=[2, 9])
# Convert to JSON-friendly dictionary
json_data = ticket.to_json()
print(json_data)
# {
# 'numbers': [3, 15, 22, 28, 44],
# 'stars': [2, 9]
# }
# Recreate from JSON
restored = EuroMillionsCombination.from_json(json_data)
print(restored.values) # [3, 15, 22, 28, 44, 2, 9]
Dictionary format
Use dictionary conversion for flexible storage and manipulation.
from pactole import EuroMillionsCombination
ticket = EuroMillionsCombination(numbers=[3, 15, 22, 28, 44], stars=[2, 9])
# Convert to dictionary
dict_data = ticket.to_dict()
print(dict_data)
# {
# 'numbers': [3, 15, 22, 28, 44],
# 'stars': [2, 9]
# }
# Recreate from dictionary
restored = EuroMillionsCombination.from_dict(dict_data)
print(restored.values) # [3, 15, 22, 28, 44, 2, 9]
Serialization shape by class
For game-specific classes (EuroMillionsCombination, EuroDreamsCombination),
to_dict() and to_json() are intentionally flat and return only component values.
from pactole import EuroDreamsCombination
ticket = EuroDreamsCombination(numbers=[2, 3, 5, 7, 9, 38], dream=[3])
print(ticket.to_dict())
# {'numbers': [2, 3, 5, 7, 9, 38], 'dream': [3]}
For generic classes (CompoundCombination, LotteryCombination), to_dict() and
to_json() return a nested structure with components and winning_ranks.
Generate random combinations
Use a template combination to generate random tickets that follow game rules.
from pactole import EuroDreamsCombination
generator = EuroDreamsCombination()
tickets = generator.generate(n=3)
for index, ticket in enumerate(tickets, start=1):
print(f"Ticket #{index}: {ticket}")
Use partitioning to spread generation across the rank space
generate(n, partitions) does more than repeated random picks:
- The global rank space is split into
partitionscontiguous slices. - Ticket
iis sampled from slicei % partitions. - This gives broader coverage than sampling all tickets from one undivided range.
Practical effects:
- Better spread in large batches (less clustering in one area of rank space).
- Deterministic slice selection order (round-robin by partition index).
- Randomness is still used inside each selected slice.
from pactole import EuroMillionsCombination
generator = EuroMillionsCombination()
# 12 tickets sampled across 4 slices of the full rank space.
tickets = generator.generate(n=12, partitions=4)
for ticket in tickets:
print(ticket.rank, ticket)
Typical partitioning patterns
Use partitioning according to your generation strategy.
from pactole import EuroMillionsCombination
generator = EuroMillionsCombination()
# 1) Quick balanced batch for one user session.
balanced_batch = generator.generate(n=8, partitions=4)
# 2) Parallel job pattern: one partition per worker group.
worker_batch = generator.generate(n=40, partitions=8)
# 3) Keep default behavior for small needs.
simple_batch = generator.generate(n=3)
Notes:
nandpartitionsare clamped to at least1.- Partitioning does not guarantee uniqueness; duplicates can still occur.
- If
partitionsis very large compared ton, many slices are never sampled.
Compare tickets in a realistic workflow
Use comparison helpers to evaluate a candidate ticket against a reference ticket.
from pactole import EuroMillionsCombination
reference = EuroMillionsCombination(numbers=[3, 15, 22, 28, 44], stars=[2, 9])
candidate = EuroMillionsCombination(numbers=[3, 15, 22, 30, 45], stars=[2, 10])
print(reference.equals(candidate)) # Exact same ticket?
print(reference.includes(numbers=[3, 15, 22])) # Candidate subset check
print(reference.intersects(candidate)) # Any overlap per component?
common = reference.intersection(candidate)
print(common.numbers.values) # [3, 15, 22]
print(common.stars.values) # [2]
Compute winning ranks
A common use case is scoring a played ticket against an official draw.
get_winning_rank returns:
- an integer rank if the ticket is winning,
Noneif it is not in any winning pattern.
from pactole import EuroMillionsCombination
draw = EuroMillionsCombination(numbers=[3, 15, 22, 28, 44], stars=[2, 9])
ticket = EuroMillionsCombination(numbers=[3, 15, 22, 30, 45], stars=[2, 10])
rank = draw.get_winning_rank(ticket)
if rank is None:
print("No winning rank")
else:
print(f"Winning rank: {rank}")