mirror of
https://github.com/kuhyx/signal-bot.git
synced 2026-11-10 18:17:02 +01:00
Seven numbers the group finds funny get a marker wherever they show up as
a count: the nightly table, every !stats_* view, !ja, the records and the
highlights. Percentages and shares stay bare (a 69% share is not a 69), and
so does the (N 📷) aside, so one line never carries two jokes. One table,
FUNNY in stats/text.py, and one helper, marked(), so adding a number is one
line. Documented in DOCS-statistics.md.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
89 lines
2.9 KiB
Python
89 lines
2.9 KiB
Python
# Copyright (c) 2026 Krzysztof Rudnicki. MIT licence.
|
|
"""Polish number agreement, and the small text pieces the renderers share.
|
|
|
|
Polish nouns take three forms after a numeral, not two. "1 znak", "2 znaki",
|
|
"5 znaków" -- and the rule is on the last *two* digits, so 12, 13 and 14 take
|
|
the many-form while 22, 23 and 24 do not. Getting this wrong is the kind of
|
|
thing the group notices immediately and mentions every time.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
from typing import Final
|
|
|
|
# Numbers the group reacts to whenever one comes up, and what it says. They
|
|
# go on counts -- messages, records, days, people -- and never on a share:
|
|
# a 69% share of voice is a rounding artefact, not something anybody did.
|
|
# The parenthesised photo aside in the day block stays bare too, because
|
|
# "(69 (nice) 📷)" nests brackets and reads as a typo.
|
|
FUNNY: Final[dict[int, str]] = {
|
|
67: "\U0001f937",
|
|
69: "(nice)",
|
|
314: "\U0001f967",
|
|
420: "\U0001f33f",
|
|
1410: "\u2694\ufe0f",
|
|
1916: "\U0001f1f5\U0001f1f1",
|
|
2137: "\U0001f64f",
|
|
}
|
|
|
|
TEEN_START: Final = 12
|
|
TEEN_END: Final = 14
|
|
FEW_START: Final = 2
|
|
FEW_END: Final = 4
|
|
|
|
|
|
def plural(count: int, one: str, few: str, many: str) -> str:
|
|
"""Pick the Polish form that agrees with a count.
|
|
|
|
Args:
|
|
count: The number the noun follows.
|
|
one: The form for exactly 1 ("znak").
|
|
few: The form for 2-4 and most numbers ending 2-4 ("znaki").
|
|
many: Every other case, including the 12-14 teens ("znaków").
|
|
|
|
Returns:
|
|
The bare noun, without the number.
|
|
"""
|
|
if count == 1:
|
|
return one
|
|
if TEEN_START <= count % 100 <= TEEN_END:
|
|
return many
|
|
if FEW_START <= count % 10 <= FEW_END:
|
|
return few
|
|
return many
|
|
|
|
|
|
def marked(count: int) -> str:
|
|
"""The count as printed: bare, or with its marker when the group has one.
|
|
|
|
The marker sticks to the number ("69 (nice) wiadomości"), so the same
|
|
count reads the same whether a noun follows it or not.
|
|
"""
|
|
marker = FUNNY.get(count)
|
|
return f"{count} {marker}" if marker else str(count)
|
|
|
|
|
|
def messages(count: int) -> str:
|
|
"""The count and its noun, agreeing: e.g. 3 wiadomości."""
|
|
return f"{marked(count)} {plural(count, 'wiadomość', 'wiadomości', 'wiadomości')}"
|
|
|
|
|
|
def characters(count: int) -> str:
|
|
"""The count and its noun, agreeing: e.g. 44 znaki."""
|
|
return f"{count} {plural(count, 'znak', 'znaki', 'znaków')}"
|
|
|
|
|
|
def commands(count: int) -> str:
|
|
"""The count and its noun, agreeing: e.g. 4 komendy."""
|
|
return f"{marked(count)} {plural(count, 'komenda', 'komendy', 'komend')}"
|
|
|
|
|
|
def people(count: int) -> str:
|
|
"""The count and its noun, agreeing: e.g. 2 osoby."""
|
|
return f"{marked(count)} {plural(count, 'osoba', 'osoby', 'osób')}"
|
|
|
|
|
|
def days(count: int) -> str:
|
|
"""The count and its noun, agreeing: e.g. 3 dni."""
|
|
return f"{marked(count)} {plural(count, 'dzień', 'dni', 'dni')}"
|