#!/usr/bin/env python3 from textual.app import App, ComposeResult from textual.widgets import Header, Footer, Input, Label, Static, Button from textual.message import Message from textual.color import Color from textual.containers import Horizontal from asyncio import sleep from datetime import datetime import random class BingoField(Static): """A Bingo field widget.""" cursor_x, cursor_y = 2, 2 class Selected(Message): """Send message to the board containing clicked field info""" def __init__(self, num: int, selected: bool) -> None: self.num = num self.selected = selected super().__init__() def __init__(self, num, text: str) -> None: self.text = text self.num = num self.selected = False super().__init__() def on_mount(self) -> None: self.styles.content_align = ("center", "middle") self.styles.border = ("solid", "green") self.styles.height = '100%' self.styles.width = '100%' def on_click(self) -> None: self.selected = not self.selected if self.selected: self.styles.animate("background", 'green', duration=0.1) self.styles.border = ("solid", "black") else: self.styles.animate("background", '#1c1c1c', duration=0.1) self.styles.border = ("solid", "green") # The post_message method sends an event to be handled in the DOM self.post_message(self.Selected(self.num, self.selected)) def render(self) -> str: return str(self.text) class BingoApp(App): """A Textual app to run a Bingo board.""" CSS_PATH = "bingo.tcss" BINDINGS = [("d", "toggle_dark", "Toggle dark mode")] def compose(self) -> ComposeResult: """Create child widgets for the app.""" yield Header() yield BingoDisplay() yield Footer() def action_toggle_dark(self) -> None: """An action to toggle dark mode.""" self.dark = not self.dark class BingoDisplay(Static): def compose(self) -> ComposeResult: """Create child widgets for the app.""" yield BingoBoard() input_field = Input( type='integer', placeholder='UNIX timestamp', max_length=10, classes='seed_input' ) input_field.border_title = 'Seed' yield Horizontal( input_field, Button('re-roll', classes='roll_btn'), classes='bottom_line' ) class BingoBoard(Static): fieldstate = [False for _ in range(25)] fields = [ 'Datenelch', '6 Stunden Schlaf', 'Tschunk getrunken', 'Spaß gehabt', 'Sticker getauscht', 'DECT genutzt', 'Hardware gehackt', 'Kabel vergessen', 'Halle gesucht', '$dinge gelötet', 'an SoS teilgenommen', 'Neue Leute kennengelernt', 'Wasser getrunken', 'Waffel gegessen', 'Corona Test gemacht', '2 Mahlzeiten gegessen', 'Fairydust bewundert', 'Talk angeschaut', 'CCC Merch getragen', 'getrollt', 'In der Lounge getanzt', 'Etwas Neues ausprobiert', 'Maske getragen', 'geduscht', 'Gulasch gegessen' ] # get rng seed from current time seed = int(datetime.now().timestamp()) random.seed(seed) random.shuffle(fields) def compose(self) -> ComposeResult: """Create child widgets for the app.""" for _ in range(25): yield BingoField(_, self.fields[_]) async def on_bingo_field_selected(self, message: BingoField.Selected) -> None: self.fieldstate[message.num] = message.selected if self.is_bingo(): self.screen.styles.animate("background", 'red', duration=0.25) await sleep(0.25) self.screen.styles.animate("background", 'orange', duration=0.25) await sleep(0.25) self.screen.styles.animate("background", 'yellow', duration=0.25) await sleep(0.25) self.screen.styles.animate("background", 'green', duration=0.25) await sleep(0.25) self.screen.styles.animate("background", 'lightblue', duration=0.25) await sleep(0.25) self.screen.styles.animate("background", 'blue', duration=0.25) await sleep(0.25) self.screen.styles.animate("background", 'purple', duration=0.25) await sleep(0.25) self.screen.styles.animate("background", '#1c1c1c', duration=0.25) def is_bingo(self): array = [ self.fieldstate[i:i+5] for i in range(0, len(self.fieldstate), 5)] # check rows bingo = any( [ all(row) for row in array ] ) # check cols bingo = bingo or any([ all(self.fieldstate[num::5]) for num in range(5)]) # check bottom left to upper right bingo = bingo or all([ self.fieldstate[4], self.fieldstate[8], self.fieldstate[12], self.fieldstate[16], self.fieldstate[20] ]) # check top left to bottom right bingo = bingo or all([ self.fieldstate[0], self.fieldstate[6], self.fieldstate[12], self.fieldstate[18], self.fieldstate[24] ]) return bingo if __name__ == "__main__": app = BingoApp() app.run()