9 Commits

Author SHA1 Message Date
97e5c9df5a add powerball lottery
minor bump
2026-07-22 16:07:14 +01:00
1efd518e9f add pre-commit config 2026-03-21 14:21:34 +00:00
a8a46f718d upd README. 2026-03-20 09:56:45 +00:00
5eaa521b8d fix Set For Life pool size.
patch bump
2026-02-26 16:45:12 +00:00
19b4f32c5a patch bump 2026-02-26 14:02:18 +00:00
1bd6c0e94f enable type_to_earch in Select widget 2026-02-26 14:02:01 +00:00
cfba2303e6 remove default empty option
select now defaults to Lotto

patch bump
2026-02-26 01:02:35 +00:00
a2ab27fa5b bump to version 1.0.0. TUI is considered complete. 2026-02-25 21:39:47 +00:00
5d6836a603 add _read_lottery_selection() helper method
patch bump
2026-02-23 19:58:47 +00:00
5 changed files with 53 additions and 17 deletions

12
.pre-commit-config.yaml Normal file
View File

@@ -0,0 +1,12 @@
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v2.3.0
hooks:
- id: check-yaml
- id: end-of-file-fixer
- id: trailing-whitespace
- repo: https://github.com/pdm-project/pdm
rev: 2.26.6
hooks:
- id: pdm-lock-check

View File

@@ -34,7 +34,7 @@ The TUI should now be discoverable as lottery-tui.
Launch the TUI, select a lottery and press the Draw button!
To exit from the application press *q* or *Ctrl+q*
To exit from the application press `Ctrl+q`.
## License

View File

@@ -1,6 +1,6 @@
[project]
name = "lottery-tui"
version = "0.2.7"
version = "1.1.0"
description = "A terminal user interface for lottery games."
authors = [{ name = "onyx-and-iris", email = "code@onyxandiris.online" }]
dependencies = ["textual>=8.0.0", "loguru>=0.7.3"]
@@ -8,7 +8,7 @@ requires-python = ">=3.10"
readme = "README.md"
license = { text = "MIT" }
classifiers = [
"Development Status :: 4 - Beta",
"Development Status :: 5 - Production/Stable",
"Programming Language :: Python",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",

View File

@@ -33,6 +33,8 @@ class Result:
bonus_name = 'Life Ball'
case 'Thunderball':
bonus_name = 'Thunderball'
case 'Powerball':
bonus_name = 'Powerball'
case _:
bonus_name = 'Bonus Numbers'
out += f'\n{bonus_name}: {", ".join(str(n) for n in self.bonus)}'
@@ -94,11 +96,11 @@ class EuroMillions(Lottery):
class SetForLife(Lottery):
"""A class representing the Set For Life lottery.
Set For Life draws 5 numbers from a pool of 1 to 39, without replacement,
Set For Life draws 5 numbers from a pool of 1 to 47, without replacement,
and 1 "Life Ball" number from a separate pool of 1 to 10.
"""
POSSIBLE_NUMBERS = range(1, 40)
POSSIBLE_NUMBERS = range(1, 48)
def draw(self) -> Result:
"""Perform a Set For Life draw."""
@@ -124,6 +126,23 @@ class Thunderball(Lottery):
return Result(kind=type(self).__name__, numbers=numbers, bonus=thunderball)
@register_lottery
class Powerball(Lottery):
"""A class representing the Powerball lottery.
Powerball draws 5 numbers from a pool of 1 to 69, without replacement,
and 1 "Powerball" number from a separate pool of 1 to 26.
"""
POSSIBLE_NUMBERS = range(1, 70)
def draw(self) -> Result:
"""Perform a Powerball draw."""
numbers = random.sample(Powerball.POSSIBLE_NUMBERS, 5)
powerball = [random.randint(1, 26)]
return Result(kind=type(self).__name__, numbers=numbers, bonus=powerball)
def request_lottery_obj(lottery_name: str) -> Lottery:
"""Return a lottery object based on the provided lottery name."""
lottery_cls = registry.get(lottery_name.lower())

View File

@@ -1,6 +1,9 @@
from rich.text import Text
from typing import NoReturn
from textual.app import App, ComposeResult
from textual.containers import Container
from textual.events import Key
from textual.types import SelectType
from textual.widgets import Button, Label, Select, Static
from .lottery import request_lottery_obj
@@ -22,7 +25,11 @@ class LotteryTUI(App):
('EuroMillions', 'euromillions'),
('Set For Life', 'setforlife'),
('Thunderball', 'thunderball'),
('Powerball', 'powerball'),
],
value='lotto',
allow_blank=False,
type_to_search=True,
id='lottery-select',
),
Button('Draw', id='draw-button'),
@@ -30,29 +37,27 @@ class LotteryTUI(App):
id='main-container',
)
def on_key(self, event):
def on_key(self, event: Key) -> NoReturn:
"""Handle key events."""
if event.key == 'q':
self.exit()
def on_button_pressed(self, event):
def on_button_pressed(self, event: Button.Pressed) -> None:
"""Handle button press events."""
if event.button.id == 'draw-button':
self._draw_button_handler()
def _draw_button_handler(self):
def _draw_button_handler(self) -> None:
"""Handle the draw button press."""
if self.query_one('#lottery-select').is_blank():
self._update_result_label(
Text('Please select a lottery before drawing.', style='bold #ff8c42')
)
return
lottery_obj = request_lottery_obj(self.query_one('#lottery-select').value)
lottery_obj = request_lottery_obj(self._read_lottery_selection())
result = lottery_obj.draw()
self._update_result_label(str(result))
def _update_result_label(self, message: str):
def _read_lottery_selection(self) -> SelectType:
"""Read the selected lottery from the dropdown."""
return self.query_one('#lottery-select').value
def _update_result_label(self, message: str) -> None:
"""Update the result label with a new message."""
self.query_one('#result-label').update(message)