___ ___ ____ _ ___ _ _
| | / ___| | _ \ | | / | | | | |
| /| | \ `--. | |_) | | | / /| | | |__| |
| ___| `--. \ | _ < | | / / | | | __ |
| | /\__/ | |_) | | |___ / ___ | | | | |
|_| \____/ |____/ |_____| \/ |_| |_| |_|
from dataclasses import dataclass
from typing import Dict, List, Optional
import asyncio
from functools import reduce
from enum import Enum
import logging
from datetime import datetime
# Configure logging
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
class CharacterType(Enum):
STANDARD = "standard"
SPECIAL = "special"
@dataclass(frozen=True)
class ASCIIConfig:
rows: int = 6
spacing: str = " " # Double space between characters
default_width: int = 8 # Increased default width
@dataclass
class ASCIICharacter:
char: str
matrix: List[str]
type: CharacterType = CharacterType.STANDARD
def __post_init__(self):
if len(self.matrix) != ASCIIConfig.rows:
raise ValueError(f"Character {self.char} must have exactly {ASCIIConfig.rows} rows")
class ASCIIArtMatrix:
def __init__(self):
self._character_map: Dict[str, ASCIICharacter] = {
'P': ASCIICharacter('P', [
' ___ ', '| |', '| /| |', '| ___|', '| | ', '|_| '
]),
'S': ASCIICharacter('S', [
' ___ ', '/ ___|', '\\ `--. ', ' `--. \\', '/\\__/ ', '\\____/ '
], CharacterType.SPECIAL),
'B': ASCIICharacter('B', [
' ____ ', '| _ \\ ', '| |_) |', '| _ < ', '| |_) |', '|____/ '
], CharacterType.SPECIAL),
'L': ASCIICharacter('L', [
' _ ', '| | ', '| | ', '| | ', '| |___ ', '|_____|'
]),
'A': ASCIICharacter('A', [
' ___ ', '/ | ', '/ /| | ', '/ / | | ', '/ ___ | ', '\\/ |_| '
], CharacterType.SPECIAL),
'H': ASCIICharacter('H', [
' _ _ ', '| | | |', '| |__| |', '| __ |', '| | | |', '|_| |_|'
])
}
async def get_character(self, char: str) -> Optional[ASCIICharacter]:
return self._character_map.get(char)
class ASCIIArtRenderer:
def __init__(self, matrix: ASCIIArtMatrix, config: ASCIIConfig):
self.matrix = matrix
self.config = config
self._render_count = 0
self._last_render_time = None
async def render_line(self, row_idx: int, message: str) -> str:
chars = await asyncio.gather(
*[self.matrix.get_character(char) for char in message]
)
return reduce(
lambda acc, char: acc + (char.matrix[row_idx] if char else " " * self.config.default_width) + self.config.spacing,
chars,
""
)
async def render_message(self, message: str) -> None:
self._render_count += 1
self._last_render_time = datetime.now()
try:
for row_idx in range(self.config.rows):
line = await self.render_line(row_idx, message)
print(line)
except Exception as e:
logger.error(f"Error rendering message: {str(e)}")
raise
async def main():
config = ASCIIConfig()
matrix = ASCIIArtMatrix()
renderer = ASCIIArtRenderer(matrix, config)
message = "PSBLAH"
await renderer.render_message(message)
if __name__ == '__main__':
asyncio.run(main())