from textual.reactive import reactive from textual.widget import Widget from textual.app import ComposeResult from textual.message import Message from textual import events from datetime import datetime import random from asyncio import sleep from BingoField import BingoField class BingoBoard(Widget): fields = reactive([], recompose = True) cursor_x, cursor_y = 2, 2 def __init__(self) -> None: self.fieldstate = [False for _ in range(25)] self.can_focus = True super().__init__() self.fields = [ 'Deko aufgehängt', '6 Stunden Schlaf', 'Tschunk getrunken', 'Spaß gehabt', 'Sticker getauscht', 'DECT genutzt', 'Hardware gehackt', 'Kabel vergessen', 'Halle gesucht', '$dinge gelötet', 'Code geschrieben', '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' ] self.default_fields = self.fields self.roll_board(int(datetime.now().timestamp())) def fieldnum_from_cursor(self) -> int: return self.cursor_x + ( self.cursor_y * 5) def roll_board(self, seed): self.seed = seed random.seed(seed) self.fields = random.sample(self.default_fields, len(self.fields)) def watch_fields(self, new_state) -> None: self.fieldstate = [False for _ in range(25)] for idx, field in enumerate(self.query(BingoField)): field.text = new_state[idx] def compose(self) -> ComposeResult: """Create child widgets for the app.""" for _ in range(25): yield BingoField(_, self.fields[_]) def on_focus(self, message: Message) -> None: fields = self.query(BingoField) fields[self.fieldnum_from_cursor()].set_highlighted(True) def on_blur(self, message: Message) -> None: fields = self.query(BingoField) fields[self.fieldnum_from_cursor()].set_highlighted(False) def on_key(self, event: events.Key) -> None: fields = self.query(BingoField) fields[self.fieldnum_from_cursor()].set_highlighted(False) match event.key: case 'up': self.cursor_y -= 1 if self.cursor_y > 0 else 0 case 'down': self.cursor_y += 1 if self.cursor_y < 4 else 0 case 'left': self.cursor_x -= 1 if self.cursor_x > 0 else 0 case 'right': self.cursor_x += 1 if self.cursor_x < 4 else 0 fields[self.fieldnum_from_cursor()].set_highlighted(True) 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