Initial commit - basic bingo field
This commit is contained in:
commit
5294ae2bc9
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
venv
|
148
bingo.py
Normal file
148
bingo.py
Normal file
@ -0,0 +1,148 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
from textual.app import App, ComposeResult
|
||||
from textual.widgets import Header, Footer, Button, Label, Switch, Static
|
||||
from textual.containers import ScrollableContainer
|
||||
from textual.message import Message
|
||||
from textual.color import Color
|
||||
|
||||
from asyncio import sleep
|
||||
|
||||
class BingoField(Static):
|
||||
"""A Bingo field widget."""
|
||||
|
||||
cursor_x, cursor_y = 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 manage stopwatches."""
|
||||
CSS_PATH = "bingo.tcss"
|
||||
|
||||
BINDINGS = [("d", "toggle_dark", "Toggle dark mode")]
|
||||
|
||||
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'
|
||||
]
|
||||
|
||||
# todo: prng stuff
|
||||
import random
|
||||
random.shuffle(fields)
|
||||
|
||||
def compose(self) -> ComposeResult:
|
||||
"""Create child widgets for the app."""
|
||||
yield Header()
|
||||
|
||||
for _ in range(25):
|
||||
yield BingoField(_, self.fields[_])
|
||||
|
||||
yield Footer()
|
||||
|
||||
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
|
||||
|
||||
def action_toggle_dark(self) -> None:
|
||||
"""An action to toggle dark mode."""
|
||||
self.dark = not self.dark
|
||||
|
||||
if __name__ == "__main__":
|
||||
app = BingoApp()
|
||||
app.run()
|
11
bingo.tcss
Normal file
11
bingo.tcss
Normal file
@ -0,0 +1,11 @@
|
||||
Screen {
|
||||
layout: grid;
|
||||
grid-size: 5 5;
|
||||
}
|
||||
|
||||
.box {
|
||||
height: 100%;
|
||||
border: solid green;
|
||||
text-align: center;
|
||||
content-align: center middle;
|
||||
}
|
1
requirements.txt
Normal file
1
requirements.txt
Normal file
@ -0,0 +1 @@
|
||||
textual
|
Loading…
Reference in New Issue
Block a user